From 1d73ea887d257930c6b3588c9eafdeda9c1d8120 Mon Sep 17 00:00:00 2001 From: lsytj0413 <511121939@qq.com> Date: Sat, 8 Oct 2022 19:34:10 +0800 Subject: [PATCH] feat(*): add event default dataOnly & kind field value Signed-off-by: lsytj0413 <511121939@qq.com> --- model/event.go | 55 ++++++++++++++----------- model/event_test.go | 99 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 24 deletions(-) diff --git a/model/event.go b/model/event.go index 1cc9f6c..8e8bbef 100644 --- a/model/event.go +++ b/model/event.go @@ -23,16 +23,19 @@ import ( validator "github.com/go-playground/validator/v10" ) +// EventKind defines this event as either `consumed` or `produced` +type EventKind string + const ( - // EventKindConsumed ... + // EventKindConsumed means the event continuation of workflow instance execution EventKindConsumed EventKind = "consumed" - // EventKindProduced ... + + // EventKindProduced means the event was created during worflow instance execution EventKindProduced EventKind = "produced" ) func init() { val.GetValidator().RegisterStructValidation(EventStructLevelValidation, Event{}) - val.GetValidator().RegisterStructValidation(EventRefStructLevelValidation, EventRef{}) } // EventStructLevelValidation custom validator for event kind consumed @@ -43,22 +46,7 @@ func EventStructLevelValidation(structLevel validator.StructLevel) { } } -// EventRefStructLevelValidation custom validator for event kind consumed -func EventRefStructLevelValidation(structLevel validator.StructLevel) { - eventRef := structLevel.Current().Interface().(EventRef) - - if len(eventRef.ResultEventTimeout) > 0 { - err := val.ValidateISO8601TimeDuration(eventRef.ResultEventTimeout) - if err != nil { - structLevel.ReportError(reflect.ValueOf(eventRef.ResultEventTimeout), "ResultEventTimeout", "resultEventTimeout", "iso8601duration", "") - } - } -} - -// EventKind ... -type EventKind string - -// Event ... +// Event used to define events and their correlations type Event struct { Common // Unique event name @@ -67,15 +55,34 @@ type Event struct { Source string `json:"source,omitempty"` // CloudEvent type Type string `json:"type" validate:"required"` - // Defines the CloudEvent as either 'consumed' or 'produced' by the workflow. Default is 'consumed' + // Defines the CloudEvent as either 'consumed' or 'produced' by the workflow. + // Defaults to `consumed` Kind EventKind `json:"kind,omitempty"` // If `true`, only the Event payload is accessible to consuming Workflow states. If `false`, both event payload and context attributes should be accessible" + // Defaults to true DataOnly bool `json:"dataOnly,omitempty"` // CloudEvent correlation definitions Correlation []Correlation `json:"correlation,omitempty" validate:"omitempty,dive"` } -// Correlation ... +type eventForUnmarshal Event + +// UnmarshalJSON unmarshal Event object from json bytes +func (e *Event) UnmarshalJSON(data []byte) error { + v := eventForUnmarshal{ + DataOnly: true, + Kind: EventKindConsumed, + } + err := json.Unmarshal(data, &v) + if err != nil { + return err + } + + *e = Event(v) + return nil +} + +// Correlation define event correlation rules for an event. Only used for `consumed` events type Correlation struct { // CloudEvent Extension Context Attribute name ContextAttributeName string `json:"contextAttributeName" validate:"required"` @@ -83,7 +90,7 @@ type Correlation struct { ContextAttributeValue string `json:"contextAttributeValue,omitempty"` } -// EventRef ... +// EventRef defining invocation of a function via event type EventRef struct { // Reference to the unique name of a 'produced' event definition TriggerEventRef string `json:"triggerEventRef" validate:"required"` @@ -91,7 +98,7 @@ type EventRef struct { ResultEventRef string `json:"resultEventRef" validate:"required"` // ResultEventTimeout defines maximum amount of time (ISO 8601 format) to wait for the result event. If not defined it be set to the actionExecutionTimeout - ResultEventTimeout string `json:"resultEventTimeout,omitempty"` + ResultEventTimeout string `json:"resultEventTimeout,omitempty" validate:"omitempty,iso8601duration"` // TODO: create StringOrMap structure // If string type, an expression which selects parts of the states data output to become the data (payload) of the event referenced by 'triggerEventRef'. @@ -114,7 +121,7 @@ func (e *EventRef) UnmarshalJSON(data []byte) error { } err := json.Unmarshal(data, &v) if err != nil { - return nil + return err } *e = EventRef(v) diff --git a/model/event_test.go b/model/event_test.go index dc54109..bb34e08 100644 --- a/model/event_test.go +++ b/model/event_test.go @@ -15,6 +15,7 @@ package model import ( + "encoding/json" "testing" "github.com/stretchr/testify/assert" @@ -65,3 +66,101 @@ func TestEventRefStructLevelValidation(t *testing.T) { }) } } + +func TestEventRefUnmarshalJSON(t *testing.T) { + type testCase struct { + desp string + data string + expect EventRef + err string + } + testCases := []testCase{ + { + desp: "all field", + data: `{"invoke": "async"}`, + expect: EventRef{ + Invoke: InvokeKindAsync, + }, + err: ``, + }, + { + desp: "invoke unset", + data: `{}`, + expect: EventRef{ + Invoke: InvokeKindSync, + }, + err: ``, + }, + { + desp: "invalid json format", + data: `{"invoke": 1}`, + expect: EventRef{}, + err: `json: cannot unmarshal number into Go struct field eventRefForUnmarshal.invoke of type model.InvokeKind`, + }, + } + for _, tc := range testCases { + t.Run(tc.desp, func(t *testing.T) { + var v EventRef + err := json.Unmarshal([]byte(tc.data), &v) + + if tc.err != "" { + assert.Error(t, err) + assert.Regexp(t, tc.err, err) + return + } + + assert.NoError(t, err) + assert.Equal(t, tc.expect, v) + }) + } +} + +func TestEventUnmarshalJSON(t *testing.T) { + type testCase struct { + desp string + data string + expect Event + err string + } + testCases := []testCase{ + { + desp: "all field", + data: `{"dataOnly": false, "kind": "produced"}`, + expect: Event{ + DataOnly: false, + Kind: EventKindProduced, + }, + err: ``, + }, + { + desp: "optional field dataOnly & kind unset", + data: `{}`, + expect: Event{ + DataOnly: true, + Kind: EventKindConsumed, + }, + err: ``, + }, + { + desp: "invalid json format", + data: `{"dataOnly": "false", "kind": "produced"}`, + expect: Event{}, + err: `json: cannot unmarshal string into Go struct field eventForUnmarshal.dataOnly of type bool`, + }, + } + for _, tc := range testCases { + t.Run(tc.desp, func(t *testing.T) { + var v Event + err := json.Unmarshal([]byte(tc.data), &v) + + if tc.err != "" { + assert.Error(t, err) + assert.Regexp(t, tc.err, err) + return + } + + assert.NoError(t, err) + assert.Equal(t, tc.expect, v) + }) + } +}