Skip to content

Commit

Permalink
Validate the refs exists (#164)
Browse files Browse the repository at this point in the history
* Add validator with context to validate the refs (functions, events, retries, etc) exists

Signed-off-by: André R. de Miranda <andre@galgo.tech>

* Valid errors exist and change unique_struct to unique

Signed-off-by: André R. de Miranda <andre@galgo.tech>

* Fix lint

Signed-off-by: André R. de Miranda <andre@galgo.tech>

* Add transition and compensation validations. Refactor state exists

Signed-off-by: André R. de Miranda <andre@galgo.tech>

* Json ignore field

Signed-off-by: André R. de Miranda <andre@galgo.tech>

* Fix tests

Signed-off-by: André R. de Miranda <andre@galgo.tech>

* Add validations: OnEvent.EventRefs, EventCondition.EventRef, and FunctionType

Signed-off-by: André R. de Miranda <andre@galgo.tech>

* Fix tests

Signed-off-by: André R. de Miranda <andre@galgo.tech>

* Replace oneof to oneofkind, and improve the error message

Signed-off-by: André R. de Miranda <andre@galgo.tech>

* Validation refactoring for each struct to have its test case. Revision suggestions

Signed-off-by: André R. de Miranda <andre@galgo.tech>

* Add validation oneofkind validation auth struct

Signed-off-by: André R. de Miranda <andre@galgo.tech>

* Add new tests and improve error description

Signed-off-by: André R. de Miranda <andre@galgo.tech>

* Add new unit tests, refactor intstr validator, and add new validation description

Signed-off-by: André R. de Miranda <andre@galgo.tech>

* Remove reflection from validation

Signed-off-by: André R. de Miranda <andre@galgo.tech>

* Remove commented code

Signed-off-by: André R. de Miranda <andre@galgo.tech>

---------

Signed-off-by: André R. de Miranda <andre@galgo.tech>
  • Loading branch information
ribeiromiranda authored Jul 11, 2023
1 parent 5110906 commit 4afc5f3
Show file tree
Hide file tree
Showing 70 changed files with 3,645 additions and 1,625 deletions.
1 change: 1 addition & 0 deletions hack/deepcopy-gen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ if [ "${GENS}" = "all" ] || grep -qw "deepcopy" <<<"${GENS}"; then
"${GOPATH}/bin/deepcopy-gen" -v 1 \
--input-dirs ./model -O zz_generated.deepcopy \
--go-header-file "${SCRIPT_ROOT}/hack/boilerplate.txt" \
--output-base ./
"$@"
fi
8 changes: 5 additions & 3 deletions model/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package model

import "github.com/serverlessworkflow/sdk-go/v2/util"

// Action specify invocations of services or other workflows during workflow execution.
type Action struct {
// Defines Unique action identifier.
Expand Down Expand Up @@ -61,7 +63,7 @@ type actionUnmarshal Action
// UnmarshalJSON implements json.Unmarshaler
func (a *Action) UnmarshalJSON(data []byte) error {
a.ApplyDefault()
return unmarshalObject("action", data, (*actionUnmarshal)(a))
return util.UnmarshalObject("action", data, (*actionUnmarshal)(a))
}

// ApplyDefault set the default values for Action
Expand Down Expand Up @@ -93,7 +95,7 @@ type functionRefUnmarshal FunctionRef
// UnmarshalJSON implements json.Unmarshaler
func (f *FunctionRef) UnmarshalJSON(data []byte) error {
f.ApplyDefault()
return unmarshalPrimitiveOrObject("functionRef", data, &f.RefName, (*functionRefUnmarshal)(f))
return util.UnmarshalPrimitiveOrObject("functionRef", data, &f.RefName, (*functionRefUnmarshal)(f))
}

// ApplyDefault set the default values for Function Ref
Expand All @@ -117,5 +119,5 @@ type sleepUnmarshal Sleep

// UnmarshalJSON implements json.Unmarshaler
func (s *Sleep) UnmarshalJSON(data []byte) error {
return unmarshalObject("sleep", data, (*sleepUnmarshal)(s))
return util.UnmarshalObject("sleep", data, (*sleepUnmarshal)(s))
}
4 changes: 3 additions & 1 deletion model/action_data_filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package model

import "github.com/serverlessworkflow/sdk-go/v2/util"

// ActionDataFilter used to filter action data results.
// +optional
// +optional
Expand All @@ -40,7 +42,7 @@ type actionDataFilterUnmarshal ActionDataFilter
// UnmarshalJSON implements json.Unmarshaler
func (a *ActionDataFilter) UnmarshalJSON(data []byte) error {
a.ApplyDefault()
return unmarshalObject("actionDataFilter", data, (*actionDataFilterUnmarshal)(a))
return util.UnmarshalObject("actionDataFilter", data, (*actionDataFilterUnmarshal)(a))
}

// ApplyDefault set the default values for Action Data Filter
Expand Down
22 changes: 22 additions & 0 deletions model/action_data_filter_validator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2022 The Serverless Workflow Specification Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package model

import "testing"

func TestActionDataFilterStructLevelValidation(t *testing.T) {
testCases := []ValidationCase{}
StructLevelValidationCtx(t, testCases)
}
73 changes: 0 additions & 73 deletions model/action_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,81 +19,8 @@ import (
"testing"

"github.com/stretchr/testify/assert"

val "github.com/serverlessworkflow/sdk-go/v2/validator"
)

func TestSleepValidate(t *testing.T) {
type testCase struct {
desp string
sleep Sleep
err string
}
testCases := []testCase{
{
desp: "all field empty",
sleep: Sleep{
Before: "",
After: "",
},
err: ``,
},
{
desp: "only before field",
sleep: Sleep{
Before: "PT5M",
After: "",
},
err: ``,
},
{
desp: "only after field",
sleep: Sleep{
Before: "",
After: "PT5M",
},
err: ``,
},
{
desp: "all field",
sleep: Sleep{
Before: "PT5M",
After: "PT5M",
},
err: ``,
},
{
desp: "invalid before value",
sleep: Sleep{
Before: "T5M",
After: "PT5M",
},
err: `Key: 'Sleep.Before' Error:Field validation for 'Before' failed on the 'iso8601duration' tag`,
},
{
desp: "invalid after value",
sleep: Sleep{
Before: "PT5M",
After: "T5M",
},
err: `Key: 'Sleep.After' Error:Field validation for 'After' failed on the 'iso8601duration' tag`,
},
}
for _, tc := range testCases {
t.Run(tc.desp, func(t *testing.T) {
err := val.GetValidator().Struct(tc.sleep)

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

assert.NoError(t, err)
})
}
}

func TestFunctionRefUnmarshalJSON(t *testing.T) {
type testCase struct {
desp string
Expand Down
58 changes: 58 additions & 0 deletions model/action_validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2022 The Serverless Workflow Specification Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package model

import (
validator "github.com/go-playground/validator/v10"

val "github.com/serverlessworkflow/sdk-go/v2/validator"
)

func init() {
val.GetValidator().RegisterStructValidationCtx(ValidationWrap(actionStructLevelValidationCtx), Action{})
val.GetValidator().RegisterStructValidationCtx(ValidationWrap(functionRefStructLevelValidation), FunctionRef{})
}

func actionStructLevelValidationCtx(ctx ValidatorContext, structLevel validator.StructLevel) {
action := structLevel.Current().Interface().(Action)

if action.FunctionRef == nil && action.EventRef == nil && action.SubFlowRef == nil {
structLevel.ReportError(action.FunctionRef, "FunctionRef", "FunctionRef", "required_without", "")
return
}

values := []bool{
action.FunctionRef != nil,
action.EventRef != nil,
action.SubFlowRef != nil,
}

if validationNotExclusiveParamters(values) {
structLevel.ReportError(action.FunctionRef, "FunctionRef", "FunctionRef", val.TagExclusive, "")
structLevel.ReportError(action.EventRef, "EventRef", "EventRef", val.TagExclusive, "")
structLevel.ReportError(action.SubFlowRef, "SubFlowRef", "SubFlowRef", val.TagExclusive, "")
}

if action.RetryRef != "" && !ctx.ExistRetry(action.RetryRef) {
structLevel.ReportError(action.RetryRef, "RetryRef", "RetryRef", val.TagExists, "")
}
}

func functionRefStructLevelValidation(ctx ValidatorContext, structLevel validator.StructLevel) {
functionRef := structLevel.Current().Interface().(FunctionRef)
if !ctx.ExistFunction(functionRef.RefName) {
structLevel.ReportError(functionRef.RefName, "RefName", "RefName", val.TagExists, functionRef.RefName)
}
}
Loading

0 comments on commit 4afc5f3

Please sign in to comment.