Skip to content

Commit 36e5a27

Browse files
ktropsKatie Atrops
and
Katie Atrops
authored
iwf-401: update activity type name to find reset history eventID (#515)
Co-authored-by: Katie Atrops <[email protected]>
1 parent 8fffb80 commit 36e5a27

File tree

4 files changed

+292
-2
lines changed

4 files changed

+292
-2
lines changed

integ/reset_by_state_id_test.go

+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package integ
2+
3+
import (
4+
"context"
5+
"github.com/indeedeng/iwf/gen/iwfidl"
6+
"github.com/indeedeng/iwf/integ/workflow/reset"
7+
"github.com/indeedeng/iwf/service"
8+
"github.com/indeedeng/iwf/service/common/ptr"
9+
"github.com/stretchr/testify/assert"
10+
"strconv"
11+
"testing"
12+
"time"
13+
)
14+
15+
func TestResetByStateIdWorkflowTemporal(t *testing.T) {
16+
if !*temporalIntegTest {
17+
t.Skip()
18+
}
19+
for i := 0; i < *repeatIntegTest; i++ {
20+
doTestResetByStatIdWorkflow(t, service.BackendTypeTemporal, nil)
21+
smallWaitForFastTest()
22+
23+
//TODO: uncomment below when IWF-403 implementation is done.
24+
//TODO cont.: Reset with state id & state execution id is broken for local activities.
25+
//doTestResetByStatIdWorkflow(t, service.BackendTypeTemporal, minimumContinueAsNewConfig(true))
26+
//smallWaitForFastTest()
27+
}
28+
}
29+
30+
func TestResetByStateIdWorkflowCadence(t *testing.T) {
31+
if !*cadenceIntegTest {
32+
t.Skip()
33+
}
34+
for i := 0; i < *repeatIntegTest; i++ {
35+
doTestResetByStatIdWorkflow(t, service.BackendTypeCadence, nil)
36+
smallWaitForFastTest()
37+
38+
//TODO: uncomment below when IWF-403 implementation is done.
39+
//TODO cont.: Reset with state id & state execution id is broken for local activities.
40+
//doTestResetByStatIdWorkflow(t, service.BackendTypeCadence, minimumContinueAsNewConfig(false))
41+
//smallWaitForFastTest()
42+
}
43+
}
44+
45+
func doTestResetByStatIdWorkflow(t *testing.T, backendType service.BackendType, config *iwfidl.WorkflowConfig) {
46+
// start test workflow server
47+
wfHandler := reset.NewHandler()
48+
closeFunc1 := startWorkflowWorker(wfHandler)
49+
defer closeFunc1()
50+
51+
_, closeFunc2 := startIwfServiceByConfig(IwfServiceTestConfig{
52+
BackendType: backendType,
53+
})
54+
defer closeFunc2()
55+
56+
// start a workflow
57+
apiClient := iwfidl.NewAPIClient(&iwfidl.Configuration{
58+
Servers: []iwfidl.ServerConfiguration{
59+
{
60+
URL: "http://localhost:" + testIwfServerPort,
61+
},
62+
},
63+
})
64+
wfId := reset.WorkflowType + strconv.Itoa(int(time.Now().UnixNano()))
65+
wfInput := &iwfidl.EncodedObject{
66+
Encoding: iwfidl.PtrString("json"),
67+
Data: iwfidl.PtrString("1"),
68+
}
69+
req := apiClient.DefaultApi.ApiV1WorkflowStartPost(context.Background())
70+
startReq := iwfidl.WorkflowStartRequest{
71+
WorkflowId: wfId,
72+
IwfWorkflowType: reset.WorkflowType,
73+
WorkflowTimeoutSeconds: 100,
74+
IwfWorkerUrl: "http://localhost:" + testWorkflowServerPort,
75+
StartStateId: ptr.Any(reset.State1),
76+
StateInput: wfInput,
77+
WorkflowStartOptions: &iwfidl.WorkflowStartOptions{
78+
WorkflowConfigOverride: config,
79+
WorkflowIDReusePolicy: ptr.Any(iwfidl.REJECT_DUPLICATE),
80+
},
81+
StateOptions: &iwfidl.WorkflowStateOptions{
82+
//Skipping wait until for state1
83+
SkipWaitUntil: iwfidl.PtrBool(true),
84+
},
85+
}
86+
startResp, httpResp, err := req.WorkflowStartRequest(startReq).Execute()
87+
panicAtHttpError(err, httpResp)
88+
89+
assertions := assert.New(t)
90+
91+
req2 := apiClient.DefaultApi.ApiV1WorkflowGetWithWaitPost(context.Background())
92+
resp2, httpResp, err := req2.WorkflowGetRequest(iwfidl.WorkflowGetRequest{
93+
WorkflowId: wfId,
94+
}).Execute()
95+
panicAtHttpError(err, httpResp)
96+
97+
history, _ := wfHandler.GetTestResult()
98+
//expect no starts in history as WaitUntil api is skipped.
99+
assertions.Equalf(map[string]int64{
100+
"S1_decide": 1,
101+
"S2_decide": 5,
102+
}, history, "reset test fail, %v", history)
103+
104+
assertions.Equal(iwfidl.COMPLETED, resp2.GetWorkflowStatus())
105+
assertions.Equal(1, len(resp2.GetResults()))
106+
assertions.Equal("S2", resp2.GetResults()[0].CompletedStateId)
107+
assertions.Equal("S2-5", resp2.GetResults()[0].CompletedStateExecutionId)
108+
assertions.Equal("5", resp2.GetResults()[0].CompletedStateOutput.GetData())
109+
110+
//reset workflow by state id
111+
resetReq := apiClient.DefaultApi.ApiV1WorkflowResetPost(context.Background())
112+
_, httpResp, err = resetReq.WorkflowResetRequest(iwfidl.WorkflowResetRequest{
113+
WorkflowRunId: iwfidl.PtrString(startResp.GetWorkflowRunId()),
114+
WorkflowId: wfId,
115+
ResetType: iwfidl.STATE_ID,
116+
StateId: iwfidl.PtrString(reset.State2),
117+
}).Execute()
118+
panicAtHttpError(err, httpResp)
119+
120+
req3 := apiClient.DefaultApi.ApiV1WorkflowGetWithWaitPost(context.Background())
121+
resp3, httpResp, err := req3.WorkflowGetRequest(iwfidl.WorkflowGetRequest{
122+
WorkflowId: wfId,
123+
}).Execute()
124+
panicAtHttpError(err, httpResp)
125+
126+
resetHistory, _ := wfHandler.GetTestResult()
127+
//expect no starts in history as WaitUntil api is skipped.
128+
assertions.Equalf(map[string]int64{
129+
"S1_decide": 1,
130+
"S2_decide": 10,
131+
}, resetHistory, "reset test fail, %v", resetHistory)
132+
133+
assertions.Equal(iwfidl.COMPLETED, resp3.GetWorkflowStatus())
134+
assertions.Equal(1, len(resp3.GetResults()))
135+
assertions.Equal("S2", resp3.GetResults()[0].CompletedStateId)
136+
assertions.Equal("S2-5", resp3.GetResults()[0].CompletedStateExecutionId)
137+
assertions.Equal("5", resp3.GetResults()[0].CompletedStateOutput.GetData())
138+
139+
//reset workflow by state execution id
140+
reset2Req := apiClient.DefaultApi.ApiV1WorkflowResetPost(context.Background())
141+
_, httpResp, err = reset2Req.WorkflowResetRequest(iwfidl.WorkflowResetRequest{
142+
WorkflowRunId: iwfidl.PtrString(startResp.GetWorkflowRunId()),
143+
WorkflowId: wfId,
144+
ResetType: iwfidl.STATE_EXECUTION_ID,
145+
StateExecutionId: iwfidl.PtrString(reset.State2 + "-4"),
146+
}).Execute()
147+
panicAtHttpError(err, httpResp)
148+
149+
req4 := apiClient.DefaultApi.ApiV1WorkflowGetWithWaitPost(context.Background())
150+
resp4, httpResp, err := req4.WorkflowGetRequest(iwfidl.WorkflowGetRequest{
151+
WorkflowId: wfId,
152+
}).Execute()
153+
panicAtHttpError(err, httpResp)
154+
155+
reset2History, _ := wfHandler.GetTestResult()
156+
//expect no starts in history as WaitUntil api is skipped.
157+
assertions.Equalf(map[string]int64{
158+
"S1_decide": 1,
159+
"S2_decide": 12,
160+
}, reset2History, "reset test fail, %v", reset2History)
161+
162+
assertions.Equal(iwfidl.COMPLETED, resp4.GetWorkflowStatus())
163+
assertions.Equal(1, len(resp4.GetResults()))
164+
assertions.Equal("S2", resp4.GetResults()[0].CompletedStateId)
165+
assertions.Equal("S2-5", resp4.GetResults()[0].CompletedStateExecutionId)
166+
assertions.Equal("5", resp4.GetResults()[0].CompletedStateOutput.GetData())
167+
}

integ/workflow/reset/routers.go

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package reset
2+
3+
import (
4+
"fmt"
5+
"github.com/gin-gonic/gin"
6+
"github.com/indeedeng/iwf/gen/iwfidl"
7+
"github.com/indeedeng/iwf/service"
8+
"log"
9+
"net/http"
10+
"strconv"
11+
)
12+
13+
/**
14+
* This test workflow has 2 states, using REST controller to implement the workflow directly.
15+
* State1:
16+
* - No WaitUntil
17+
* - Execute moves to State2
18+
* State2:
19+
* - No WaitUntil
20+
* - Execute loops through state2 5 times, then gracefully completes the workflow.
21+
* This test is used for testing reset by state id and state execution id without WaitUntil
22+
*/
23+
const (
24+
WorkflowType = "reset"
25+
State1 = "S1"
26+
State2 = "S2"
27+
)
28+
29+
type handler struct {
30+
invokeHistory map[string]int64
31+
}
32+
33+
func NewHandler() *handler {
34+
return &handler{
35+
invokeHistory: make(map[string]int64),
36+
}
37+
}
38+
39+
// ApiV1WorkflowStartPost - for a workflow
40+
func (h *handler) ApiV1WorkflowStateStart(c *gin.Context) {
41+
panic("No start call is expected.")
42+
}
43+
44+
func (h *handler) ApiV1WorkflowStateDecide(c *gin.Context) {
45+
log.Println("start of decide")
46+
var req iwfidl.WorkflowStateDecideRequest
47+
if err := c.ShouldBindJSON(&req); err != nil {
48+
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
49+
return
50+
}
51+
log.Println("received state decide request, ", req)
52+
context := req.GetContext()
53+
if context.GetAttempt() <= 0 || context.GetFirstAttemptTimestamp() <= 0 {
54+
panic("attempt and firstAttemptTimestamp should be greater than zero")
55+
}
56+
57+
if req.GetWorkflowType() == WorkflowType {
58+
h.invokeHistory[req.GetWorkflowStateId()+"_decide"]++
59+
if req.GetWorkflowStateId() == State1 {
60+
// go to S2
61+
c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{
62+
StateDecision: &iwfidl.StateDecision{
63+
NextStates: []iwfidl.StateMovement{
64+
{
65+
StateId: State2,
66+
StateInput: req.StateInput,
67+
StateOptions: &iwfidl.WorkflowStateOptions{
68+
//Skipping wait until for 1st execution of state2
69+
SkipWaitUntil: iwfidl.PtrBool(true),
70+
},
71+
},
72+
},
73+
},
74+
})
75+
return
76+
} else if req.GetWorkflowStateId() == State2 {
77+
input := req.GetStateInput()
78+
i, _ := strconv.Atoi(input.GetData())
79+
if i < 5 {
80+
updatedInput := &iwfidl.EncodedObject{
81+
Encoding: iwfidl.PtrString("json"),
82+
Data: iwfidl.PtrString(fmt.Sprintf("%v", i+1)),
83+
}
84+
c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{
85+
StateDecision: &iwfidl.StateDecision{
86+
NextStates: []iwfidl.StateMovement{
87+
{
88+
StateId: State2,
89+
StateInput: updatedInput,
90+
StateOptions: &iwfidl.WorkflowStateOptions{
91+
//Skipping wait until for all executions of state2 after the 1st execution.
92+
SkipWaitUntil: iwfidl.PtrBool(true),
93+
},
94+
},
95+
},
96+
},
97+
})
98+
return
99+
} else {
100+
// go to complete
101+
c.JSON(http.StatusOK, iwfidl.WorkflowStateDecideResponse{
102+
StateDecision: &iwfidl.StateDecision{
103+
NextStates: []iwfidl.StateMovement{
104+
{
105+
StateId: service.GracefulCompletingWorkflowStateId,
106+
StateInput: req.StateInput,
107+
},
108+
},
109+
},
110+
})
111+
return
112+
}
113+
}
114+
}
115+
116+
c.JSON(http.StatusBadRequest, struct{}{})
117+
}
118+
119+
func (h *handler) GetTestResult() (map[string]int64, map[string]interface{}) {
120+
return h.invokeHistory, nil
121+
}

service/client/cadence/reset.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,10 @@ func getDecisionEventIDByStateOrStateExecutionId(
167167
if e.GetEventType() == shared.EventTypeDecisionTaskCompleted {
168168
decisionFinishID = e.GetEventId()
169169
}
170+
//TODO: Add check for local activity. (IWF-403)
170171
if e.GetEventType() == shared.EventTypeActivityTaskScheduled {
171172
typeName := e.GetActivityTaskScheduledEventAttributes().GetActivityType().GetName()
172-
if strings.Contains(typeName, "StateStart") || strings.Contains(typeName, "StateApiWaitUntil") {
173+
if strings.Contains(typeName, "StateApiExecute") || strings.Contains(typeName, "StateApiWaitUntil") {
173174
var backendType service.BackendType
174175
var input service.StateStartActivityInput
175176
err = converter.FromData(e.GetActivityTaskScheduledEventAttributes().Input, &backendType, &input)

service/client/temporal/reset.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,10 @@ func getDecisionEventIDByStateOrStateExecutionId(
162162
if e.GetEventType() == enums.EVENT_TYPE_WORKFLOW_TASK_COMPLETED {
163163
decisionFinishID = e.GetEventId()
164164
}
165+
//TODO: Add check for local activity. (IWF-403)
165166
if e.GetEventType() == enums.EVENT_TYPE_ACTIVITY_TASK_SCHEDULED {
166167
typeName := e.GetActivityTaskScheduledEventAttributes().GetActivityType().GetName()
167-
if strings.Contains(typeName, "StateStart") || strings.Contains(typeName, "StateApiWaitUntil") {
168+
if strings.Contains(typeName, "StateApiExecute") || strings.Contains(typeName, "StateApiWaitUntil") {
168169
var backendType service.BackendType
169170
var input service.StateStartActivityInput
170171
err = converter.FromPayloads(e.GetActivityTaskScheduledEventAttributes().Input, &backendType, &input)

0 commit comments

Comments
 (0)