func TestWithRealEqualSplits(t *testing.T) { splitParams, err := NewSplitParamsGivenSplitCount( "select * from test_table", map[string]interface{}{}, []sqlparser.ColIdent{sqlparser.NewColIdent("id"), sqlparser.NewColIdent("user_id")}, 3, /* split_count */ getTestSchema()) if err != nil { t.Fatalf("want: nil, got: %v", err) } mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockSQLExecuter := splitquery_testing.NewMockSQLExecuter(mockCtrl) expectedCall1 := mockSQLExecuter.EXPECT().SQLExecute( "select min(id), max(id) from test_table", nil /* Bind Variables */) expectedCall1.Return( &sqltypes.Result{ Rows: [][]sqltypes.Value{ {int64Value(10), int64Value(3010)}, }, }, nil) equalSplits, err := NewEqualSplitsAlgorithm(splitParams, mockSQLExecuter) splitter := NewSplitter(splitParams, equalSplits) queryParts, err := splitter.Split() if err != nil { t.Errorf("Splitter.Split() failed with: %v", err) } expected := []querytypes.QuerySplit{ { Sql: "select * from test_table where id < :_splitquery_end_id", BindVariables: map[string]interface{}{ "_splitquery_end_id": int64(1010), }, }, { Sql: "select * from test_table where" + " (:_splitquery_start_id <= id)" + " and" + " (id < :_splitquery_end_id)", BindVariables: map[string]interface{}{ "_splitquery_start_id": int64(1010), "_splitquery_end_id": int64(2010), }, }, { Sql: "select * from test_table where" + " :_splitquery_start_id <= id", BindVariables: map[string]interface{}{ "_splitquery_start_id": int64(2010), }, }, } verifyQueryPartsEqual(t, expected, queryParts) }
func TestSQLExecuterReturnsError(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() splitParams, err := NewSplitParamsGivenNumRowsPerQueryPart( "select * from test_table where int_col > 5", nil, /* bindVariables */ []sqlparser.ColIdent{ sqlparser.NewColIdent("id"), sqlparser.NewColIdent("user_id"), }, /* splitColumns */ 1000, getTestSchema(), ) if err != nil { t.Fatalf("NewSplitParamsGivenNumRowsPerQueryPart failed with: %v", err) } mockSQLExecuter := splitquery_testing.NewMockSQLExecuter(mockCtrl) expectedCall1 := mockSQLExecuter.EXPECT().SQLExecute( "select id, user_id from test_table"+ " where int_col > 5"+ " order by id asc, user_id asc"+ " limit 1000, 1", map[string]interface{}{}) expectedCall1.Return( &sqltypes.Result{ Rows: [][]sqltypes.Value{ {int64Value(1), int64Value(1)}}, }, nil) expectedCall2 := mockSQLExecuter.EXPECT().SQLExecute( "select id, user_id from test_table"+ " where (int_col > 5) and"+ " (:_splitquery_prev_id < id or"+ " (:_splitquery_prev_id = id and :_splitquery_prev_user_id <= user_id))"+ " order by id asc, user_id asc"+ " limit 1000, 1", map[string]interface{}{ "_splitquery_prev_id": int64(1), "_splitquery_prev_user_id": int64(1), }) expectedErr := fmt.Errorf("Error accessing database!") expectedCall2.Return(nil, expectedErr) algorithm, err := NewFullScanAlgorithm(splitParams, mockSQLExecuter) if err != nil { t.Fatalf("NewFullScanAlgorithm failed with: %v", err) } boundaries, err := algorithm.generateBoundaries() if err != expectedErr { t.Fatalf("FullScanAlgorithm.generateBoundaries() did not fail as expected. err: %v", err) } if boundaries != nil { t.Fatalf("boundaries: %v, expected: nil", boundaries) } }
func TestEqualSplitsAlgorithm(t *testing.T) { // singleTest is a function that executes a single-test. singleTest := func(testCase *testCaseType) { splitParams, err := NewSplitParamsGivenSplitCount( "select * from test_table where int_col > 5", /* bindVariables */ nil, []string{testCase.SplitColumn}, testCase.SplitCount, GetSchema(), ) if err != nil { t.Errorf("NewSplitParamsWithNumRowsPerQueryPart failed with: %v", err) return } mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockSQLExecuter := splitquery_testing.NewMockSQLExecuter(mockCtrl) expectedCall1 := mockSQLExecuter.EXPECT().SQLExecute( fmt.Sprintf( "select min(%v), max(%v) from test_table", testCase.SplitColumn, testCase.SplitColumn), nil /* Bind Variables */) expectedCall1.Return( &sqltypes.Result{ Rows: [][]sqltypes.Value{ {testCase.MinValue, testCase.MaxValue}, }, }, nil) algorithm, err := NewEqualSplitsAlgorithm(splitParams, mockSQLExecuter) if err != nil { t.Errorf("NewEqualSplitsAlgorithm() failed with: %v", err) return } boundaries, err := algorithm.generateBoundaries() if err != nil { t.Errorf("EqualSplitsAlgorithm.generateBoundaries() failed with: %v", err) return } if !reflect.DeepEqual(boundaries, testCase.ExpectedBoundaries) { t.Errorf("EqualSplitsAlgorith.generateBoundaries()=%+v, expected: %+v. testCase: %+v", boundaries, testCase.ExpectedBoundaries, testCase) } } // singleTest() for _, testCase := range testCases { singleTest(&testCase) } }
func TestSmallNumberOfRows(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() splitParams, err := NewSplitParamsGivenNumRowsPerQueryPart( "select * from test_table where int_col > 5", nil, /* bindVariables */ []sqlparser.ColIdent{ sqlparser.NewColIdent("id"), sqlparser.NewColIdent("user_id"), }, /* splitColumns */ 1000, getTestSchema(), ) if err != nil { t.Fatalf("NewSplitParamsGivenNumRowsPerQueryPart failed with: %v", err) } mockSQLExecuter := splitquery_testing.NewMockSQLExecuter(mockCtrl) expectedCall1 := mockSQLExecuter.EXPECT().SQLExecute( "select id, user_id from test_table"+ " where int_col > 5"+ " order by id asc, user_id asc"+ " limit 1000, 1", map[string]interface{}{}) expectedCall1.Return( &sqltypes.Result{Rows: [][]sqltypes.Value{}}, nil) algorithm, err := NewFullScanAlgorithm(splitParams, mockSQLExecuter) if err != nil { t.Fatalf("NewFullScanAlgorithm failed with: %v", err) } boundaries, err := algorithm.generateBoundaries() if err != nil { t.Fatalf("FullScanAlgorithm.generateBoundaries() failed with: %v", err) } expectedBoundaries := []tuple{} if !reflect.DeepEqual(expectedBoundaries, boundaries) { t.Fatalf("expected: %v, got: %v", expectedBoundaries, boundaries) } }
func TestMultipleBoundaries(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() splitParams, err := NewSplitParamsGivenNumRowsPerQueryPart( "select * from test_table where int_col > 5", nil, /* bindVariables */ []string{"id", "user_id"}, /* splitColumns */ 1000, GetSchema(), ) if err != nil { t.Fatalf("NewSplitParamsGivenNumRowsPerQueryPart failed with: %v", err) } mockSQLExecuter := splitquery_testing.NewMockSQLExecuter(mockCtrl) expectedCall1 := mockSQLExecuter.EXPECT().SQLExecute( "select id, user_id from test_table"+ " where int_col > 5"+ " order by id asc, user_id asc"+ " limit 1000, 1", map[string]interface{}{}) expectedCall1.Return( &sqltypes.Result{ Rows: [][]sqltypes.Value{ {Int64Value(1), Int64Value(1)}}, }, nil) expectedCall2 := mockSQLExecuter.EXPECT().SQLExecute( "select id, user_id from test_table"+ " where (int_col > 5) and"+ " (:_splitquery_prev_id < id or"+ " (:_splitquery_prev_id = id and :_splitquery_prev_user_id <= user_id))"+ " order by id asc, user_id asc"+ " limit 1000, 1", map[string]interface{}{ "_splitquery_prev_id": int64(1), "_splitquery_prev_user_id": int64(1), }) expectedCall2.Return( &sqltypes.Result{ Rows: [][]sqltypes.Value{ {Int64Value(2), Int64Value(10)}}, }, nil) expectedCall2.After(expectedCall1) expectedCall3 := mockSQLExecuter.EXPECT().SQLExecute( "select id, user_id from test_table"+ " where (int_col > 5) and"+ " (:_splitquery_prev_id < id or"+ " (:_splitquery_prev_id = id and :_splitquery_prev_user_id <= user_id))"+ " order by id asc, user_id asc"+ " limit 1000, 1", map[string]interface{}{ "_splitquery_prev_id": int64(2), "_splitquery_prev_user_id": int64(10), }) expectedCall3.Return( &sqltypes.Result{Rows: [][]sqltypes.Value{}}, nil) expectedCall3.After(expectedCall2) algorithm, err := NewFullScanAlgorithm(splitParams, mockSQLExecuter) if err != nil { t.Fatalf("NewFullScanAlgorithm failed with: %v", err) } boundaries, err := algorithm.generateBoundaries() if err != nil { t.Fatalf("FullScanAlgorithm.generateBoundaries() failed with: %v", err) } expectedBoundaries := []tuple{ {Int64Value(1), Int64Value(1)}, {Int64Value(2), Int64Value(10)}, } if !reflect.DeepEqual(expectedBoundaries, boundaries) { t.Fatalf("expected: %v, got: %v", expectedBoundaries, boundaries) } }