Skip to content

Commit 2fd3146

Browse files
committed
Fix Float32OrString validation methods
Signed-off-by: Ricardo Zanini <[email protected]>
1 parent 2f01a0d commit 2fd3146

File tree

8 files changed

+122
-88
lines changed

8 files changed

+122
-88
lines changed

Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@ fmt:
66
@go vet ./...
77
@go fmt ./...
88

9+
goimports:
10+
@command -v goimports > /dev/null || go install golang.org/x/tools/cmd/goimports@latest
11+
@goimports -w .
12+
13+
914
lint:
1015
@command -v golangci-lint > /dev/null || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "${GOPATH}/bin"
1116
make addheaders
17+
make goimports
1218
make fmt
1319
./hack/go-lint.sh ${params}
1420

go.mod

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,32 @@
11
module github.com/serverlessworkflow/sdk-go/v2
22

3-
go 1.22.0
3+
go 1.22.8
44

55
toolchain go1.23.1
66

77
require (
8-
github.com/go-playground/validator/v10 v10.11.1
8+
github.com/go-playground/validator/v10 v10.16.0
99
github.com/pkg/errors v0.9.1
1010
github.com/relvacode/iso8601 v1.4.0
1111
github.com/sosodev/duration v1.3.1
1212
github.com/stretchr/testify v1.9.0
1313
gopkg.in/yaml.v3 v3.0.1
14-
k8s.io/apimachinery v0.31.0
14+
k8s.io/apimachinery v0.31.1
1515
sigs.k8s.io/controller-runtime v0.19.0
1616
sigs.k8s.io/yaml v1.4.0
1717
)
1818

1919
require (
2020
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
2121
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
22+
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
2223
github.com/go-logr/logr v1.4.2 // indirect
2324
github.com/go-playground/locales v0.14.1 // indirect
24-
github.com/go-playground/universal-translator v0.18.0 // indirect
25+
github.com/go-playground/universal-translator v0.18.1 // indirect
2526
github.com/gogo/protobuf v1.3.2 // indirect
2627
github.com/google/gofuzz v1.2.0 // indirect
2728
github.com/json-iterator/go v1.1.12 // indirect
28-
github.com/leodido/go-urn v1.2.1 // indirect
29+
github.com/leodido/go-urn v1.4.0 // indirect
2930
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
3031
github.com/modern-go/reflect2 v1.0.2 // indirect
3132
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect

go.sum

Lines changed: 13 additions & 77 deletions
Large diffs are not rendered by default.

model/action_validator_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ package model
1616

1717
import (
1818
"testing"
19+
20+
"k8s.io/apimachinery/pkg/util/intstr"
1921
)
2022

2123
func buildActionByOperationState(state *State, name string) *Action {
@@ -64,7 +66,8 @@ func buildFunctionRef(workflow *Workflow, action *Action, name string) (*Functio
6466

6567
func buildRetryRef(workflow *Workflow, action *Action, name string) {
6668
retry := Retry{
67-
Name: name,
69+
Name: name,
70+
MaxAttempts: intstr.FromInt32(1),
6871
}
6972

7073
workflow.Retries = append(workflow.Retries, retry)

model/retry.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,5 @@ func (r *Retry) UnmarshalJSON(data []byte) error {
5353
}
5454

5555
func (r *Retry) ApplyDefault() {
56-
r.MaxAttempts = intstr.FromInt(1)
56+
r.MaxAttempts = intstr.FromInt32(1)
5757
}

model/retry_validator_test.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func TestRetryStructLevelValidation(t *testing.T) {
3737
model.Retries[0].Delay = "PT5S"
3838
model.Retries[0].MaxDelay = "PT5S"
3939
model.Retries[0].Increment = "PT5S"
40-
model.Retries[0].Jitter = floatstr.FromString("PT5S")
40+
model.Retries[0].Jitter = floatstr.FromString("0.5")
4141
return *model
4242
},
4343
},
@@ -82,8 +82,18 @@ func TestRetryStructLevelValidation(t *testing.T) {
8282
},
8383
Err: `workflow.retries[0].delay invalid iso8601 duration "P5S"
8484
workflow.retries[0].maxDelay invalid iso8601 duration "P5S"
85-
workflow.retries[0].increment invalid iso8601 duration "P5S"
86-
workflow.retries[0].jitter invalid iso8601 duration "P5S"`,
85+
workflow.retries[0].increment invalid iso8601 duration "P5S"`,
86+
},
87+
{
88+
Desp: "multiplier less than zero",
89+
Model: func() Workflow {
90+
multiplierZero := floatstr.FromString("0")
91+
model := baseWorkflow.DeepCopy()
92+
model.Retries[0].Multiplier = &multiplierZero
93+
94+
return *model
95+
},
96+
Err: `workflow.retries[0].multiplier must have the minimum `,
8797
},
8898
}
8999

model/workflow_validator.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ package model
1717
import (
1818
"context"
1919

20+
"github.com/serverlessworkflow/sdk-go/v2/util/floatstr"
21+
2022
validator "github.com/go-playground/validator/v10"
2123

2224
val "github.com/serverlessworkflow/sdk-go/v2/validator"
@@ -156,6 +158,8 @@ func init() {
156158
val.GetValidator().RegisterStructValidationCtx(ValidationWrap(onErrorStructLevelValidationCtx), OnError{})
157159
val.GetValidator().RegisterStructValidationCtx(ValidationWrap(transitionStructLevelValidationCtx), Transition{})
158160
val.GetValidator().RegisterStructValidationCtx(ValidationWrap(startStructLevelValidationCtx), Start{})
161+
162+
val.GetValidator().RegisterStructValidation(floatstr.ValidateFloat32OrString, Retry{})
159163
}
160164

161165
func startStructLevelValidationCtx(ctx ValidatorContext, structLevel validator.StructLevel) {

util/floatstr/floatstr.go

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,14 @@ package floatstr
1616

1717
import (
1818
"encoding/json"
19+
"errors"
1920
"fmt"
21+
"reflect"
2022
"strconv"
23+
"strings"
24+
25+
"github.com/go-playground/validator/v10"
26+
val "github.com/serverlessworkflow/sdk-go/v2/validator"
2127
)
2228

2329
// Float32OrString is a type that can hold a float32 or a string.
@@ -71,7 +77,7 @@ func (floatstr *Float32OrString) UnmarshalJSON(value []byte) error {
7177
}
7278

7379
// MarshalJSON implements the json.Marshaller interface.
74-
func (floatstr Float32OrString) MarshalJSON() ([]byte, error) {
80+
func (floatstr *Float32OrString) MarshalJSON() ([]byte, error) {
7581
switch floatstr.Type {
7682
case Float:
7783
return json.Marshal(floatstr.FloatVal)
@@ -103,3 +109,71 @@ func (floatstr *Float32OrString) FloatValue() float32 {
103109
}
104110
return floatstr.FloatVal
105111
}
112+
113+
func init() {
114+
val.GetValidator().RegisterCustomTypeFunc(func(fl reflect.Value) interface{} {
115+
if fl.Kind() != reflect.Struct {
116+
return errors.New("invalid type: expected Float32OrString")
117+
}
118+
119+
// Get the Float32OrString value
120+
_, ok := fl.Interface().(Float32OrString)
121+
if !ok {
122+
return fmt.Errorf("invalid type: expected Float32OrString")
123+
}
124+
125+
return nil
126+
}, Float32OrString{})
127+
}
128+
129+
func ValidateFloat32OrString(sl validator.StructLevel) {
130+
// Get the current struct being validated.
131+
current := sl.Current()
132+
133+
for i := 0; i < current.NumField(); i++ {
134+
field := current.Type().Field(i)
135+
value := current.Field(i)
136+
137+
// Check if the field is a pointer and handle nil pointers.
138+
if value.Kind() == reflect.Ptr {
139+
if value.IsNil() {
140+
continue // Skip nil pointers.
141+
}
142+
value = value.Elem() // Dereference the pointer.
143+
}
144+
145+
// Check if the field is of type Float32OrString.
146+
if value.Type() == reflect.TypeOf(Float32OrString{}) {
147+
// Extract validation tags from the field.
148+
tags := field.Tag.Get("validate")
149+
150+
// Split tags and look for min/max.
151+
tagList := strings.Split(tags, ",")
152+
for _, tag := range tagList {
153+
if strings.HasPrefix(tag, "min=") {
154+
minVal, err := strconv.ParseFloat(strings.TrimPrefix(tag, "min="), 32)
155+
if err != nil {
156+
sl.ReportError(value.Interface(), field.Name, field.Name, "min", "")
157+
continue
158+
}
159+
160+
if value.FieldByName("FloatVal").Float() < minVal {
161+
sl.ReportError(value.Interface(), field.Name, field.Name, "min", "")
162+
}
163+
}
164+
165+
if strings.HasPrefix(tag, "max=") {
166+
maxVal, err := strconv.ParseFloat(strings.TrimPrefix(tag, "max="), 32)
167+
if err != nil {
168+
sl.ReportError(value.Interface(), field.Name, field.Name, "max", "")
169+
continue
170+
}
171+
172+
if value.FieldByName("FloatVal").Float() > maxVal {
173+
sl.ReportError(value.Interface(), field.Name, field.Name, "max", "")
174+
}
175+
}
176+
}
177+
}
178+
}
179+
}

0 commit comments

Comments
 (0)