diff --git a/tools/cli/admin_commands.go b/tools/cli/admin_commands.go index 99cd404705c..7b882afa0e0 100644 --- a/tools/cli/admin_commands.go +++ b/tools/cli/admin_commands.go @@ -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) } diff --git a/tools/cli/admin_commands_test.go b/tools/cli/admin_commands_test.go index 931361835d0..3866fd5a172 100644 --- a/tools/cli/admin_commands_test.go +++ b/tools/cli/admin_commands_test.go @@ -53,6 +53,7 @@ type cliTestData struct { mockAdminClient *admin.MockClient ioHandler *testIOHandler app *cli.App + mockManagerFactory *MockManagerFactory } func newCLITestData(t *testing.T) *cliTestData { @@ -62,15 +63,17 @@ func newCLITestData(t *testing.T) *cliTestData { td.mockFrontendClient = frontend.NewMockClient(ctrl) td.mockAdminClient = admin.NewMockClient(ctrl) + td.mockManagerFactory = NewMockManagerFactory(ctrl) td.ioHandler = &testIOHandler{} - // make a new CLI App with client factory returning our frontend and admin clients + // Create a new CLI app with client factory and persistence manager factory td.app = NewCliApp( &clientFactoryMock{ serverFrontendClient: td.mockFrontendClient, serverAdminClient: td.mockAdminClient, }, WithIOHandler(td.ioHandler), + WithManagerFactory(td.mockManagerFactory), // Inject the mocked persistence manager factory ) return &td } diff --git a/tools/cli/admin_db_clean_command.go b/tools/cli/admin_db_clean_command.go index 56a6cdde4d5..298b00953c4 100644 --- a/tools/cli/admin_db_clean_command.go +++ b/tools/cli/admin_db_clean_command.go @@ -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 } @@ -131,16 +132,18 @@ func fixExecution( invariants []executions.InvariantFactory, execution *store.ScanOutputEntity, ) (invariant.ManagerFixResult, error) { - execManager, err := getDeps(c).initializeExecutionStore(c, execution.Execution.(entity.Entity).GetShardID()) - defer execManager.Close() + execManager, err := getDeps(c).initializeExecutionManager(c, execution.Execution.(entity.Entity).GetShardID()) if err != nil { - return invariant.ManagerFixResult{}, fmt.Errorf("Error in fix execution: %w", err) + return invariant.ManagerFixResult{}, err } + defer execManager.Close() + historyV2Mgr, err := getDeps(c).initializeHistoryManager(c) - defer historyV2Mgr.Close() if err != nil { - return invariant.ManagerFixResult{}, fmt.Errorf("Error in fix execution: %w", err) + return invariant.ManagerFixResult{}, err } + defer historyV2Mgr.Close() + pr := persistence.NewPersistenceRetryer( execManager, historyV2Mgr, @@ -156,7 +159,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 + } + invariantManager, err := getDeps(c).initializeInvariantManager(ivs) + if err != nil { + return invariant.ManagerFixResult{}, err } - return invariant.NewInvariantManager(ivs).RunFixes(ctx, execution.Execution), nil + + return invariantManager.RunFixes(ctx, execution.Execution.(entity.Entity)), nil } diff --git a/tools/cli/admin_db_clean_command_test.go b/tools/cli/admin_db_clean_command_test.go index caf5c21982e..a2ef7f483ee 100644 --- a/tools/cli/admin_db_clean_command_test.go +++ b/tools/cli/admin_db_clean_command_test.go @@ -24,14 +24,20 @@ package cli import ( "flag" + "fmt" "os" "testing" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "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 @@ -39,6 +45,26 @@ func TestAdminDBClean_errorCases(t *testing.T) { 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 + require.NoError(t, set.Set(FlagScanType, "ConcreteExecutionType")) + require.NoError(t, 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 { @@ -58,8 +84,8 @@ func TestAdminDBClean_errorCases(t *testing.T) { set := flag.NewFlagSet("test", 0) set.String(FlagScanType, "", "scan type flag") set.String(FlagInputFile, "", "Input file flag") - _ = set.Set(FlagScanType, "unknown") - _ = set.Set(FlagInputFile, "input.json") + require.NoError(t, set.Set(FlagScanType, "unknown")) + require.NoError(t, set.Set(FlagInputFile, "input.json")) return cli.NewContext(app, set, nil) }, inputFileData: ``, @@ -78,8 +104,9 @@ func TestAdminDBClean_errorCases(t *testing.T) { set.Var(cli.NewStringSlice("invalid_collection", "history"), FlagInvariantCollection, "invariant collection flag") // Set actual values for the flags - _ = set.Set(FlagScanType, "ConcreteExecutionType") - _ = set.Set(FlagInputFile, "input.json") + require.NoError(t, set.Set(FlagScanType, "ConcreteExecutionType")) + require.NoError(t, set.Set(FlagInputFile, "input.json")) + return cli.NewContext(app, set, nil) }, inputFileData: ``, @@ -93,9 +120,11 @@ func TestAdminDBClean_errorCases(t *testing.T) { set.String(FlagScanType, "", "scan type flag") set.String(FlagInvariantCollection, "", "invariant collection flag") set.String(FlagInputFile, "", "Input file flag") - _ = set.Set(FlagScanType, "ConcreteExecutionType") - _ = set.Set(FlagInvariantCollection, "invalid_collection") // Collection will trigger no invariants - _ = set.Set(FlagInputFile, "input.json") + + require.NoError(t, set.Set(FlagScanType, "ConcreteExecutionType")) + require.NoError(t, set.Set(FlagInputFile, "input.json")) + require.NoError(t, set.Set(FlagInvariantCollection, "invalid_collection")) + return cli.NewContext(app, set, nil) }, inputFileData: `[{"Execution": {"ShardID": 1}}]`, @@ -144,3 +173,152 @@ func TestAdminDBClean_errorCases(t *testing.T) { }) } } + +func TestAdminDBClean_inFixExecution(t *testing.T) { + tests := []struct { + name string + contextSetup func(td *cliTestData, inputFilePath string) *cli.Context + mockSetup func(td *cliTestData) + inputFileData string + expectedError string + expectedOutput string + }{ + { + name: "Success", + 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") + + require.NoError(t, set.Set(FlagScanType, "ConcreteExecutionType")) + require.NoError(t, 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") + + require.NoError(t, set.Set(FlagScanType, "ConcreteExecutionType")) + require.NoError(t, 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) + + mockExecManager.EXPECT().Close().Times(1) + mockHistoryManager.EXPECT().Close().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(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") + + require.NoError(t, set.Set(FlagScanType, "ConcreteExecutionType")) + require.NoError(t, set.Set(FlagInputFile, inputFilePath)) + + 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: ``, + 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") + + require.NoError(t, set.Set(FlagScanType, "ConcreteExecutionType")) + require.NoError(t, 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) { + td := newCLITestData(t) + tt.mockSetup(td) + + inputFile, err := os.CreateTemp("", "test_input_*.json") + assert.NoError(t, err) + defer os.Remove(inputFile.Name()) + + if tt.inputFileData != "" { + _, err = inputFile.WriteString(tt.inputFileData) + assert.NoError(t, err) + } + inputFile.Close() + + c := tt.contextSetup(td, inputFile.Name()) + + err = AdminDBClean(c) + if tt.expectedError != "" { + assert.ErrorContains(t, err, tt.expectedError) + } else { + assert.NoError(t, err) + } + + assert.Equal(t, tt.expectedOutput, td.consoleOutput()) + }) + } +} diff --git a/tools/cli/admin_db_scan_command.go b/tools/cli/admin_db_scan_command.go index 5781cb067e0..5cf7d99f35b 100644 --- a/tools/cli/admin_db_scan_command.go +++ b/tools/cli/admin_db_scan_command.go @@ -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) @@ -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) diff --git a/tools/cli/admin_timers.go b/tools/cli/admin_timers.go index a09772ffaea..427b4e9ca9e 100644 --- a/tools/cli/admin_timers.go +++ b/tools/cli/admin_timers.go @@ -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) } diff --git a/tools/cli/app.go b/tools/cli/app.go index 7ba4cde1f23..ce370259028 100644 --- a/tools/cli/app.go +++ b/tools/cli/app.go @@ -50,6 +50,22 @@ func WithIOHandler(h IOHandler) CLIAppOptions { } } +// WithManagerFactory sets the ManagerFactory for the CLI app. +func WithManagerFactory(factory ManagerFactory) CLIAppOptions { + return func(app *cli.App) { + if app.Metadata == nil { + return + } + + d, ok := app.Metadata[depsKey].(*deps) + if !ok { + return + } + + d.ManagerFactory = factory + } +} + // NewCliApp instantiates a new instance of the CLI application func NewCliApp(cf ClientFactory, opts ...CLIAppOptions) *cli.App { version := fmt.Sprintf("CLI feature version: %v \n"+ @@ -63,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{ @@ -255,7 +271,7 @@ func getDeps(ctx *cli.Context) cliDeps { type cliDeps interface { ClientFactory IOHandler - PersistenceManagerFactory + ManagerFactory } type IOHandler interface { @@ -306,5 +322,5 @@ var _ cliDeps = &deps{} type deps struct { ClientFactory IOHandler - PersistenceManagerFactory + ManagerFactory } diff --git a/tools/cli/app_test.go b/tools/cli/app_test.go index 932d168b3cd..ab1e31855e1 100644 --- a/tools/cli/app_test.go +++ b/tools/cli/app_test.go @@ -925,3 +925,132 @@ func (s *cliAppSuite) TestConvertArray() { s.Nil(res) } } + +func TestWithManagerFactory(t *testing.T) { + tests := []struct { + name string + app *cli.App + expectFactory bool + expectNilMeta bool + expectDepsType bool + }{ + { + name: "Valid Metadata with deps key", + app: &cli.App{ + Metadata: map[string]interface{}{ + depsKey: &deps{}, + }, + }, + expectFactory: true, + expectNilMeta: false, + expectDepsType: true, + }, + { + name: "No Metadata", + app: &cli.App{Metadata: nil}, + expectFactory: false, + expectNilMeta: true, + expectDepsType: false, + }, + { + name: "Incorrect deps key type", + app: &cli.App{ + Metadata: map[string]interface{}{ + depsKey: "invalid_type", + }, + }, + expectFactory: false, + expectNilMeta: false, + expectDepsType: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockManagerFactory(ctrl) + + option := WithManagerFactory(mockFactory) + option(tt.app) + + if tt.expectNilMeta { + assert.Nil(t, tt.app.Metadata, "Expected Metadata to be nil") + } else { + d, ok := tt.app.Metadata[depsKey].(*deps) + if tt.expectDepsType { + assert.True(t, ok, "Expected depsKey to be of type *deps") + if tt.expectFactory { + assert.Equal(t, mockFactory, d.ManagerFactory, "Expected ManagerFactory to be set correctly") + } + } else { + assert.False(t, ok, "Expected depsKey not to be of type *deps") + } + } + }) + } +} + +func TestWithIOHandler(t *testing.T) { + tests := []struct { + name string + app *cli.App + expectHandler bool + expectNilMeta bool + expectDepsType bool + }{ + { + name: "Valid Metadata with deps key", + app: &cli.App{ + Metadata: map[string]interface{}{ + depsKey: &deps{}, + }, + }, + expectHandler: true, + expectNilMeta: false, + expectDepsType: true, + }, + { + name: "No Metadata", + app: &cli.App{Metadata: nil}, + expectHandler: false, + expectNilMeta: true, + expectDepsType: false, + }, + { + name: "Incorrect deps key type", + app: &cli.App{ + Metadata: map[string]interface{}{ + depsKey: "invalid_type", + }, + }, + expectHandler: false, + expectNilMeta: false, + expectDepsType: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + testHandler := testIOHandler{} + + option := WithIOHandler(&testHandler) + option(tt.app) + + if tt.expectNilMeta { + assert.Nil(t, tt.app.Metadata, "Expected Metadata to be nil") + } else { + d, ok := tt.app.Metadata[depsKey].(*deps) + if tt.expectDepsType { + assert.True(t, ok, "Expected depsKey to be of type *deps") + if tt.expectHandler { + assert.Equal(t, &testHandler, d.IOHandler, "Expected IOHandler to be set correctly") + } + } else { + assert.False(t, ok, "Expected depsKey not to be of type *deps") + } + } + }) + } +} diff --git a/tools/cli/database.go b/tools/cli/database.go index 4cb4c787960..a049ff44032 100644 --- a/tools/cli/database.go +++ b/tools/cli/database.go @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -//go:generate mockgen -package $GOPACKAGE -source $GOFILE -destination database_mock.go -self_package github.com/uber/cadence/tools/cli +//go:generate mockgen -package $GOPACKAGE -destination mock_manager_factory.go -self_package github.com/uber/cadence/tools/cli github.com/uber/cadence/tools/cli ManagerFactory package cli @@ -37,6 +37,7 @@ import ( "github.com/uber/cadence/common/persistence/client" "github.com/uber/cadence/common/persistence/nosql/nosqlplugin/cassandra" "github.com/uber/cadence/common/persistence/sql" + "github.com/uber/cadence/common/reconciliation/invariant" "github.com/uber/cadence/tools/common/flag" ) @@ -152,19 +153,20 @@ func getDBFlags() []cli.Flag { } } -type PersistenceManagerFactory interface { - initializeExecutionStore(c *cli.Context, shardID int) (persistence.ExecutionManager, error) +type ManagerFactory interface { + initializeExecutionManager(c *cli.Context, shardID int) (persistence.ExecutionManager, error) initializeHistoryManager(c *cli.Context) (persistence.HistoryManager, error) initializeShardManager(c *cli.Context) (persistence.ShardManager, error) initializeDomainManager(c *cli.Context) (persistence.DomainManager, error) initPersistenceFactory(c *cli.Context) (client.Factory, error) + initializeInvariantManager(ivs []invariant.Invariant) (invariant.Manager, error) } -type defaultPersistenceManagerFactory struct { +type defaultManagerFactory struct { persistenceFactory client.Factory } -func (f *defaultPersistenceManagerFactory) initializeExecutionStore(c *cli.Context, shardID int) (persistence.ExecutionManager, error) { +func (f *defaultManagerFactory) initializeExecutionManager(c *cli.Context, shardID int) (persistence.ExecutionManager, error) { factory, err := f.getPersistenceFactory(c) if err != nil { return nil, fmt.Errorf("Failed to get persistence factory: %w", err) @@ -176,7 +178,7 @@ func (f *defaultPersistenceManagerFactory) initializeExecutionStore(c *cli.Conte return executionManager, nil } -func (f *defaultPersistenceManagerFactory) initializeHistoryManager(c *cli.Context) (persistence.HistoryManager, error) { +func (f *defaultManagerFactory) initializeHistoryManager(c *cli.Context) (persistence.HistoryManager, error) { factory, err := f.getPersistenceFactory(c) if err != nil { return nil, fmt.Errorf("Failed to get persistence factory: %w", err) @@ -188,7 +190,7 @@ func (f *defaultPersistenceManagerFactory) initializeHistoryManager(c *cli.Conte return historyManager, nil } -func (f *defaultPersistenceManagerFactory) initializeShardManager(c *cli.Context) (persistence.ShardManager, error) { +func (f *defaultManagerFactory) initializeShardManager(c *cli.Context) (persistence.ShardManager, error) { factory, err := f.getPersistenceFactory(c) if err != nil { return nil, fmt.Errorf("Failed to get persistence factory: %w", err) @@ -200,7 +202,7 @@ func (f *defaultPersistenceManagerFactory) initializeShardManager(c *cli.Context return shardManager, nil } -func (f *defaultPersistenceManagerFactory) initializeDomainManager(c *cli.Context) (persistence.DomainManager, error) { +func (f *defaultManagerFactory) initializeDomainManager(c *cli.Context) (persistence.DomainManager, error) { factory, err := f.getPersistenceFactory(c) if err != nil { return nil, fmt.Errorf("Failed to get persistence factory: %w", err) @@ -212,7 +214,7 @@ func (f *defaultPersistenceManagerFactory) initializeDomainManager(c *cli.Contex return domainManager, nil } -func (f *defaultPersistenceManagerFactory) getPersistenceFactory(c *cli.Context) (client.Factory, error) { +func (f *defaultManagerFactory) getPersistenceFactory(c *cli.Context) (client.Factory, error) { var err error if f.persistenceFactory == nil { f.persistenceFactory, err = getDeps(c).initPersistenceFactory(c) @@ -223,7 +225,7 @@ func (f *defaultPersistenceManagerFactory) getPersistenceFactory(c *cli.Context) return f.persistenceFactory, nil } -func (f *defaultPersistenceManagerFactory) initPersistenceFactory(c *cli.Context) (client.Factory, error) { +func (f *defaultManagerFactory) initPersistenceFactory(c *cli.Context) (client.Factory, error) { cfg, err := getDeps(c).ServerConfig(c) if err != nil { @@ -265,6 +267,10 @@ func (f *defaultPersistenceManagerFactory) initPersistenceFactory(c *cli.Context ), nil } +func (f *defaultManagerFactory) initializeInvariantManager(ivs []invariant.Invariant) (invariant.Manager, error) { + return invariant.NewInvariantManager(ivs), nil +} + func overrideDataStore(c *cli.Context, ds config.DataStore) (config.DataStore, error) { if c.IsSet(FlagDBType) { // overriding DBType will wipe out all settings, everything will be set from flags only diff --git a/tools/cli/database_mock.go b/tools/cli/database_mock.go deleted file mode 100644 index 045175a8c05..00000000000 --- a/tools/cli/database_mock.go +++ /dev/null @@ -1,135 +0,0 @@ -// The MIT License (MIT) - -// Copyright (c) 2017-2020 Uber Technologies Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -// Code generated by MockGen. DO NOT EDIT. -// Source: database.go - -// Package cli is a generated GoMock package. -package cli - -import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - cli "github.com/urfave/cli/v2" - - persistence "github.com/uber/cadence/common/persistence" - client "github.com/uber/cadence/common/persistence/client" -) - -// MockPersistenceManagerFactory is a mock of PersistenceManagerFactory interface. -type MockPersistenceManagerFactory struct { - ctrl *gomock.Controller - recorder *MockPersistenceManagerFactoryMockRecorder -} - -// MockPersistenceManagerFactoryMockRecorder is the mock recorder for MockPersistenceManagerFactory. -type MockPersistenceManagerFactoryMockRecorder struct { - mock *MockPersistenceManagerFactory -} - -// NewMockPersistenceManagerFactory creates a new mock instance. -func NewMockPersistenceManagerFactory(ctrl *gomock.Controller) *MockPersistenceManagerFactory { - mock := &MockPersistenceManagerFactory{ctrl: ctrl} - mock.recorder = &MockPersistenceManagerFactoryMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockPersistenceManagerFactory) EXPECT() *MockPersistenceManagerFactoryMockRecorder { - return m.recorder -} - -// initPersistenceFactory mocks base method. -func (m *MockPersistenceManagerFactory) initPersistenceFactory(c *cli.Context) (client.Factory, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "initPersistenceFactory", c) - ret0, _ := ret[0].(client.Factory) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// initPersistenceFactory indicates an expected call of initPersistenceFactory. -func (mr *MockPersistenceManagerFactoryMockRecorder) initPersistenceFactory(c interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "initPersistenceFactory", reflect.TypeOf((*MockPersistenceManagerFactory)(nil).initPersistenceFactory), c) -} - -// initializeDomainManager mocks base method. -func (m *MockPersistenceManagerFactory) initializeDomainManager(c *cli.Context) (persistence.DomainManager, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "initializeDomainManager", c) - ret0, _ := ret[0].(persistence.DomainManager) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// initializeDomainManager indicates an expected call of initializeDomainManager. -func (mr *MockPersistenceManagerFactoryMockRecorder) initializeDomainManager(c interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "initializeDomainManager", reflect.TypeOf((*MockPersistenceManagerFactory)(nil).initializeDomainManager), c) -} - -// initializeExecutionStore mocks base method. -func (m *MockPersistenceManagerFactory) initializeExecutionStore(c *cli.Context, shardID int) (persistence.ExecutionManager, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "initializeExecutionStore", c, shardID) - ret0, _ := ret[0].(persistence.ExecutionManager) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// initializeExecutionStore indicates an expected call of initializeExecutionStore. -func (mr *MockPersistenceManagerFactoryMockRecorder) initializeExecutionStore(c, shardID interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "initializeExecutionStore", reflect.TypeOf((*MockPersistenceManagerFactory)(nil).initializeExecutionStore), c, shardID) -} - -// initializeHistoryManager mocks base method. -func (m *MockPersistenceManagerFactory) initializeHistoryManager(c *cli.Context) (persistence.HistoryManager, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "initializeHistoryManager", c) - ret0, _ := ret[0].(persistence.HistoryManager) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// initializeHistoryManager indicates an expected call of initializeHistoryManager. -func (mr *MockPersistenceManagerFactoryMockRecorder) initializeHistoryManager(c interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "initializeHistoryManager", reflect.TypeOf((*MockPersistenceManagerFactory)(nil).initializeHistoryManager), c) -} - -// initializeShardManager mocks base method. -func (m *MockPersistenceManagerFactory) initializeShardManager(c *cli.Context) (persistence.ShardManager, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "initializeShardManager", c) - ret0, _ := ret[0].(persistence.ShardManager) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// initializeShardManager indicates an expected call of initializeShardManager. -func (mr *MockPersistenceManagerFactoryMockRecorder) initializeShardManager(c interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "initializeShardManager", reflect.TypeOf((*MockPersistenceManagerFactory)(nil).initializeShardManager), c) -} diff --git a/tools/cli/database_test.go b/tools/cli/database_test.go new file mode 100644 index 00000000000..b52324b5de6 --- /dev/null +++ b/tools/cli/database_test.go @@ -0,0 +1,161 @@ +// The MIT License (MIT) + +// Copyright (c) 2017-2020 Uber Technologies Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package cli + +import ( + "fmt" + "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/persistence/client" +) + +func TestDefaultManagerFactory(t *testing.T) { + tests := []struct { + name string + setupMocks func(*client.MockFactory, *gomock.Controller) interface{} + methodToTest func(*defaultManagerFactory, *cli.Context) (interface{}, error) + expectError bool + }{ + { + name: "initializeExecutionManager - success", + setupMocks: func(mockFactory *client.MockFactory, ctrl *gomock.Controller) interface{} { + mockExecutionManager := persistence.NewMockExecutionManager(ctrl) + mockFactory.EXPECT().NewExecutionManager(gomock.Any()).Return(mockExecutionManager, nil) + return mockExecutionManager + }, + methodToTest: func(f *defaultManagerFactory, ctx *cli.Context) (interface{}, error) { + return f.initializeExecutionManager(ctx, 1) + }, + expectError: false, + }, + { + name: "initializeExecutionManager - error", + setupMocks: func(mockFactory *client.MockFactory, ctrl *gomock.Controller) interface{} { + mockFactory.EXPECT().NewExecutionManager(gomock.Any()).Return(nil, fmt.Errorf("some error")) + return nil + }, + methodToTest: func(f *defaultManagerFactory, ctx *cli.Context) (interface{}, error) { + return f.initializeExecutionManager(ctx, 1) + }, + expectError: true, + }, + { + name: "initializeHistoryManager - success", + setupMocks: func(mockFactory *client.MockFactory, ctrl *gomock.Controller) interface{} { + mockHistoryManager := persistence.NewMockHistoryManager(ctrl) + mockFactory.EXPECT().NewHistoryManager().Return(mockHistoryManager, nil) + return mockHistoryManager + }, + methodToTest: func(f *defaultManagerFactory, ctx *cli.Context) (interface{}, error) { + return f.initializeHistoryManager(ctx) + }, + expectError: false, + }, + { + name: "initializeHistoryManager - error", + setupMocks: func(mockFactory *client.MockFactory, ctrl *gomock.Controller) interface{} { + mockFactory.EXPECT().NewHistoryManager().Return(nil, fmt.Errorf("some error")) + return nil + }, + methodToTest: func(f *defaultManagerFactory, ctx *cli.Context) (interface{}, error) { + return f.initializeHistoryManager(ctx) + }, + expectError: true, + }, + { + name: "initializeShardManager - success", + setupMocks: func(mockFactory *client.MockFactory, ctrl *gomock.Controller) interface{} { + mockShardManager := persistence.NewMockShardManager(ctrl) + mockFactory.EXPECT().NewShardManager().Return(mockShardManager, nil) + return mockShardManager + }, + methodToTest: func(f *defaultManagerFactory, ctx *cli.Context) (interface{}, error) { + return f.initializeShardManager(ctx) + }, + expectError: false, + }, + { + name: "initializeShardManager - error", + setupMocks: func(mockFactory *client.MockFactory, ctrl *gomock.Controller) interface{} { + mockFactory.EXPECT().NewShardManager().Return(nil, fmt.Errorf("some error")) + return nil + }, + methodToTest: func(f *defaultManagerFactory, ctx *cli.Context) (interface{}, error) { + return f.initializeShardManager(ctx) + }, + expectError: true, + }, + { + name: "initializeDomainManager - success", + setupMocks: func(mockFactory *client.MockFactory, ctrl *gomock.Controller) interface{} { + mockDomainManager := persistence.NewMockDomainManager(ctrl) + mockFactory.EXPECT().NewDomainManager().Return(mockDomainManager, nil) + return mockDomainManager + }, + methodToTest: func(f *defaultManagerFactory, ctx *cli.Context) (interface{}, error) { + return f.initializeDomainManager(ctx) + }, + expectError: false, + }, + { + name: "initializeDomainManager - error", + setupMocks: func(mockFactory *client.MockFactory, ctrl *gomock.Controller) interface{} { + mockFactory.EXPECT().NewDomainManager().Return(nil, fmt.Errorf("some error")) + return nil + }, + methodToTest: func(f *defaultManagerFactory, ctx *cli.Context) (interface{}, error) { + return f.initializeDomainManager(ctx) + }, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := client.NewMockFactory(ctrl) + expectedManager := tt.setupMocks(mockFactory, ctrl) + + f := &defaultManagerFactory{persistenceFactory: mockFactory} + app := &cli.App{} + ctx := cli.NewContext(app, nil, nil) + + result, err := tt.methodToTest(f, ctx) + + if tt.expectError { + assert.Error(t, err) + assert.Nil(t, result) + } else { + assert.NoError(t, err) + assert.Equal(t, expectedManager, result) + } + }) + } +} diff --git a/tools/cli/mock_manager_factory.go b/tools/cli/mock_manager_factory.go new file mode 100644 index 00000000000..fcbfec356fd --- /dev/null +++ b/tools/cli/mock_manager_factory.go @@ -0,0 +1,151 @@ +// The MIT License (MIT) + +// Copyright (c) 2017-2020 Uber Technologies Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/uber/cadence/tools/cli (interfaces: ManagerFactory) + +// Package cli is a generated GoMock package. +package cli + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + cli "github.com/urfave/cli/v2" + + persistence "github.com/uber/cadence/common/persistence" + client "github.com/uber/cadence/common/persistence/client" + invariant "github.com/uber/cadence/common/reconciliation/invariant" +) + +// MockManagerFactory is a mock of ManagerFactory interface. +type MockManagerFactory struct { + ctrl *gomock.Controller + recorder *MockManagerFactoryMockRecorder +} + +// MockManagerFactoryMockRecorder is the mock recorder for MockManagerFactory. +type MockManagerFactoryMockRecorder struct { + mock *MockManagerFactory +} + +// NewMockManagerFactory creates a new mock instance. +func NewMockManagerFactory(ctrl *gomock.Controller) *MockManagerFactory { + mock := &MockManagerFactory{ctrl: ctrl} + mock.recorder = &MockManagerFactoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockManagerFactory) EXPECT() *MockManagerFactoryMockRecorder { + return m.recorder +} + +// initPersistenceFactory mocks base method. +func (m *MockManagerFactory) initPersistenceFactory(arg0 *cli.Context) (client.Factory, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "initPersistenceFactory", arg0) + ret0, _ := ret[0].(client.Factory) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// initPersistenceFactory indicates an expected call of initPersistenceFactory. +func (mr *MockManagerFactoryMockRecorder) initPersistenceFactory(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "initPersistenceFactory", reflect.TypeOf((*MockManagerFactory)(nil).initPersistenceFactory), arg0) +} + +// initializeDomainManager mocks base method. +func (m *MockManagerFactory) initializeDomainManager(arg0 *cli.Context) (persistence.DomainManager, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "initializeDomainManager", arg0) + ret0, _ := ret[0].(persistence.DomainManager) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// initializeDomainManager indicates an expected call of initializeDomainManager. +func (mr *MockManagerFactoryMockRecorder) initializeDomainManager(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "initializeDomainManager", reflect.TypeOf((*MockManagerFactory)(nil).initializeDomainManager), arg0) +} + +// initializeExecutionManager mocks base method. +func (m *MockManagerFactory) initializeExecutionManager(arg0 *cli.Context, arg1 int) (persistence.ExecutionManager, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "initializeExecutionManager", arg0, arg1) + ret0, _ := ret[0].(persistence.ExecutionManager) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// initializeExecutionManager indicates an expected call of initializeExecutionManager. +func (mr *MockManagerFactoryMockRecorder) initializeExecutionManager(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "initializeExecutionManager", reflect.TypeOf((*MockManagerFactory)(nil).initializeExecutionManager), arg0, arg1) +} + +// initializeHistoryManager mocks base method. +func (m *MockManagerFactory) initializeHistoryManager(arg0 *cli.Context) (persistence.HistoryManager, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "initializeHistoryManager", arg0) + ret0, _ := ret[0].(persistence.HistoryManager) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// initializeHistoryManager indicates an expected call of initializeHistoryManager. +func (mr *MockManagerFactoryMockRecorder) initializeHistoryManager(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "initializeHistoryManager", reflect.TypeOf((*MockManagerFactory)(nil).initializeHistoryManager), arg0) +} + +// initializeInvariantManager mocks base method. +func (m *MockManagerFactory) initializeInvariantManager(arg0 []invariant.Invariant) (invariant.Manager, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "initializeInvariantManager", arg0) + ret0, _ := ret[0].(invariant.Manager) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// initializeInvariantManager indicates an expected call of initializeInvariantManager. +func (mr *MockManagerFactoryMockRecorder) initializeInvariantManager(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "initializeInvariantManager", reflect.TypeOf((*MockManagerFactory)(nil).initializeInvariantManager), arg0) +} + +// initializeShardManager mocks base method. +func (m *MockManagerFactory) initializeShardManager(arg0 *cli.Context) (persistence.ShardManager, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "initializeShardManager", arg0) + ret0, _ := ret[0].(persistence.ShardManager) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// initializeShardManager indicates an expected call of initializeShardManager. +func (mr *MockManagerFactoryMockRecorder) initializeShardManager(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "initializeShardManager", reflect.TypeOf((*MockManagerFactory)(nil).initializeShardManager), arg0) +}