From 0cbbfa1fe169943f4edaa557a88f475b7ff3e6cb Mon Sep 17 00:00:00 2001 From: Shijie Sheng Date: Mon, 21 Oct 2024 10:52:40 -0700 Subject: [PATCH] [CLI] add unit test to workflow_commands --- idls | 2 +- tools/cli/app_test.go | 309 ++++++++++++++++++++++++++++----- tools/cli/workflow_commands.go | 4 +- 3 files changed, 273 insertions(+), 42 deletions(-) diff --git a/idls b/idls index 279b1f70dfb..55e4ad43798 160000 --- a/idls +++ b/idls @@ -1 +1 @@ -Subproject commit 279b1f70dfb8aa54bc26fa22436eb0d6b93efabc +Subproject commit 55e4ad437989730379baf570f00a11ddcb7d3a75 diff --git a/tools/cli/app_test.go b/tools/cli/app_test.go index 7df4134f4f4..a2a1d397db0 100644 --- a/tools/cli/app_test.go +++ b/tools/cli/app_test.go @@ -21,6 +21,7 @@ package cli import ( + "fmt" "strings" "testing" "time" @@ -40,13 +41,22 @@ import ( "github.com/uber/cadence/common/types" ) -type cliAppSuite struct { - suite.Suite - app *cli.App - mockCtrl *gomock.Controller - serverFrontendClient *frontend.MockClient - serverAdminClient *admin.MockClient -} +type ( + cliAppSuite struct { + suite.Suite + app *cli.App + mockCtrl *gomock.Controller + serverFrontendClient *frontend.MockClient + serverAdminClient *admin.MockClient + } + + testcase struct { + name string + command string + err string + mock func() + } +) var _ ClientFactory = (*clientFactoryMock)(nil) @@ -106,6 +116,22 @@ func (s *cliAppSuite) TearDownTest() { s.mockCtrl.Finish() // assert mock’s expectations } +func (s *cliAppSuite) testcaseHelper(testcases []testcase) { + for _, tt := range testcases { + s.T().Run(tt.name, func(t *testing.T) { + if tt.mock != nil { + tt.mock() + } + err := s.app.Run(strings.Split(tt.command, " ")) + if tt.err != "" { + assert.ErrorContains(t, err, tt.err) + } else { + assert.NoError(t, err) + } + }) + } +} + func (s *cliAppSuite) TestAppCommands() { for _, test := range commands { cmd := s.app.Command(test) @@ -418,13 +444,160 @@ func (s *cliAppSuite) TestSignalWorkflow_Failed() { s.Error(s.app.Run([]string{"", "--do", domainName, "workflow", "signal", "-w", "wid", "-n", "signal-name"})) } +func (s *cliAppSuite) TestDescribeWorkflow() { + s.testcaseHelper([]testcase{ + { + "happy", + "cadence --do test-domain wf describe -w wid", + "", + func() { + resp := &types.DescribeWorkflowExecutionResponse{ + WorkflowExecutionInfo: &types.WorkflowExecutionInfo{ + Execution: &types.WorkflowExecution{ + WorkflowID: "wid", + }, + Type: &types.WorkflowType{ + Name: "workflow-type", + }, + StartTime: common.Int64Ptr(time.Now().UnixNano()), + CloseTime: common.Int64Ptr(time.Now().UnixNano()), + }, + PendingActivities: []*types.PendingActivityInfo{ + {}, + }, + PendingDecision: &types.PendingDecisionInfo{}, + } + s.serverFrontendClient.EXPECT().DescribeWorkflowExecution(gomock.Any(), gomock.Any()).Return(resp, nil) + }, + }, + }) +} + func (s *cliAppSuite) TestQueryWorkflow() { - resp := &types.QueryWorkflowResponse{ - QueryResult: []byte("query-result"), - } - s.serverFrontendClient.EXPECT().QueryWorkflow(gomock.Any(), gomock.Any()).Return(resp, nil) - err := s.app.Run([]string{"", "--do", domainName, "workflow", "query", "-w", "wid", "-qt", "query-type-test"}) - s.Nil(err) + s.testcaseHelper([]testcase{ + { + name: "happy", + command: `cadence --do test-domain wf query -w wid -qt query-type-test`, + err: "", + mock: func () { + resp := &types.QueryWorkflowResponse{ + QueryResult: []byte("query-result"), + } + s.serverFrontendClient.EXPECT().QueryWorkflow(gomock.Any(), gomock.Any()).Return(resp, nil) + }, + }, + { + name: "query with reject not_open", + command: `cadence --do test-domain wf query -w wid -qt query-type-test --query_reject_condition not_open`, + err: "", + mock: func () { + resp := &types.QueryWorkflowResponse{ + QueryResult: []byte("query-result"), + } + s.serverFrontendClient.EXPECT(). + QueryWorkflow(gomock.Any(), &types.QueryWorkflowRequest{ + Domain: "test-domain", + Execution: &types.WorkflowExecution{ + WorkflowID: "wid", + }, + Query: &types.WorkflowQuery{ + QueryType: "query-type-test", + }, + QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), + }). + Return(resp, nil) + }, + }, + { + name: "query with reject not_completed_cleanly", + command: `cadence --do test-domain wf query -w wid -qt query-type-test --query_reject_condition not_completed_cleanly`, + err: "", + mock: func () { + resp := &types.QueryWorkflowResponse{ + QueryResult: []byte("query-result"), + } + s.serverFrontendClient.EXPECT(). + QueryWorkflow(gomock.Any(), &types.QueryWorkflowRequest{ + Domain: "test-domain", + Execution: &types.WorkflowExecution{ + WorkflowID: "wid", + }, + Query: &types.WorkflowQuery{ + QueryType: "query-type-test", + }, + QueryRejectCondition: types.QueryRejectConditionNotCompletedCleanly.Ptr(), + }). + Return(resp, nil) + }, + }, + { + name: "query with unknown reject", + command: `cadence --do test-domain wf query -w wid -qt query-type-test --query_reject_condition unknown`, + err: "invalid reject condition", + }, + { + name: "query with eventual consistency", + command: `cadence --do test-domain wf query -w wid -qt query-type-test --query_consistency_level eventual`, + err: "", + mock: func () { + resp := &types.QueryWorkflowResponse{ + QueryResult: []byte("query-result"), + } + s.serverFrontendClient.EXPECT(). + QueryWorkflow(gomock.Any(), &types.QueryWorkflowRequest{ + Domain: "test-domain", + Execution: &types.WorkflowExecution{ + WorkflowID: "wid", + }, + Query: &types.WorkflowQuery{ + QueryType: "query-type-test", + }, + QueryConsistencyLevel: types.QueryConsistencyLevelEventual.Ptr(), + }). + Return(resp, nil) + }, + }, + { + name: "query with strong consistency", + command: `cadence --do test-domain wf query -w wid -qt query-type-test --query_consistency_level strong`, + err: "", + mock: func () { + resp := &types.QueryWorkflowResponse{ + QueryResult: []byte("query-result"), + } + s.serverFrontendClient.EXPECT(). + QueryWorkflow(gomock.Any(), &types.QueryWorkflowRequest{ + Domain: "test-domain", + Execution: &types.WorkflowExecution{ + WorkflowID: "wid", + }, + Query: &types.WorkflowQuery{ + QueryType: "query-type-test", + }, + QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), + }). + Return(resp, nil) + }, + }, + { + name: "query with invalid consistency", + command: `cadence --do test-domain wf query -w wid -qt query-type-test --query_consistency_level invalid`, + err: "invalid query consistency level", + }, + { + name: "failed", + command: `cadence --do test-domain wf query -w wid -qt query-type-test`, + err: "some error", + mock: func () { + s.serverFrontendClient.EXPECT().QueryWorkflow(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("some error")) + }, + }, + { + name: "missing flags", + command: "cadence wf query", + err: "Required flag not found", + }, + }) } func (s *cliAppSuite) TestQueryWorkflowUsingStackTrace() { @@ -436,14 +609,6 @@ func (s *cliAppSuite) TestQueryWorkflowUsingStackTrace() { s.Nil(err) } -func (s *cliAppSuite) TestQueryWorkflow_Failed() { - resp := &types.QueryWorkflowResponse{ - QueryResult: []byte("query-result"), - } - s.serverFrontendClient.EXPECT().QueryWorkflow(gomock.Any(), gomock.Any()).Return(resp, &types.BadRequestError{"faked error"}) - s.Error(s.app.Run([]string{"", "--do", domainName, "workflow", "query", "-w", "wid", "-qt", "query-type-test"})) -} - var ( closeStatus = types.WorkflowExecutionCloseStatusCompleted @@ -483,6 +648,46 @@ var ( } ) +func (s *cliAppSuite) TestListAllWorkflow() { + s.testcaseHelper([]testcase{ + { + name: "happy", + command: `cadence --do test-domain wf listall`, + mock: func () { + countWorkflowResp := &types.CountWorkflowExecutionsResponse{} + s.serverFrontendClient.EXPECT().CountWorkflowExecutions(gomock.Any(), gomock.Any()).Return(countWorkflowResp, nil) + s.serverFrontendClient.EXPECT().ListClosedWorkflowExecutions(gomock.Any(), gomock.Any()).Return(listClosedWorkflowExecutionsResponse, nil) + }, + }, + }) +} + +func (s *cliAppSuite) TestScanAllWorkflow() { + s.testcaseHelper([]testcase{ + { + name: "happy", + command: `cadence --do test-domain wf scanall`, + mock: func () { + s.serverFrontendClient.EXPECT().ScanWorkflowExecutions(gomock.Any(), gomock.Any()).Return(&types.ListWorkflowExecutionsResponse{}, nil) + }, + }, + }) +} + +func (s *cliAppSuite) TestResetWorkflow() { + s.testcaseHelper([]testcase{ + { + name: "happy", + command: `cadence --do test-domain wf reset -w wid -r rid -reason test-reason --event_id 1`, + err: "", + mock: func () { + resp := &types.ResetWorkflowExecutionResponse{RunID: uuid.New()} + s.serverFrontendClient.EXPECT().ResetWorkflowExecution(gomock.Any(), gomock.Any()).Return(resp, nil) + }, + }, + }) +} + func (s *cliAppSuite) TestListWorkflow() { resp := listClosedWorkflowExecutionsResponse countWorkflowResp := &types.CountWorkflowExecutionsResponse{} @@ -854,31 +1059,55 @@ func (s *cliAppSuite) TestParseBool() { } func (s *cliAppSuite) TestSignalWithStartWorkflowExecution() { - for _, tt := range []struct { - name string - command string - err string - mock func() - }{ + s.testcaseHelper([]testcase{ { name: "happy", - command: "cadence --do test-domain wf signalwithstart -w wid -n signal-name -i input", + command: `cadence --do test-domain wf signalwithstart --et 100 --workflow_type sometype --tasklist tasklist -w wid -n signal-name --signal_input []`, err: "", mock: func () { - s.serverFrontendClient.EXPECT().SignalWithStartWorkflowExecution(gomock.Any(), gomock.Any()).Return(nil) + s.serverFrontendClient.EXPECT().SignalWithStartWorkflowExecution(gomock.Any(), gomock.Any()).Return(&types.StartWorkflowExecutionResponse{}, nil) }, }, - } { - s.T().Run(tt.name, func(t *testing.T) { - tt.mock() - err := s.app.Run(strings.Split(tt.command, " ")) - if tt.err != "" { - assert.ErrorContains(t, err, tt.err) - } else { - assert.NoError(t, err) - } - }) - } + { + name: "failed", + command: `cadence --do test-domain wf signalwithstart --et 100 --workflow_type sometype --tasklist tasklist -w wid -n signal-name --signal_input []`, + err: "some error", + mock: func () { + s.serverFrontendClient.EXPECT().SignalWithStartWorkflowExecution(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("some error")) + }, + }, + { + name: "missing flags", + command: "cadence wf signalwithstart", + err: "Required flag not found", + }, + }) +} + +func (s *cliAppSuite) TestCompleteActivity() { + s.testcaseHelper([]testcase{ + { + name: "happy", + command: `cadence --do test-domain wf activity complete -w wid -r rid -aid 3 -result result --identity tester`, + err: "", + mock: func () { + s.serverFrontendClient.EXPECT().RespondActivityTaskCompletedByID(gomock.Any(), gomock.Any()).Return(nil) + }, + }, + }) +} + +func (s *cliAppSuite) TestFailActivity() { + s.testcaseHelper([]testcase{ + { + name: "happy", + command: `cadence --do test-domain wf activity fail -w wid -r rid -aid 3 --reason somereason --detail somedetail --identity tester`, + err: "", + mock: func () { + s.serverFrontendClient.EXPECT().RespondActivityTaskFailedByID(gomock.Any(), gomock.Any()).Return(nil) + }, + }, + }) } func (s *cliAppSuite) TestConvertStringToRealType() { diff --git a/tools/cli/workflow_commands.go b/tools/cli/workflow_commands.go index 97384d2287f..83cc74f0a13 100644 --- a/tools/cli/workflow_commands.go +++ b/tools/cli/workflow_commands.go @@ -1079,7 +1079,9 @@ func describeWorkflowHelper(c *cli.Context, wid, rid string) error { o = resp } else { o, err = convertDescribeWorkflowExecutionResponse(resp, frontendClient, c) - return commoncli.Problem("WF helper describe failed: ", err) + if err != nil { + return commoncli.Problem("convert describe workflow response failed: ", err) + } } prettyPrintJSONObject(o)