From 4081c61fffc49b2415c40887041955d24b754f85 Mon Sep 17 00:00:00 2001 From: monalisa Date: Mon, 14 Aug 2023 22:45:28 +0200 Subject: [PATCH 1/4] Add better error messages for invalid JSON schema types --- libs/template/utils.go | 14 ++++++++++++-- libs/template/utils_test.go | 12 ++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/libs/template/utils.go b/libs/template/utils.go index bf11ed86f1d..e29e0484119 100644 --- a/libs/template/utils.go +++ b/libs/template/utils.go @@ -66,8 +66,13 @@ func toString(v any, T jsonschema.Type) (string, error) { return "", err } return strconv.FormatInt(intVal, 10), nil - default: + case jsonschema.ArrayType, jsonschema.ObjectType: return "", fmt.Errorf("cannot format object of type %s as a string. Value of object: %#v", T, v) + default: + if T == "int" { + return "", fmt.Errorf(`unknown json schema type %q. Please use "integer" instead`, T) + } + return "", fmt.Errorf("unknown json schema type: %q", T) } } @@ -87,8 +92,13 @@ func fromString(s string, T jsonschema.Type) (any, error) { v, err = strconv.ParseFloat(s, 32) case jsonschema.IntegerType: v, err = strconv.ParseInt(s, 10, 64) - default: + case jsonschema.ArrayType, jsonschema.ObjectType: return "", fmt.Errorf("cannot parse string as object of type %s. Value of string: %q", T, s) + default: + if T == "int" { + return "", fmt.Errorf(`unknown json schema type %q. Please use "integer" instead`, T) + } + return "", fmt.Errorf("unknown json schema type: %q", T) } // Return more readable error incase of a syntax error diff --git a/libs/template/utils_test.go b/libs/template/utils_test.go index 5fe702439e9..5e86bd1e2b1 100644 --- a/libs/template/utils_test.go +++ b/libs/template/utils_test.go @@ -80,6 +80,12 @@ func TestTemplateToString(t *testing.T) { _, err = toString("abc", jsonschema.IntegerType) assert.EqualError(t, err, "cannot convert \"abc\" to an integer") + + _, err = toString("abc", "foobar") + assert.EqualError(t, err, "unknown json schema type: \"foobar\"") + + _, err = toString("abc", "int") + assert.EqualError(t, err, "unknown json schema type \"int\". Please use \"integer\" instead") } func TestTemplateFromString(t *testing.T) { @@ -112,4 +118,10 @@ func TestTemplateFromString(t *testing.T) { _, err = fromString("1.0", jsonschema.IntegerType) assert.EqualError(t, err, "could not parse \"1.0\" as a integer: strconv.ParseInt: parsing \"1.0\": invalid syntax") + + _, err = fromString("1.0", "foobar") + assert.EqualError(t, err, "unknown json schema type: \"foobar\"") + + _, err = fromString("1.0", "int") + assert.EqualError(t, err, "unknown json schema type \"int\". Please use \"integer\" instead") } From 8467a2c1249813868b6113e5fe9871d145ba0b43 Mon Sep 17 00:00:00 2001 From: monalisa Date: Mon, 14 Aug 2023 23:08:27 +0200 Subject: [PATCH 2/4] add validation for schema --- libs/template/config.go | 19 ++++++++++++++++++ libs/template/config_test.go | 37 ++++++++++++++++++++++++++++++++++++ libs/template/utils.go | 6 ------ libs/template/utils_test.go | 6 ------ 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/libs/template/config.go b/libs/template/config.go index ee5fcbef803..4c565b13213 100644 --- a/libs/template/config.go +++ b/libs/template/config.go @@ -27,6 +27,9 @@ func newConfig(ctx context.Context, schemaPath string) (*config, error) { if err != nil { return nil, err } + if err := validateSchema(schema); err != nil { + return nil, err + } // Return config return &config{ @@ -36,6 +39,22 @@ func newConfig(ctx context.Context, schemaPath string) (*config, error) { }, nil } +func validateSchema(schema *jsonschema.Schema) error { + for _, v := range schema.Properties { + switch v.Type { + case jsonschema.NumberType, jsonschema.BooleanType, jsonschema.StringType, jsonschema.IntegerType: + continue + case jsonschema.ArrayType, jsonschema.ObjectType: + return fmt.Errorf("property type %s is not supported by bundle templates", v.Type) + case "int", "int32", "int64": + return fmt.Errorf("type %s is not a recognized json schema type. Please use \"integer\" instead", v.Type) + default: + return fmt.Errorf("type %s is not a recognized json schema type", v.Type) + } + } + return nil +} + // Reads json file at path and assigns values from the file func (c *config) assignValuesFromFile(path string) error { // Read the config file diff --git a/libs/template/config_test.go b/libs/template/config_test.go index 7b8341ec48f..8f967ce6898 100644 --- a/libs/template/config_test.go +++ b/libs/template/config_test.go @@ -161,3 +161,40 @@ func TestTemplateConfigValidateTypeForInvalidType(t *testing.T) { err = c.validate() assert.EqualError(t, err, `incorrect type for int_val. expected type integer, but value is "this-should-be-an-int"`) } + +func TestTemplateValidateSchema(t *testing.T) { + var err error + toSchema := func(s string) *jsonschema.Schema { + return &jsonschema.Schema{ + Properties: map[string]*jsonschema.Schema{ + "foo": { + Type: jsonschema.Type(s), + }, + }, + } + } + + err = validateSchema(toSchema("string")) + assert.NoError(t, err) + + err = validateSchema(toSchema("boolean")) + assert.NoError(t, err) + + err = validateSchema(toSchema("number")) + assert.NoError(t, err) + + err = validateSchema(toSchema("integer")) + assert.NoError(t, err) + + err = validateSchema(toSchema("object")) + assert.EqualError(t, err, "property type object is not supported by bundle templates") + + err = validateSchema(toSchema("array")) + assert.EqualError(t, err, "property type array is not supported by bundle templates") + + err = validateSchema(toSchema("int")) + assert.EqualError(t, err, "type int is not a recognized json schema type. Please use \"integer\" instead") + + err = validateSchema(toSchema("foobar")) + assert.EqualError(t, err, "type foobar is not a recognized json schema type") +} diff --git a/libs/template/utils.go b/libs/template/utils.go index e29e0484119..ade6a573058 100644 --- a/libs/template/utils.go +++ b/libs/template/utils.go @@ -69,9 +69,6 @@ func toString(v any, T jsonschema.Type) (string, error) { case jsonschema.ArrayType, jsonschema.ObjectType: return "", fmt.Errorf("cannot format object of type %s as a string. Value of object: %#v", T, v) default: - if T == "int" { - return "", fmt.Errorf(`unknown json schema type %q. Please use "integer" instead`, T) - } return "", fmt.Errorf("unknown json schema type: %q", T) } } @@ -95,9 +92,6 @@ func fromString(s string, T jsonschema.Type) (any, error) { case jsonschema.ArrayType, jsonschema.ObjectType: return "", fmt.Errorf("cannot parse string as object of type %s. Value of string: %q", T, s) default: - if T == "int" { - return "", fmt.Errorf(`unknown json schema type %q. Please use "integer" instead`, T) - } return "", fmt.Errorf("unknown json schema type: %q", T) } diff --git a/libs/template/utils_test.go b/libs/template/utils_test.go index 5e86bd1e2b1..1e038aac6f8 100644 --- a/libs/template/utils_test.go +++ b/libs/template/utils_test.go @@ -83,9 +83,6 @@ func TestTemplateToString(t *testing.T) { _, err = toString("abc", "foobar") assert.EqualError(t, err, "unknown json schema type: \"foobar\"") - - _, err = toString("abc", "int") - assert.EqualError(t, err, "unknown json schema type \"int\". Please use \"integer\" instead") } func TestTemplateFromString(t *testing.T) { @@ -121,7 +118,4 @@ func TestTemplateFromString(t *testing.T) { _, err = fromString("1.0", "foobar") assert.EqualError(t, err, "unknown json schema type: \"foobar\"") - - _, err = fromString("1.0", "int") - assert.EqualError(t, err, "unknown json schema type \"int\". Please use \"integer\" instead") } From 43387fe3652c495357f1703e4c3f2f04a6284bfb Mon Sep 17 00:00:00 2001 From: monalisa Date: Tue, 15 Aug 2023 15:47:36 +0200 Subject: [PATCH 3/4] address comments --- libs/jsonschema/schema.go | 37 ++++++++++++++++++++++++++++ libs/jsonschema/schema_test.go | 44 ++++++++++++++++++++++++++++++++++ libs/template/config.go | 16 ++----------- libs/template/config_test.go | 6 ----- 4 files changed, 83 insertions(+), 20 deletions(-) create mode 100644 libs/jsonschema/schema_test.go diff --git a/libs/jsonschema/schema.go b/libs/jsonschema/schema.go index 49e31bb7434..0aaea81d5a7 100644 --- a/libs/jsonschema/schema.go +++ b/libs/jsonschema/schema.go @@ -1,5 +1,11 @@ package jsonschema +import ( + "encoding/json" + "fmt" + "os" +) + // defines schema for a json object type Schema struct { // Type of the object @@ -47,3 +53,34 @@ const ( ArrayType Type = "array" IntegerType Type = "integer" ) + +func validate(schema *Schema) error { + for _, v := range schema.Properties { + switch v.Type { + case NumberType, BooleanType, StringType, IntegerType: + continue + case "int", "int32", "int64": + return fmt.Errorf("type %s is not a recognized json schema type. Please use \"integer\" instead", v.Type) + case "float", "float32", "float64": + return fmt.Errorf("type %s is not a recognized json schema type. Please use \"number\" instead", v.Type) + case "bool": + return fmt.Errorf("type %s is not a recognized json schema type. Please use \"boolean\" instead", v.Type) + default: + return fmt.Errorf("type %s is not a recognized json schema type", v.Type) + } + } + return nil +} + +func Load(path string) (*Schema, error) { + b, err := os.ReadFile(path) + if err != nil { + return nil, err + } + schema := &Schema{} + err = json.Unmarshal(b, schema) + if err != nil { + return nil, err + } + return schema, validate(schema) +} diff --git a/libs/jsonschema/schema_test.go b/libs/jsonschema/schema_test.go new file mode 100644 index 00000000000..eb525e7b345 --- /dev/null +++ b/libs/jsonschema/schema_test.go @@ -0,0 +1,44 @@ +package jsonschema + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestJsonSchemaValidate(t *testing.T) { + var err error + toSchema := func(s string) *Schema { + return &Schema{ + Properties: map[string]*Schema{ + "foo": { + Type: Type(s), + }, + }, + } + } + + err = validate(toSchema("string")) + assert.NoError(t, err) + + err = validate(toSchema("boolean")) + assert.NoError(t, err) + + err = validate(toSchema("number")) + assert.NoError(t, err) + + err = validate(toSchema("integer")) + assert.NoError(t, err) + + err = validate(toSchema("int")) + assert.EqualError(t, err, "type int is not a recognized json schema type. Please use \"integer\" instead") + + err = validate(toSchema("float")) + assert.EqualError(t, err, "type float is not a recognized json schema type. Please use \"number\" instead") + + err = validate(toSchema("bool")) + assert.EqualError(t, err, "type bool is not a recognized json schema type. Please use \"boolean\" instead") + + err = validate(toSchema("foobar")) + assert.EqualError(t, err, "type foobar is not a recognized json schema type") +} diff --git a/libs/template/config.go b/libs/template/config.go index 4c565b13213..173244b0b6c 100644 --- a/libs/template/config.go +++ b/libs/template/config.go @@ -18,12 +18,7 @@ type config struct { func newConfig(ctx context.Context, schemaPath string) (*config, error) { // Read config schema - schemaBytes, err := os.ReadFile(schemaPath) - if err != nil { - return nil, err - } - schema := &jsonschema.Schema{} - err = json.Unmarshal(schemaBytes, schema) + schema, err := jsonschema.Load(schemaPath) if err != nil { return nil, err } @@ -41,15 +36,8 @@ func newConfig(ctx context.Context, schemaPath string) (*config, error) { func validateSchema(schema *jsonschema.Schema) error { for _, v := range schema.Properties { - switch v.Type { - case jsonschema.NumberType, jsonschema.BooleanType, jsonschema.StringType, jsonschema.IntegerType: - continue - case jsonschema.ArrayType, jsonschema.ObjectType: + if v.Type == jsonschema.ArrayType || v.Type == jsonschema.ObjectType { return fmt.Errorf("property type %s is not supported by bundle templates", v.Type) - case "int", "int32", "int64": - return fmt.Errorf("type %s is not a recognized json schema type. Please use \"integer\" instead", v.Type) - default: - return fmt.Errorf("type %s is not a recognized json schema type", v.Type) } } return nil diff --git a/libs/template/config_test.go b/libs/template/config_test.go index 8f967ce6898..335242467f8 100644 --- a/libs/template/config_test.go +++ b/libs/template/config_test.go @@ -191,10 +191,4 @@ func TestTemplateValidateSchema(t *testing.T) { err = validateSchema(toSchema("array")) assert.EqualError(t, err, "property type array is not supported by bundle templates") - - err = validateSchema(toSchema("int")) - assert.EqualError(t, err, "type int is not a recognized json schema type. Please use \"integer\" instead") - - err = validateSchema(toSchema("foobar")) - assert.EqualError(t, err, "type foobar is not a recognized json schema type") } From f0867fd83575c93a0869ea5bc70853109d250699 Mon Sep 17 00:00:00 2001 From: monalisa Date: Tue, 15 Aug 2023 15:51:46 +0200 Subject: [PATCH 4/4] make validate a member function --- libs/jsonschema/schema.go | 4 ++-- libs/jsonschema/schema_test.go | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libs/jsonschema/schema.go b/libs/jsonschema/schema.go index 0aaea81d5a7..c0d1736c1dc 100644 --- a/libs/jsonschema/schema.go +++ b/libs/jsonschema/schema.go @@ -54,7 +54,7 @@ const ( IntegerType Type = "integer" ) -func validate(schema *Schema) error { +func (schema *Schema) validate() error { for _, v := range schema.Properties { switch v.Type { case NumberType, BooleanType, StringType, IntegerType: @@ -82,5 +82,5 @@ func Load(path string) (*Schema, error) { if err != nil { return nil, err } - return schema, validate(schema) + return schema, schema.validate() } diff --git a/libs/jsonschema/schema_test.go b/libs/jsonschema/schema_test.go index eb525e7b345..76112492f57 100644 --- a/libs/jsonschema/schema_test.go +++ b/libs/jsonschema/schema_test.go @@ -18,27 +18,27 @@ func TestJsonSchemaValidate(t *testing.T) { } } - err = validate(toSchema("string")) + err = toSchema("string").validate() assert.NoError(t, err) - err = validate(toSchema("boolean")) + err = toSchema("boolean").validate() assert.NoError(t, err) - err = validate(toSchema("number")) + err = toSchema("number").validate() assert.NoError(t, err) - err = validate(toSchema("integer")) + err = toSchema("integer").validate() assert.NoError(t, err) - err = validate(toSchema("int")) + err = toSchema("int").validate() assert.EqualError(t, err, "type int is not a recognized json schema type. Please use \"integer\" instead") - err = validate(toSchema("float")) + err = toSchema("float").validate() assert.EqualError(t, err, "type float is not a recognized json schema type. Please use \"number\" instead") - err = validate(toSchema("bool")) + err = toSchema("bool").validate() assert.EqualError(t, err, "type bool is not a recognized json schema type. Please use \"boolean\" instead") - err = validate(toSchema("foobar")) + err = toSchema("foobar").validate() assert.EqualError(t, err, "type foobar is not a recognized json schema type") }