Skip to content

Commit d76e8d0

Browse files
Unmarshal state.end when boolean (#155)
* Unmarshal state.end when boolean Signed-off-by: André R. de Miranda <andre@galgo.tech> * Change unit test end to boolean Signed-off-by: André R. de Miranda <andre@galgo.tech> * Add function primitiveOrMapType and used in End.Unmarshal Signed-off-by: André R. de Miranda <andre@galgo.tech> * Unmarshal Workflow.End direct without using a map Signed-off-by: André R. de Miranda <andre@galgo.tech> --------- Signed-off-by: André R. de Miranda <andre@galgo.tech>
1 parent 8790952 commit d76e8d0

File tree

5 files changed

+146
-24
lines changed

5 files changed

+146
-24
lines changed

model/util.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ func requiresNotNilOrEmpty(value interface{}) string {
8585
return value.(string)
8686
}
8787

88+
// TODO: check the places that use unmarshalString if the case changes for primitiveOrStruct.
8889
func unmarshalString(data []byte) (string, error) {
8990
var value string
9091
if err := json.Unmarshal(data, &value); err != nil {
@@ -93,6 +94,15 @@ func unmarshalString(data []byte) (string, error) {
9394
return value, nil
9495
}
9596

97+
func primitiveOrStruct[T any, U any](data []byte) (valStruct *U, valPrimitive T, err error) {
98+
if data[0] == '{' {
99+
err = json.Unmarshal(data, &valStruct)
100+
} else {
101+
err = json.Unmarshal(data, &valPrimitive)
102+
}
103+
return
104+
}
105+
96106
func unmarshalKey(key string, data map[string]json.RawMessage, output interface{}) error {
97107
if _, found := data[key]; found {
98108
if err := json.Unmarshal(data[key], output); err != nil {

model/util_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package model
1616

1717
import (
18+
"encoding/json"
1819
"testing"
1920

2021
"github.com/stretchr/testify/assert"
@@ -33,3 +34,48 @@ func TestIncludePaths(t *testing.T) {
3334
SetIncludePaths([]string{"1"})
3435
}))
3536
}
37+
38+
func Test_primitiveOrMapType(t *testing.T) {
39+
type dataMap map[string]json.RawMessage
40+
data := []byte(`"value":true`)
41+
_, _, err := primitiveOrStruct[bool, dataMap](data)
42+
assert.Error(t, err)
43+
44+
data = []byte(`{value":true}`)
45+
_, _, err = primitiveOrStruct[bool, dataMap](data)
46+
assert.Error(t, err)
47+
48+
data = []byte(`value":true}`)
49+
_, _, err = primitiveOrStruct[bool, dataMap](data)
50+
assert.Error(t, err)
51+
52+
data = []byte(`"true"`)
53+
_, _, err = primitiveOrStruct[bool, dataMap](data)
54+
assert.Error(t, err)
55+
56+
data = []byte(`true`)
57+
valMap, valBool, err := primitiveOrStruct[bool, dataMap](data)
58+
assert.NoError(t, err)
59+
assert.Nil(t, valMap)
60+
assert.True(t, valBool)
61+
62+
data = []byte(`"true"`)
63+
valMap, valString, err := primitiveOrStruct[string, dataMap](data)
64+
assert.NoError(t, err)
65+
assert.Nil(t, valMap)
66+
assert.Equal(t, `true`, valString)
67+
68+
data = []byte(`{"value":true}`)
69+
valMap, valBool, err = primitiveOrStruct[bool, dataMap](data)
70+
assert.NoError(t, err)
71+
assert.NotNil(t, valMap)
72+
assert.Equal(t, valMap, &dataMap{"value": []byte("true")})
73+
assert.False(t, valBool)
74+
75+
data = []byte(`{"value": "true"}`)
76+
valMap, valBool, err = primitiveOrStruct[bool, dataMap](data)
77+
assert.NoError(t, err)
78+
assert.NotNil(t, valMap)
79+
assert.Equal(t, valMap, &dataMap{"value": []byte(`"true"`)})
80+
assert.False(t, valBool)
81+
}

model/workflow.go

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -508,25 +508,17 @@ type End struct {
508508

509509
// UnmarshalJSON ...
510510
func (e *End) UnmarshalJSON(data []byte) error {
511-
512-
endMap := make(map[string]json.RawMessage)
513-
if err := json.Unmarshal(data, &endMap); err != nil {
514-
e.Terminate = false
515-
e.Compensate = false
516-
return nil
517-
}
518-
519-
if err := unmarshalKey("compensate", endMap, &e.Compensate); err != nil {
520-
return err
521-
}
522-
if err := unmarshalKey("terminate", endMap, &e.Terminate); err != nil {
523-
return err
524-
}
525-
if err := unmarshalKey("produceEvents", endMap, &e.ProduceEvents); err != nil {
511+
type endUnmarshal End
512+
end, endBool, err := primitiveOrStruct[bool, endUnmarshal](data)
513+
if err != nil {
526514
return err
527515
}
528-
if err := unmarshalKey("continueAs", endMap, &e.ContinueAs); err != nil {
529-
return err
516+
517+
if end == nil {
518+
e.Terminate = endBool
519+
e.Compensate = false
520+
} else {
521+
*e = End(*end)
530522
}
531523

532524
return nil

model/workflow_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,57 @@ func TestContinueAsUnmarshalJSON(t *testing.T) {
148148
})
149149
}
150150
}
151+
152+
func TestEndUnmarshalJSON(t *testing.T) {
153+
type testCase struct {
154+
desp string
155+
data string
156+
expect End
157+
err string
158+
}
159+
testCases := []testCase{
160+
{
161+
desp: "bool success",
162+
data: `true`,
163+
expect: End{
164+
Terminate: true,
165+
},
166+
err: ``,
167+
},
168+
{
169+
desp: "string fail",
170+
data: `"true"`,
171+
expect: End{},
172+
err: `json: cannot unmarshal string into Go value of type bool`,
173+
},
174+
{
175+
desp: `object success`,
176+
data: `{"terminate": true}`,
177+
expect: End{
178+
Terminate: true,
179+
},
180+
err: ``,
181+
},
182+
{
183+
desp: `object key invalid`,
184+
data: `{"terminate_parameter_invalid": true}`,
185+
expect: End{},
186+
err: ``,
187+
},
188+
}
189+
for _, tc := range testCases {
190+
t.Run(tc.desp, func(t *testing.T) {
191+
var v End
192+
err := json.Unmarshal([]byte(tc.data), &v)
193+
194+
if tc.err != "" {
195+
assert.Error(t, err)
196+
assert.Regexp(t, tc.err, err)
197+
return
198+
}
199+
200+
assert.NoError(t, err)
201+
assert.Equal(t, tc.expect, v)
202+
})
203+
}
204+
}

parser/parser_test.go

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ func TestFromFile(t *testing.T) {
7373
assert.Equal(t, "greeting", w.ID)
7474
assert.IsType(t, &model.OperationState{}, w.States[0].OperationState)
7575
assert.Equal(t, "greetingFunction", w.States[0].OperationState.Actions[0].FunctionRef.RefName)
76+
assert.NotNil(t, w.States[0].End)
77+
assert.True(t, w.States[0].End.Terminate)
7678
},
7779
}, {
7880
"./testdata/workflows/actiondata-defaultvalue.yaml",
@@ -82,6 +84,8 @@ func TestFromFile(t *testing.T) {
8284
assert.NotNil(t, w.States[0].OperationState)
8385
assert.Equal(t, true, w.States[0].OperationState.Actions[0].ActionDataFilter.UseResults)
8486
assert.Equal(t, "greeting", w.States[0].OperationState.Actions[0].Name)
87+
assert.NotNil(t, w.States[0].End)
88+
assert.True(t, w.States[0].End.Terminate)
8589
},
8690
}, {
8791
"./testdata/workflows/greetings.sw.yaml",
@@ -93,6 +97,7 @@ func TestFromFile(t *testing.T) {
9397
assert.NotEmpty(t, w.States[0].OperationState.Actions)
9498
assert.NotNil(t, w.States[0].OperationState.Actions[0].FunctionRef)
9599
assert.Equal(t, "greetingFunction", w.States[0].OperationState.Actions[0].FunctionRef.RefName)
100+
assert.True(t, w.States[0].End.Terminate)
96101
},
97102
}, {
98103
"./testdata/workflows/eventbaseddataandswitch.sw.json",
@@ -105,11 +110,16 @@ func TestFromFile(t *testing.T) {
105110
assert.NotNil(t, w.States[1])
106111
assert.NotNil(t, w.States[1].SwitchState)
107112
assert.Equal(t, "PT1H", w.States[1].SwitchState.Timeouts.EventTimeout)
113+
assert.Nil(t, w.States[1].End)
114+
assert.NotNil(t, w.States[2].End)
115+
assert.True(t, w.States[2].End.Terminate)
108116
},
109117
}, {
110118
"./testdata/workflows/conditionbasedstate.yaml", func(t *testing.T, w *model.Workflow) {
111119
operationState := w.States[0].OperationState
112120
assert.Equal(t, "${ .applicants | .age < 18 }", operationState.Actions[0].Condition)
121+
assert.NotNil(t, w.States[0].End)
122+
assert.True(t, w.States[0].End.Terminate)
113123
},
114124
}, {
115125
"./testdata/workflows/eventbasedgreeting.sw.json", func(t *testing.T, w *model.Workflow) {
@@ -121,6 +131,8 @@ func TestFromFile(t *testing.T) {
121131
assert.NotEmpty(t, eventState.OnEvents)
122132
assert.Equal(t, "GreetingEvent", eventState.OnEvents[0].EventRefs[0])
123133
assert.Equal(t, true, eventState.Exclusive)
134+
assert.NotNil(t, w.States[0].End)
135+
assert.True(t, w.States[0].End.Terminate)
124136
},
125137
}, {
126138
"./testdata/workflows/eventbasedgreetingexclusive.sw.json", func(t *testing.T, w *model.Workflow) {
@@ -277,7 +289,9 @@ func TestFromFile(t *testing.T) {
277289
assert.Equal(t, "0 0/15 * * * ?", w.Start.Schedule.Cron.Expression)
278290
assert.Equal(t, "checkInboxFunction", w.States[0].OperationState.Actions[0].FunctionRef.RefName)
279291
assert.Equal(t, "SendTextForHighPriority", w.States[0].Transition.NextState)
280-
assert.False(t, w.States[1].End.Terminate)
292+
assert.Nil(t, w.States[0].End)
293+
assert.NotNil(t, w.States[1].End)
294+
assert.True(t, w.States[1].End.Terminate)
281295
},
282296
}, {
283297
"./testdata/workflows/applicationrequest-issue16.sw.yaml", func(t *testing.T, w *model.Workflow) {
@@ -553,7 +567,6 @@ func TestFromFile(t *testing.T) {
553567
file.name, func(t *testing.T) {
554568
workflow, err := FromFile(file.name)
555569
if assert.NoError(t, err, "Test File %s", file.name) {
556-
557570
assert.NotNil(t, workflow, "Test File %s", file.name)
558571
file.f(t, workflow)
559572
}
@@ -623,17 +636,24 @@ states:
623636
"data": {
624637
"result": "Hello World!"
625638
},
626-
"end": true
627-
}
639+
"transition": "Next Hello State"
640+
},
641+
{
642+
"name": "Next Hello State",
643+
"type": "inject",
644+
"data": {
645+
"result": "Next Hello World!"
646+
},
647+
"end": true
648+
}
628649
]
629650
}
630651
`))
631652
assert.Nil(t, err)
632653
assert.NotNil(t, workflow.Auth)
633654

634-
// TODO correctly marshall end: true (fixed by https://github.com/serverlessworkflow/sdk-go/pull/147)
635655
b, _ := json.Marshal(workflow)
636-
assert.Equal(t, "{\"id\":\"applicantrequest\",\"name\":\"Applicant Request Decision Workflow\",\"description\":\"Determine if applicant request is valid\",\"version\":\"1.0\",\"start\":{\"stateName\":\"CheckApplication\"},\"specVersion\":\"0.8\",\"expressionLang\":\"jq\",\"auth\":[{\"name\":\"testAuth\",\"scheme\":\"bearer\",\"properties\":{\"token\":\"test_token\"}},{\"name\":\"testAuth2\",\"scheme\":\"basic\",\"properties\":{\"username\":\"test_user\",\"password\":\"test_pwd\"}}],\"states\":[{\"name\":\"Hello State\",\"type\":\"inject\",\"end\":{},\"data\":{\"result\":\"Hello World!\"}}]}",
656+
assert.Equal(t, "{\"id\":\"applicantrequest\",\"name\":\"Applicant Request Decision Workflow\",\"description\":\"Determine if applicant request is valid\",\"version\":\"1.0\",\"start\":{\"stateName\":\"CheckApplication\"},\"specVersion\":\"0.8\",\"expressionLang\":\"jq\",\"auth\":[{\"name\":\"testAuth\",\"scheme\":\"bearer\",\"properties\":{\"token\":\"test_token\"}},{\"name\":\"testAuth2\",\"scheme\":\"basic\",\"properties\":{\"username\":\"test_user\",\"password\":\"test_pwd\"}}],\"states\":[{\"name\":\"Hello State\",\"type\":\"inject\",\"transition\":{\"nextState\":\"Next Hello State\"},\"data\":{\"result\":\"Hello World!\"}},{\"name\":\"Next Hello State\",\"type\":\"inject\",\"end\":{\"terminate\":true},\"data\":{\"result\":\"Next Hello World!\"}}]}",
637657
string(b))
638658

639659
})
@@ -664,7 +684,7 @@ states:
664684
assert.NotNil(t, workflow.Auth)
665685

666686
b, _ := json.Marshal(workflow)
667-
assert.Equal(t, "{\"id\":\"applicantrequest\",\"name\":\"Applicant Request Decision Workflow\",\"description\":\"Determine if applicant request is valid\",\"version\":\"1.0\",\"start\":{\"stateName\":\"CheckApplication\"},\"specVersion\":\"0.8\",\"expressionLang\":\"jq\",\"auth\":[{\"name\":\"testAuth\",\"scheme\":\"bearer\",\"properties\":{\"token\":\"test_token\"}},{\"name\":\"testAuth2\",\"scheme\":\"basic\",\"properties\":{\"username\":\"test_user\",\"password\":\"test_pwd\"}}],\"states\":[{\"name\":\"Hello State\",\"type\":\"inject\",\"end\":{},\"data\":{\"result\":\"Hello World!\"}}]}",
687+
assert.Equal(t, "{\"id\":\"applicantrequest\",\"name\":\"Applicant Request Decision Workflow\",\"description\":\"Determine if applicant request is valid\",\"version\":\"1.0\",\"start\":{\"stateName\":\"CheckApplication\"},\"specVersion\":\"0.8\",\"expressionLang\":\"jq\",\"auth\":[{\"name\":\"testAuth\",\"scheme\":\"bearer\",\"properties\":{\"token\":\"test_token\"}},{\"name\":\"testAuth2\",\"scheme\":\"basic\",\"properties\":{\"username\":\"test_user\",\"password\":\"test_pwd\"}}],\"states\":[{\"name\":\"Hello State\",\"type\":\"inject\",\"end\":{\"terminate\":true},\"data\":{\"result\":\"Hello World!\"}}]}",
668688
string(b))
669689

670690
})

0 commit comments

Comments
 (0)