From 8b6ef58ede4653ed1363bdc6a7d730aa3d0f05dd Mon Sep 17 00:00:00 2001 From: candiduslynx Date: Tue, 17 Oct 2023 12:58:27 +0300 Subject: [PATCH 1/2] add JSON schema for configtype.Duration --- configtype/duration.go | 11 ++++++ configtype/duration_test.go | 75 +++++++++++++++++++++++++++++++++++++ scheduler/strategy_test.go | 3 +- 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/configtype/duration.go b/configtype/duration.go index 6c1e0777f8..672af0e256 100644 --- a/configtype/duration.go +++ b/configtype/duration.go @@ -3,6 +3,8 @@ package configtype import ( "encoding/json" "time" + + "github.com/invopop/jsonschema" ) // Duration is a wrapper around time.Duration that should be used in config @@ -19,6 +21,15 @@ func NewDuration(d time.Duration) Duration { } } +func (Duration) JSONSchema() *jsonschema.Schema { + // provide a pattern for only non-negative durations + return &jsonschema.Schema{ + Type: "string", + Pattern: `^[-+]?([0-9]*(\.[0-9]*)?[a-z]+)+$`, // copied from time.ParseDuration + Title: "CloudQuery configtype.Duration", + } +} + func (d *Duration) UnmarshalJSON(b []byte) error { var s string if err := json.Unmarshal(b, &s); err != nil { diff --git a/configtype/duration_test.go b/configtype/duration_test.go index 0fdd3c2b06..fadd3d1104 100644 --- a/configtype/duration_test.go +++ b/configtype/duration_test.go @@ -2,11 +2,15 @@ package configtype_test import ( "encoding/json" + "math/rand" "testing" "time" "github.com/cloudquery/plugin-sdk/v4/configtype" + "github.com/cloudquery/plugin-sdk/v4/plugin" "github.com/google/go-cmp/cmp" + "github.com/invopop/jsonschema" + "github.com/stretchr/testify/require" ) func TestDuration(t *testing.T) { @@ -52,3 +56,74 @@ func TestComparability(t *testing.T) { } } } + +func TestDuration_JSONSchema(t *testing.T) { + sc := (&jsonschema.Reflector{RequiredFromJSONSchemaTags: true}).Reflect(configtype.Duration{}) + schema, err := json.MarshalIndent(sc, "", " ") + require.NoError(t, err) + + validator, err := plugin.JSONSchemaValidator(string(schema)) + require.NoError(t, err) + + type testCase struct { + Name string + Spec string + Err bool + } + + for _, tc := range append([]testCase{ + { + Name: "empty", + Err: true, + Spec: `""`, + }, + { + Name: "null", + Err: true, + Spec: `null`, + }, + { + Name: "bad type", + Err: true, + Spec: `false`, + }, + { + Name: "bad format", + Err: true, + Spec: `false`, + }, + }, + func() []testCase { + rnd := rand.New(rand.NewSource(time.Now().UnixNano())) + const ( + cases = 20 + maxDur = int64(100 * time.Hour) + maxDurHalf = maxDur / 2 + ) + result := make([]testCase, cases) + for i := 0; i < cases; i++ { + val := rnd.Int63n(maxDur) - maxDurHalf + d := configtype.NewDuration(time.Duration(val)) + + data, err := d.MarshalJSON() + require.NoError(t, err) + result[i] = testCase{ + Name: string(data), + Spec: string(data), + } + } + return result + }()..., + ) { + t.Run(tc.Name, func(t *testing.T) { + var val any + err := json.Unmarshal([]byte(tc.Spec), &val) + require.NoError(t, err) + if tc.Err { + require.Error(t, validator.Validate(val)) + } else { + require.NoError(t, validator.Validate(val)) + } + }) + } +} diff --git a/scheduler/strategy_test.go b/scheduler/strategy_test.go index 3eec7d4480..9718ee563c 100644 --- a/scheduler/strategy_test.go +++ b/scheduler/strategy_test.go @@ -3,7 +3,6 @@ package scheduler_test import ( _ "embed" "encoding/json" - "reflect" "testing" "github.com/cloudquery/plugin-sdk/v4/plugin" @@ -13,7 +12,7 @@ import ( ) func TestStrategy_JSONSchema(t *testing.T) { - sc := (&jsonschema.Reflector{RequiredFromJSONSchemaTags: true}).ReflectFromType(reflect.TypeOf(scheduler.StrategyDFS)) + sc := (&jsonschema.Reflector{RequiredFromJSONSchemaTags: true}).Reflect(scheduler.StrategyDFS) schema, err := json.MarshalIndent(sc, "", " ") require.NoError(t, err) From df0b27e786aa77246e467afb8263f262f48cc002 Mon Sep 17 00:00:00 2001 From: candiduslynx Date: Tue, 17 Oct 2023 13:24:30 +0300 Subject: [PATCH 2/2] rm comment --- configtype/duration.go | 1 - 1 file changed, 1 deletion(-) diff --git a/configtype/duration.go b/configtype/duration.go index 672af0e256..dc8789ce05 100644 --- a/configtype/duration.go +++ b/configtype/duration.go @@ -22,7 +22,6 @@ func NewDuration(d time.Duration) Duration { } func (Duration) JSONSchema() *jsonschema.Schema { - // provide a pattern for only non-negative durations return &jsonschema.Schema{ Type: "string", Pattern: `^[-+]?([0-9]*(\.[0-9]*)?[a-z]+)+$`, // copied from time.ParseDuration