Skip to content

Commit

Permalink
add more tests inside of fixExecution
Browse files Browse the repository at this point in the history
  • Loading branch information
bowenxia committed Oct 30, 2024
1 parent 32917ca commit 4bdd1b6
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 96 deletions.
2 changes: 1 addition & 1 deletion tools/cli/admin_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ func AdminDeleteWorkflow(c *cli.Context) error {
if err != nil {
return commoncli.Problem("Error in Admin delete WF: ", err)
}
exeStore, err := getDeps(c).initializeExecutionStore(c, shardIDInt)
exeStore, err := getDeps(c).initializeExecutionManager(c, shardIDInt)
if err != nil {
return commoncli.Problem("Error in Admin delete WF: ", err)
}
Expand Down
14 changes: 7 additions & 7 deletions tools/cli/admin_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ const (
)

type cliTestData struct {
mockFrontendClient *frontend.MockClient
mockAdminClient *admin.MockClient
ioHandler *testIOHandler
app *cli.App
mockPersistenceManagerFactory *MockPersistenceManagerFactory
mockFrontendClient *frontend.MockClient
mockAdminClient *admin.MockClient
ioHandler *testIOHandler
app *cli.App
mockManagerFactory *MockManagerFactory
}

func newCLITestData(t *testing.T) *cliTestData {
Expand All @@ -61,7 +61,7 @@ func newCLITestData(t *testing.T) *cliTestData {

td.mockFrontendClient = frontend.NewMockClient(ctrl)
td.mockAdminClient = admin.NewMockClient(ctrl)
td.mockPersistenceManagerFactory = NewMockPersistenceManagerFactory(ctrl)
td.mockManagerFactory = NewMockManagerFactory(ctrl)
td.ioHandler = &testIOHandler{}

// Create a new CLI app with client factory and persistence manager factory
Expand All @@ -71,7 +71,7 @@ func newCLITestData(t *testing.T) *cliTestData {
serverAdminClient: td.mockAdminClient,
},
WithIOHandler(td.ioHandler),
WithPersistenceManagerFactory(td.mockPersistenceManagerFactory), // Inject the mocked persistence manager factory
WithPersistenceManagerFactory(td.mockManagerFactory), // Inject the mocked persistence manager factory
)
return &td
}
Expand Down
18 changes: 12 additions & 6 deletions tools/cli/admin_db_clean_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ func AdminDBClean(c *cli.Context) error {
continue
}

fmt.Println(string(data))
output := getDeps(c).Output()
output.Write([]byte(string(data) + "\n"))
}
return nil
}
Expand All @@ -131,19 +132,19 @@ func fixExecution(
invariants []executions.InvariantFactory,
execution *store.ScanOutputEntity,
) (invariant.ManagerFixResult, error) {
execManager, err := getDeps(c).initializeExecutionStore(c, execution.Execution.(entity.Entity).GetShardID())
execManager, err := getDeps(c).initializeExecutionManager(c, execution.Execution.(entity.Entity).GetShardID())
if execManager != nil {
defer execManager.Close()
}
if err != nil {
return invariant.ManagerFixResult{}, fmt.Errorf("Error in fix execution: %w", err)
return invariant.ManagerFixResult{}, err
}
historyV2Mgr, err := getDeps(c).initializeHistoryManager(c)
if historyV2Mgr != nil {
defer historyV2Mgr.Close()
}
if err != nil {
return invariant.ManagerFixResult{}, fmt.Errorf("Error in fix execution: %w", err)
return invariant.ManagerFixResult{}, err
}
pr := persistence.NewPersistenceRetryer(
execManager,
Expand All @@ -160,7 +161,12 @@ func fixExecution(
ctx, cancel, err := newContext(c)
defer cancel()
if err != nil {
return invariant.ManagerFixResult{}, fmt.Errorf("Context not created: %w", err)
return invariant.ManagerFixResult{}, err
}
return invariant.NewInvariantManager(ivs).RunFixes(ctx, execution.Execution), nil
invariantManager, err := getDeps(c).initializeInvariantManager(ivs)
if err != nil {
return invariant.ManagerFixResult{}, err
}

return invariantManager.RunFixes(ctx, execution.Execution.(entity.Entity)), nil
}
151 changes: 116 additions & 35 deletions tools/cli/admin_db_clean_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,46 @@ package cli

import (
"flag"
"github.com/golang/mock/gomock"
"github.com/uber/cadence/common/persistence"
"github.com/uber/cadence/common/reconciliation/invariant"
"github.com/uber/cadence/common/types"
"fmt"
"os"
"testing"

"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/urfave/cli/v2"

"github.com/uber/cadence/common/persistence"
"github.com/uber/cadence/common/reconciliation/invariant"
)

func TestAdminDBClean_errorCases(t *testing.T) {
func TestAdminDBClean_noFixExecution(t *testing.T) {
tests := []struct {
name string
setupContext func(app *cli.App) *cli.Context
inputFileData string // Simulate the content of the input file
expectedOutput string
expectedError string
}{
{
name: "SuccessCase_emptyResult",
setupContext: func(app *cli.App) *cli.Context {
set := flag.NewFlagSet("test", 0)
// Define flags
set.String(FlagScanType, "", "scan type flag")
set.String(FlagInputFile, "", "Input file flag")
// Use a StringSliceFlag to simulate multiple collection values
set.Var(cli.NewStringSlice("CollectionHistory", "CollectionDomain"), FlagInvariantCollection, "invariant collection flag")

// Set actual values for the flags
_ = set.Set(FlagScanType, "ConcreteExecutionType")
_ = set.Set(FlagInputFile, "input.json")

return cli.NewContext(app, set, nil)
},
inputFileData: `[{"Execution": {"ShardID": 1}}]`, // Simulate the content of input file
expectedOutput: ``,
expectedError: "",
},
{
name: "MissingRequiredFlagScanType",
setupContext: func(app *cli.App) *cli.Context {
Expand Down Expand Up @@ -149,90 +170,150 @@ func TestAdminDBClean_errorCases(t *testing.T) {
}
}

func TestAdminDBClean(t *testing.T) {
func TestAdminDBClean_inFixExecution(t *testing.T) {
tests := []struct {
name string
contextSetup func(td *cliTestData) *cli.Context
contextSetup func(td *cliTestData, inputFilePath string) *cli.Context
mockSetup func(td *cliTestData)
inputFileData string
expectedError string
expectedOutput string
}{
{
name: "Success",
contextSetup: func(td *cliTestData) *cli.Context {
contextSetup: func(td *cliTestData, inputFilePath string) *cli.Context {
set := flag.NewFlagSet("test", 0)
// Define flags
set.String(FlagScanType, "", "scan type flag")
set.String(FlagInvariantCollection, "", "invariant collection flag")
set.String(FlagInputFile, "", "Input file flag")
set.Var(cli.NewStringSlice("CollectionHistory", "CollectionDomain"), FlagInvariantCollection, "invariant collection flag")

// Set values for flags
_ = set.Set(FlagScanType, "ConcreteExecutionType")
_ = set.Set(FlagInvariantCollection, "CollectionHistory") // Valid collection to ensure invariants are generated
_ = set.Set(FlagInputFile, "input.json")
_ = set.Set(FlagInputFile, inputFilePath) // 传递临时文件路径

return cli.NewContext(td.app, set, nil)
},
mockSetup: func(td *cliTestData) {
ctrl := gomock.NewController(t)
mockExecManager := persistence.NewMockExecutionManager(ctrl)
mockHistoryManager := persistence.NewMockHistoryManager(ctrl)
mockInvariantManager := invariant.NewMockManager(ctrl)

mockExecManager.EXPECT().Close().Times(1)
mockHistoryManager.EXPECT().Close().Times(1)

mockInvariantManager.EXPECT().RunFixes(gomock.Any(), gomock.Any()).Return(invariant.ManagerFixResult{}).Times(1)

td.mockManagerFactory.EXPECT().initializeExecutionManager(gomock.Any(), gomock.Any()).Return(mockExecManager, nil).Times(1)
td.mockManagerFactory.EXPECT().initializeHistoryManager(gomock.Any()).Return(mockHistoryManager, nil).Times(1)
td.mockManagerFactory.EXPECT().initializeInvariantManager(gomock.Any()).Return(mockInvariantManager, nil).Times(1)

},
inputFileData: `{"Execution": {"ShardID": 1}, "Result": {}}`,
expectedOutput: `{"Execution":{"BranchToken":null,"TreeID":"","BranchID":"","ShardID":1,"DomainID":"","WorkflowID":"","RunID":"","State":0},"Input":{"Execution":{"BranchToken":null,"TreeID":"","BranchID":"","ShardID":1,"DomainID":"","WorkflowID":"","RunID":"","State":0},"Result":{"CheckResultType":"","DeterminingInvariantType":null,"CheckResults":null}},"Result":{"FixResultType":"","DeterminingInvariantName":null,"FixResults":null}}
`,
expectedError: "",
},
{
name: "init invariant manager error",
contextSetup: func(td *cliTestData, inputFilePath string) *cli.Context {
set := flag.NewFlagSet("test", 0)
set.String(FlagScanType, "", "scan type flag")
set.String(FlagInputFile, "", "Input file flag")
set.Var(cli.NewStringSlice("CollectionHistory", "CollectionDomain"), FlagInvariantCollection, "invariant collection flag")

_ = set.Set(FlagScanType, "ConcreteExecutionType")
_ = set.Set(FlagInputFile, inputFilePath) // 传递临时文件路径

return cli.NewContext(td.app, set, nil)
},
mockSetup: func(td *cliTestData) {
// Mock the PersistenceManagerFactory
ctrl := gomock.NewController(t)
mockExecManager := persistence.NewMockExecutionManager(ctrl)
mockHistoryManager := persistence.NewMockHistoryManager(ctrl)

// Mock ExecutionManager and HistoryManager close methods
mockExecManager.EXPECT().Close().Times(1)
mockHistoryManager.EXPECT().Close().Times(1)

// Mock initializeExecutionStore and initializeHistoryManager correctly
td.mockPersistenceManagerFactory.EXPECT().initializeExecutionStore(gomock.Any(), gomock.Any()).Return(mockExecManager, nil).AnyTimes()
td.mockPersistenceManagerFactory.EXPECT().initializeHistoryManager(gomock.Any()).Return(mockHistoryManager, nil).AnyTimes()
td.mockManagerFactory.EXPECT().initializeExecutionManager(gomock.Any(), gomock.Any()).Return(mockExecManager, nil).Times(1)
td.mockManagerFactory.EXPECT().initializeHistoryManager(gomock.Any()).Return(mockHistoryManager, nil).Times(1)
td.mockManagerFactory.EXPECT().initializeInvariantManager(gomock.Any()).Return(nil, fmt.Errorf("init invariant manager error")).Times(1)

},
inputFileData: `{"Execution": {"ShardID": 1}, "Result": {}}`,
expectedOutput: ``,
expectedError: "Error in fix execution: : init invariant manager error",
},
{
name: "init execution manager error",
contextSetup: func(td *cliTestData, inputFilePath string) *cli.Context {
set := flag.NewFlagSet("test", 0)
set.String(FlagScanType, "", "scan type flag")
set.String(FlagInputFile, "", "Input file flag")
set.Var(cli.NewStringSlice("CollectionHistory", "CollectionDomain"), FlagInvariantCollection, "invariant collection flag")

// Mock fixExecution by setting up a valid InvariantFactory
mockInvariant := invariant.NewMockInvariant(ctrl)
mockInvariant.EXPECT().Fix(gomock.Any(), gomock.Any()).Return(invariant.FixResult{
FixResultType: invariant.FixResultTypeFixed,
}).Times(1)
_ = set.Set(FlagScanType, "ConcreteExecutionType")
_ = set.Set(FlagInputFile, inputFilePath) // 传递临时文件路径

// Ensure that ToInvariants returns a non-empty list of factories
td.mockFrontendClient.EXPECT().StartWorkflowExecution(gomock.Any(), gomock.Any()).Return(&types.StartWorkflowExecutionResponse{RunID: "test-run-id"}, nil).AnyTimes()
return cli.NewContext(td.app, set, nil)
},
mockSetup: func(td *cliTestData) {
td.mockManagerFactory.EXPECT().initializeExecutionManager(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("init execution manager error")).Times(1)
},
inputFileData: `{"Execution": {"ShardID": 1}, "Result": {}}`,
expectedOutput: `{"Execution":{"ShardID":1},"Input":{"Execution":{"ShardID":1}},"Result":{}}`,
expectedError: "",
expectedOutput: ``,
expectedError: "Error in fix execution: : init execution manager error",
},
{
name: "init history manager error",
contextSetup: func(td *cliTestData, inputFilePath string) *cli.Context {
set := flag.NewFlagSet("test", 0)
set.String(FlagScanType, "", "scan type flag")
set.String(FlagInputFile, "", "Input file flag")
set.Var(cli.NewStringSlice("CollectionHistory", "CollectionDomain"), FlagInvariantCollection, "invariant collection flag")

_ = set.Set(FlagScanType, "ConcreteExecutionType")
_ = set.Set(FlagInputFile, inputFilePath) // 传递临时文件路径

return cli.NewContext(td.app, set, nil)
},
mockSetup: func(td *cliTestData) {
ctrl := gomock.NewController(t)
mockExecManager := persistence.NewMockExecutionManager(ctrl)
mockExecManager.EXPECT().Close().Times(1)

td.mockManagerFactory.EXPECT().initializeExecutionManager(gomock.Any(), gomock.Any()).Return(mockExecManager, nil).Times(1)
td.mockManagerFactory.EXPECT().initializeHistoryManager(gomock.Any()).Return(nil, fmt.Errorf("init history manager error")).Times(1)
},
inputFileData: `{"Execution": {"ShardID": 1}, "Result": {}}`,
expectedOutput: ``,
expectedError: "Error in fix execution: : init history manager error",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create test data and set up mocks
td := newCLITestData(t)
tt.mockSetup(td)

// Create temp input file
inputFile, err := os.CreateTemp("", "test_input_*.json")
assert.NoError(t, err)
defer os.Remove(inputFile.Name()) // Clean up after test
defer os.Remove(inputFile.Name())

// Write input data to the temp file
if tt.inputFileData != "" {
_, err = inputFile.WriteString(tt.inputFileData)
assert.NoError(t, err)
}
inputFile.Close()

// Prepare the CLI context
c := tt.contextSetup(td)
c := tt.contextSetup(td, inputFile.Name())

// Run AdminDBClean
err = AdminDBClean(c)
if tt.expectedError != "" {
assert.ErrorContains(t, err, tt.expectedError)
} else {
assert.NoError(t, err)
}

// Validate output
assert.Equal(t, tt.expectedOutput, td.consoleOutput())
})
}
Expand Down
4 changes: 2 additions & 2 deletions tools/cli/admin_db_scan_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func checkExecution(
invariants []executions.InvariantFactory,
fetcher executions.ExecutionFetcher,
) (interface{}, invariant.ManagerCheckResult, error) {
execManager, err := getDeps(c).initializeExecutionStore(c, common.WorkflowIDToHistoryShard(req.WorkflowID, numberOfShards))
execManager, err := getDeps(c).initializeExecutionManager(c, common.WorkflowIDToHistoryShard(req.WorkflowID, numberOfShards))
defer execManager.Close()
if err != nil {
return nil, invariant.ManagerCheckResult{}, fmt.Errorf("Error in execution check: %w", err)
Expand Down Expand Up @@ -200,7 +200,7 @@ func listExecutionsByShardID(
outputFile *os.File,
) error {

client, err := getDeps(c).initializeExecutionStore(c, shardID)
client, err := getDeps(c).initializeExecutionManager(c, shardID)
defer client.Close()
if err != nil {
commoncli.Problem("Error in Admin DB unsupported WF scan: ", err)
Expand Down
2 changes: 1 addition & 1 deletion tools/cli/admin_timers.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func NewDBLoadCloser(c *cli.Context) (LoadCloser, error) {
return nil, fmt.Errorf("error in NewDBLoadCloser: failed to get shard ID: %w", err)
}

executionManager, err := getDeps(c).initializeExecutionStore(c, shardID)
executionManager, err := getDeps(c).initializeExecutionManager(c, shardID)
if err != nil {
return nil, fmt.Errorf("error in NewDBLoadCloser: failed to initialize execution store: %w", err)
}
Expand Down
12 changes: 6 additions & 6 deletions tools/cli/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ func WithIOHandler(h IOHandler) CLIAppOptions {
}
}

// WithPersistenceManagerFactory sets the PersistenceManagerFactory for the CLI app.
func WithPersistenceManagerFactory(factory PersistenceManagerFactory) CLIAppOptions {
// WithPersistenceManagerFactory sets the ManagerFactory for the CLI app.
func WithPersistenceManagerFactory(factory ManagerFactory) CLIAppOptions {
return func(app *cli.App) {
if app.Metadata == nil {
return
Expand All @@ -62,7 +62,7 @@ func WithPersistenceManagerFactory(factory PersistenceManagerFactory) CLIAppOpti
return
}

d.PersistenceManagerFactory = factory
d.ManagerFactory = factory
}
}

Expand All @@ -79,7 +79,7 @@ func NewCliApp(cf ClientFactory, opts ...CLIAppOptions) *cli.App {
app.Usage = "A command-line tool for cadence users"
app.Version = version
app.Metadata = map[string]any{
depsKey: &deps{ClientFactory: cf, IOHandler: &defaultIOHandler{app: app}, PersistenceManagerFactory: &defaultPersistenceManagerFactory{}},
depsKey: &deps{ClientFactory: cf, IOHandler: &defaultIOHandler{app: app}, ManagerFactory: &defaultManagerFactory{}},
}
app.Flags = []cli.Flag{
&cli.StringFlag{
Expand Down Expand Up @@ -271,7 +271,7 @@ func getDeps(ctx *cli.Context) cliDeps {
type cliDeps interface {
ClientFactory
IOHandler
PersistenceManagerFactory
ManagerFactory
}

type IOHandler interface {
Expand Down Expand Up @@ -322,5 +322,5 @@ var _ cliDeps = &deps{}
type deps struct {
ClientFactory
IOHandler
PersistenceManagerFactory
ManagerFactory
}
Loading

0 comments on commit 4bdd1b6

Please sign in to comment.