Skip to content

Commit

Permalink
DataInputSchema can only be a string and not an object (#196)
Browse files Browse the repository at this point in the history
  • Loading branch information
spolti authored May 8, 2024
1 parent 66cd3e5 commit bb89ed0
Show file tree
Hide file tree
Showing 13 changed files with 245 additions and 37 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ lint:

.PHONY: test
coverage="false"

test: deepcopy buildergen
make lint
@go test ./...
Expand Down
9 changes: 8 additions & 1 deletion builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package builder
import (
"testing"

"github.com/pkg/errors"
"github.com/stretchr/testify/assert"

"github.com/serverlessworkflow/sdk-go/v2/model"
Expand Down Expand Up @@ -58,7 +59,13 @@ func TestValidate(t *testing.T) {
state2.End().Terminate(true)
err = Validate(state2.Build())
if assert.Error(t, err) {
assert.Equal(t, "state.name is required", err.(val.WorkflowErrors)[0].Error())
var workflowErrors val.WorkflowErrors
if errors.As(err, &workflowErrors) {
assert.Equal(t, "state.name is required", workflowErrors[0].Error())
} else {
// Handle other error types if necessary
t.Errorf("Unexpected error: %v", err)
}
}
}

Expand Down
43 changes: 40 additions & 3 deletions model/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
package model

import (
"bytes"
"encoding/json"
"errors"

"github.com/serverlessworkflow/sdk-go/v2/util"
)
Expand Down Expand Up @@ -121,7 +123,7 @@ type BaseWorkflow struct {
// qualities.
// +optional
Annotations []string `json:"annotations,omitempty"`
// DataInputSchema URI of the JSON Schema used to validate the workflow data input
// DataInputSchema URI or Object of the JSON Schema used to validate the workflow data input
// +optional
DataInputSchema *DataInputSchema `json:"dataInputSchema,omitempty"`
// Serverless Workflow schema version
Expand Down Expand Up @@ -225,6 +227,7 @@ func (w *Workflow) UnmarshalJSON(data []byte) error {
return nil
}

// States ...
// +kubebuilder:validation:MinItems=1
type States []State

Expand Down Expand Up @@ -510,7 +513,7 @@ type StateDataFilter struct {
// +builder-gen:new-call=ApplyDefault
type DataInputSchema struct {
// +kubebuilder:validation:Required
Schema string `json:"schema" validate:"required"`
Schema *Object `json:"schema" validate:"required"`
// +kubebuilder:validation:Required
FailOnValidationErrors bool `json:"failOnValidationErrors"`
}
Expand All @@ -520,7 +523,41 @@ type dataInputSchemaUnmarshal DataInputSchema
// UnmarshalJSON implements json.Unmarshaler
func (d *DataInputSchema) UnmarshalJSON(data []byte) error {
d.ApplyDefault()
return util.UnmarshalPrimitiveOrObject("dataInputSchema", data, &d.Schema, (*dataInputSchemaUnmarshal)(d))

// expected: data = "{\"key\": \"value\"}"
// data = {"key": "value"}
// data = "file://..."
// data = { "schema": "{\"key\": \"value\"}", "failOnValidationErrors": true }
// data = { "schema": {"key": "value"}, "failOnValidationErrors": true }
// data = { "schema": "file://...", "failOnValidationErrors": true }

schemaString := ""
err := util.UnmarshalPrimitiveOrObject("dataInputSchema", data, &schemaString, (*dataInputSchemaUnmarshal)(d))
if err != nil {
return err
}

if d.Schema != nil {
if d.Schema.Type == Map {
return nil

} else if d.Schema.Type == String {
schemaString = d.Schema.StringValue

} else {
return errors.New("invalid dataInputSchema must be a string or object")
}
}

if schemaString != "" {
data = []byte(schemaString)
if bytes.TrimSpace(data)[0] != '{' {
data = []byte("\"" + schemaString + "\"")
}
}

d.Schema = new(Object)
return util.UnmarshalObjectOrFile("schema", data, &d.Schema)
}

// ApplyDefault set the default values for Data Input Schema
Expand Down
57 changes: 42 additions & 15 deletions model/workflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,13 @@ func TestTransitionUnmarshalJSON(t *testing.T) {
}

func TestDataInputSchemaUnmarshalJSON(t *testing.T) {

var schemaName Object
err := json.Unmarshal([]byte("{\"key\": \"value\"}"), &schemaName)
if !assert.NoError(t, err) {
return
}

type testCase struct {
desp string
data string
Expand All @@ -508,53 +515,73 @@ func TestDataInputSchemaUnmarshalJSON(t *testing.T) {
testCases := []testCase{
{
desp: "string success",
data: `"schema name"`,
data: "{\"key\": \"value\"}",
expect: DataInputSchema{
Schema: "schema name",
Schema: &schemaName,
FailOnValidationErrors: true,
},
err: ``,
},
{
desp: `object success`,
data: `{"schema": "schema name"}`,
desp: "string fail",
data: "{\"key\": }",
expect: DataInputSchema{
Schema: "schema name",
Schema: &schemaName,
FailOnValidationErrors: true,
},
err: `invalid character '}' looking for beginning of value`,
},
{
desp: `object success (without quotes)`,
data: `{"key": "value"}`,
expect: DataInputSchema{
Schema: &schemaName,
FailOnValidationErrors: true,
},
err: ``,
},
{
desp: `object fail`,
data: `{"schema": "schema name}`,
desp: `schema object success`,
data: `{"schema": "{\"key\": \"value\"}"}`,
expect: DataInputSchema{
Schema: "schema name",
Schema: &schemaName,
FailOnValidationErrors: true,
},
err: `unexpected end of JSON input`,
err: ``,
},
{
desp: `object key invalid`,
data: `{"schema_invalid": "schema name"}`,
desp: `schema object success (without quotes)`,
data: `{"schema": {"key": "value"}}`,
expect: DataInputSchema{
Schema: &schemaName,
FailOnValidationErrors: true,
},
err: ``,
},
{
desp: `schema object fail`,
data: `{"schema": "schema name}`,
expect: DataInputSchema{
Schema: &schemaName,
FailOnValidationErrors: true,
},
err: `unexpected end of JSON input`,
},
}
for _, tc := range testCases {
t.Run(tc.desp, func(t *testing.T) {
var v DataInputSchema
err := json.Unmarshal([]byte(tc.data), &v)

if tc.err != "" {
assert.Error(t, err)
assert.Regexp(t, tc.err, err)
assert.Error(t, err, tc.desp)
assert.Regexp(t, tc.err, err, tc.desp)
return
}

assert.NoError(t, err)
assert.Equal(t, tc.expect, v)
assert.NoError(t, err, tc.desp)
assert.Equal(t, tc.expect.Schema, v.Schema, tc.desp)
assert.Equal(t, tc.expect.FailOnValidationErrors, v.FailOnValidationErrors, tc.desp)
})
}
}
Expand Down
5 changes: 4 additions & 1 deletion model/workflow_validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,8 @@ func TestDataInputSchemaStructLevelValidation(t *testing.T) {
action1 := buildActionByOperationState(operationState, "action 1")
buildFunctionRef(baseWorkflow, action1, "function 1")

sampleSchema := FromString("sample schema")

testCases := []ValidationCase{
{
Desp: "empty DataInputSchema",
Expand All @@ -440,13 +442,14 @@ func TestDataInputSchemaStructLevelValidation(t *testing.T) {
Model: func() Workflow {
model := baseWorkflow.DeepCopy()
model.DataInputSchema = &DataInputSchema{
Schema: "sample schema",
Schema: &sampleSchema,
}
return *model
},
},
}

//fmt.Printf("%+v", testCases[0].Model)
StructLevelValidationCtx(t, testCases)
}

Expand Down
41 changes: 36 additions & 5 deletions model/zz_generated.buildergen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion model/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 20 additions & 2 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package parser

import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -582,8 +583,25 @@ func TestFromFile(t *testing.T) {
}, {
"./testdata/workflows/dataInputSchemaValidation.yaml", func(t *testing.T, w *model.Workflow) {
assert.NotNil(t, w.DataInputSchema)

assert.Equal(t, "sample schema", w.DataInputSchema.Schema)
expected := model.DataInputSchema{}
data, err := util.LoadExternalResource("file://testdata/datainputschema.json")
err1 := util.UnmarshalObject("schema", data, &expected.Schema)
assert.Nil(t, err)
assert.Nil(t, err1)
assert.Equal(t, expected.Schema, w.DataInputSchema.Schema)
assert.Equal(t, false, w.DataInputSchema.FailOnValidationErrors)
},
}, {
"./testdata/workflows/dataInputSchemaObject.json", func(t *testing.T, w *model.Workflow) {
assert.NotNil(t, w.DataInputSchema)
expected := model.Object{}
err := json.Unmarshal([]byte("{\"title\": \"Hello World Schema\", \"properties\": {\"person\": "+
"{\"type\": \"object\",\"properties\": {\"name\": {\"type\": \"string\"}},\"required\": "+
"[\"name\"]}}, \"required\": [\"person\"]}"),
&expected)
fmt.Printf("err: %s\n", err)
fmt.Printf("schema: %+v\n", expected)
assert.Equal(t, &expected, w.DataInputSchema.Schema)
assert.Equal(t, false, w.DataInputSchema.FailOnValidationErrors)
},
},
Expand Down
16 changes: 16 additions & 0 deletions parser/testdata/datainputschema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"title": "Hello World Schema",
"properties": {
"person": {
"type": "object",
"properties": {
"name": {
"type": "string"
}
},
"required": [
"name"
]
}
}
}
Loading

0 comments on commit bb89ed0

Please sign in to comment.