aboutsummaryrefslogtreecommitdiff
path: root/config
diff options
context:
space:
mode:
Diffstat (limited to 'config')
-rw-r--r--config/config.go84
-rw-r--r--config/config_test.go12
2 files changed, 91 insertions, 5 deletions
diff --git a/config/config.go b/config/config.go
index 2ec6706..cd2883b 100644
--- a/config/config.go
+++ b/config/config.go
@@ -1,9 +1,11 @@
package config
import (
+ "fmt"
"github.com/pkg/errors"
"io/ioutil"
+ "github.com/santhosh-tekuri/jsonschema"
"gopkg.in/yaml.v2"
)
@@ -47,7 +49,7 @@ type TelegramTdlibClientConfig struct {
UseChatInfoDatabase bool `yaml:":use_chat_info_database"`
}
-func ReadConfig(path string) (Config, error) {
+func ReadConfig(path string, schema_path string) (Config, error) {
var config Config
file, err := ioutil.ReadFile(path)
@@ -60,5 +62,85 @@ func ReadConfig(path string) (Config, error) {
return config, errors.Wrap(err, "Error parsing config")
}
+ err = validateConfig(file, schema_path)
+ if err != nil {
+ return config, errors.Wrap(err, "Validation error")
+ }
+
return config, nil
}
+
+func validateConfig(file []byte, schema_path string) error {
+ schema, err := jsonschema.Compile(schema_path)
+ if err != nil {
+ return errors.Wrap(err, "Corrupted JSON schema")
+ }
+
+ var config_generic interface{}
+
+ err = yaml.Unmarshal(file, &config_generic)
+ if err != nil {
+ return errors.Wrap(err, "Error re-parsing config")
+ }
+
+ config_generic, err = convertToStringKeysRecursive(config_generic, "")
+ if err != nil {
+ return errors.Wrap(err, "Config conversion error")
+ }
+
+ err = schema.ValidateInterface(config_generic)
+ if err != nil {
+ return errors.Wrap(err, "Config validation error")
+ }
+
+ return nil
+}
+
+// copied and adapted from https://github.com/docker/docker-ce/blob/de14285fad39e215ea9763b8b404a37686811b3f/components/cli/cli/compose/loader/loader.go#L330
+func convertToStringKeysRecursive(value interface{}, keyPrefix string) (interface{}, error) {
+ if mapping, ok := value.(map[interface{}]interface{}); ok {
+ dict := make(map[string]interface{})
+ for key, entry := range mapping {
+ str, ok := key.(string)
+ if !ok {
+ return nil, formatInvalidKeyError(keyPrefix, key)
+ }
+ var newKeyPrefix string
+ if keyPrefix == "" {
+ newKeyPrefix = str
+ } else {
+ newKeyPrefix = fmt.Sprintf("%s.%s", keyPrefix, str)
+ }
+ convertedEntry, err := convertToStringKeysRecursive(entry, newKeyPrefix)
+ if err != nil {
+ return nil, err
+ }
+ dict[str] = convertedEntry
+ }
+ return dict, nil
+ }
+ if list, ok := value.([]interface{}); ok {
+ var convertedList []interface{}
+ for index, entry := range list {
+ newKeyPrefix := fmt.Sprintf("%s[%d]", keyPrefix, index)
+ convertedEntry, err := convertToStringKeysRecursive(entry, newKeyPrefix)
+ if err != nil {
+ return nil, err
+ }
+ convertedList = append(convertedList, convertedEntry)
+ }
+ return convertedList, nil
+ }
+
+ return value, nil
+}
+
+func formatInvalidKeyError(keyPrefix string, key interface{}) error {
+ var location string
+ if keyPrefix == "" {
+ location = "at top level"
+ } else {
+ location = fmt.Sprintf("in %s", keyPrefix)
+ }
+ return errors.Errorf("Non-string key %s: %#v", location, key)
+}
diff --git a/config/config_test.go b/config/config_test.go
index 34009d7..6fce23b 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -4,23 +4,27 @@ import (
"testing"
)
+const SCHEMA_PATH string = "../config_schema.json"
+
func TestNoConfig(t *testing.T) {
- _, err := ReadConfig("../test/sfklase.yml")
+ _, err := ReadConfig("../test/sfklase.yml", SCHEMA_PATH)
if err == nil {
t.Errorf("Non-existent config was successfully read")
}
}
func TestGoodConfig(t *testing.T) {
- _, err := ReadConfig("../test/good_config.yml")
+ _, err := ReadConfig("../test/good_config.yml", SCHEMA_PATH)
if err != nil {
t.Errorf("Good config is not accepted: %v", err)
}
}
func TestBadConfig(t *testing.T) {
- _, err := ReadConfig("../test/bad_config.yml")
+ _, err := ReadConfig("../test/bad_config.yml", SCHEMA_PATH)
if err == nil {
- t.Errorf("Bad config is accepted but it shoudn't!")
+ t.Errorf("Bad config is accepted but it shouldn't!")
+ } else {
+ t.Log(err)
}
}