Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return better error messages for invalid JSON schema types in templates #661

Merged
merged 4 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions libs/jsonschema/schema.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package jsonschema

import (
"encoding/json"
"fmt"
"os"
)

// defines schema for a json object
type Schema struct {
// Type of the object
Expand Down Expand Up @@ -47,3 +53,34 @@ const (
ArrayType Type = "array"
IntegerType Type = "integer"
)

func (schema *Schema) validate() 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, schema.validate()
}
44 changes: 44 additions & 0 deletions libs/jsonschema/schema_test.go
Original file line number Diff line number Diff line change
@@ -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 = toSchema("string").validate()
assert.NoError(t, err)

err = toSchema("boolean").validate()
assert.NoError(t, err)

err = toSchema("number").validate()
assert.NoError(t, err)

err = toSchema("integer").validate()
assert.NoError(t, err)

err = toSchema("int").validate()
assert.EqualError(t, err, "type int is not a recognized json schema type. Please use \"integer\" instead")

err = toSchema("float").validate()
assert.EqualError(t, err, "type float is not a recognized json schema type. Please use \"number\" instead")

err = toSchema("bool").validate()
assert.EqualError(t, err, "type bool is not a recognized json schema type. Please use \"boolean\" instead")

err = toSchema("foobar").validate()
assert.EqualError(t, err, "type foobar is not a recognized json schema type")
}
15 changes: 11 additions & 4 deletions libs/template/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@ type config struct {

func newConfig(ctx context.Context, schemaPath string) (*config, error) {
// Read config schema
schemaBytes, err := os.ReadFile(schemaPath)
schema, err := jsonschema.Load(schemaPath)
if err != nil {
return nil, err
}
schema := &jsonschema.Schema{}
err = json.Unmarshal(schemaBytes, schema)
if err != nil {
if err := validateSchema(schema); err != nil {
return nil, err
}

Expand All @@ -36,6 +34,15 @@ func newConfig(ctx context.Context, schemaPath string) (*config, error) {
}, nil
}

func validateSchema(schema *jsonschema.Schema) error {
for _, v := range schema.Properties {
if v.Type == jsonschema.ArrayType || v.Type == jsonschema.ObjectType {
return fmt.Errorf("property type %s is not supported by bundle templates", v.Type)
}
}
return nil
shreyas-goenka marked this conversation as resolved.
Show resolved Hide resolved
}

// Reads json file at path and assigns values from the file
func (c *config) assignValuesFromFile(path string) error {
// Read the config file
Expand Down
31 changes: 31 additions & 0 deletions libs/template/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,34 @@ 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")
}
8 changes: 6 additions & 2 deletions libs/template/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,10 @@ 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:
return "", fmt.Errorf("unknown json schema type: %q", T)
}
}

Expand All @@ -87,8 +89,10 @@ 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:
return "", fmt.Errorf("unknown json schema type: %q", T)
}

// Return more readable error incase of a syntax error
Expand Down
6 changes: 6 additions & 0 deletions libs/template/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ 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\"")
}

func TestTemplateFromString(t *testing.T) {
Expand Down Expand Up @@ -112,4 +115,7 @@ 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\"")
}