Example #1
0
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)
	}
}