func TestBuildUniqueKeyRangeEndPreparedQuery(t *testing.T) { databaseName := "mydb" originalTableName := "tbl" var chunkSize int64 = 500 { uniqueKeyColumns := []string{"name", "position"} rangeStartArgs := []interface{}{3, 17} rangeEndArgs := []interface{}{103, 117} query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQuery(databaseName, originalTableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test") test.S(t).ExpectNil(err) expected := ` select /* gh-ost mydb.tbl test */ name, position from ( select name, position from mydb.tbl where ((name > ?) or (((name = ?)) AND (position > ?))) and ((name < ?) or (((name = ?)) AND (position < ?)) or ((name = ?) and (position = ?))) order by name asc, position asc limit 500 ) select_osc_chunk order by name desc, position desc limit 1 ` test.S(t).ExpectEquals(normalizeQuery(query), normalizeQuery(expected)) test.S(t).ExpectTrue(reflect.DeepEqual(explodedArgs, []interface{}{3, 3, 17, 103, 103, 117, 103, 117})) } }
func TestParseAlterStatement(t *testing.T) { statement := "add column t int, engine=innodb" parser := NewParser() err := parser.ParseAlterStatement(statement) test.S(t).ExpectNil(err) test.S(t).ExpectFalse(parser.HasNonTrivialRenames()) }
func TestBinlogPrevious(t *testing.T) { c1 := BinlogCoordinates{LogFile: "mysql-bin.00017", LogPos: 104} cres, err := c1.PreviousFileCoordinates() test.S(t).ExpectNil(err) test.S(t).ExpectEquals(c1.Type, cres.Type) test.S(t).ExpectEquals(cres.LogFile, "mysql-bin.00016") c2 := BinlogCoordinates{LogFile: "mysql-bin.00100", LogPos: 104} cres, err = c2.PreviousFileCoordinates() test.S(t).ExpectNil(err) test.S(t).ExpectEquals(c1.Type, cres.Type) test.S(t).ExpectEquals(cres.LogFile, "mysql-bin.00099") c3 := BinlogCoordinates{LogFile: "mysql.00.prod.com.00100", LogPos: 104} cres, err = c3.PreviousFileCoordinates() test.S(t).ExpectNil(err) test.S(t).ExpectEquals(c1.Type, cres.Type) test.S(t).ExpectEquals(cres.LogFile, "mysql.00.prod.com.00099") c4 := BinlogCoordinates{LogFile: "mysql.00.prod.com.00000", LogPos: 104} _, err = c4.PreviousFileCoordinates() test.S(t).ExpectNotNil(err) }
func TestBinlogFileNumberDistance(t *testing.T) { c1 := BinlogCoordinates{LogFile: "mysql-bin.00017", LogPos: 104} fileNum, numLen := c1.FileNumber() test.S(t).ExpectEquals(fileNum, 17) test.S(t).ExpectEquals(numLen, 5) }
func TestBuildUniqueKeyMinValuesPreparedQuery(t *testing.T) { databaseName := "mydb" originalTableName := "tbl" uniqueKeyColumns := []string{"name", "position"} { query, err := BuildUniqueKeyMinValuesPreparedQuery(databaseName, originalTableName, uniqueKeyColumns) test.S(t).ExpectNil(err) expected := ` select /* gh-ost mydb.tbl */ name, position from mydb.tbl order by name asc, position asc limit 1 ` test.S(t).ExpectEquals(normalizeQuery(query), normalizeQuery(expected)) } { query, err := BuildUniqueKeyMaxValuesPreparedQuery(databaseName, originalTableName, uniqueKeyColumns) test.S(t).ExpectNil(err) expected := ` select /* gh-ost mydb.tbl */ name, position from mydb.tbl order by name desc, position desc limit 1 ` test.S(t).ExpectEquals(normalizeQuery(query), normalizeQuery(expected)) } }
func TestInstanceKeyMapReadJSON(t *testing.T) { json := `[{"Hostname":"host1","Port":3306},{"Hostname":"host2","Port":3306}]` m := *NewInstanceKeyMap() m.ReadJson(json) test.S(t).ExpectEquals(len(m), 2) test.S(t).ExpectTrue(m[key1]) test.S(t).ExpectTrue(m[key2]) }
func TestBinlogFileNumber(t *testing.T) { c1 := BinlogCoordinates{LogFile: "mysql-bin.00017", LogPos: 104} c2 := BinlogCoordinates{LogFile: "mysql-bin.00022", LogPos: 104} test.S(t).ExpectEquals(c1.FileNumberDistance(&c1), 0) test.S(t).ExpectEquals(c1.FileNumberDistance(&c2), 5) test.S(t).ExpectEquals(c2.FileNumberDistance(&c1), -5) }
func TestBuildEqualsPreparedComparison(t *testing.T) { { columns := []string{"c1", "c2"} comparison, err := BuildEqualsPreparedComparison(columns) test.S(t).ExpectNil(err) test.S(t).ExpectEquals(comparison, "((`c1` = ?) and (`c2` = ?))") } }
func TestBuildDMLDeleteQuery(t *testing.T) { databaseName := "mydb" tableName := "tbl" tableColumns := NewColumnList([]string{"id", "name", "rank", "position", "age"}) args := []interface{}{3, "testname", "first", 17, 23} { uniqueKeyColumns := NewColumnList([]string{"position"}) query, uniqueKeyArgs, err := BuildDMLDeleteQuery(databaseName, tableName, tableColumns, uniqueKeyColumns, args) test.S(t).ExpectNil(err) expected := ` delete /* gh-ost mydb.tbl */ from mydb.tbl where ((position = ?)) ` test.S(t).ExpectEquals(normalizeQuery(query), normalizeQuery(expected)) test.S(t).ExpectTrue(reflect.DeepEqual(uniqueKeyArgs, []interface{}{17})) } { uniqueKeyColumns := NewColumnList([]string{"name", "position"}) query, uniqueKeyArgs, err := BuildDMLDeleteQuery(databaseName, tableName, tableColumns, uniqueKeyColumns, args) test.S(t).ExpectNil(err) expected := ` delete /* gh-ost mydb.tbl */ from mydb.tbl where ((name = ?) and (position = ?)) ` test.S(t).ExpectEquals(normalizeQuery(query), normalizeQuery(expected)) test.S(t).ExpectTrue(reflect.DeepEqual(uniqueKeyArgs, []interface{}{"testname", 17})) } { uniqueKeyColumns := NewColumnList([]string{"position", "name"}) query, uniqueKeyArgs, err := BuildDMLDeleteQuery(databaseName, tableName, tableColumns, uniqueKeyColumns, args) test.S(t).ExpectNil(err) expected := ` delete /* gh-ost mydb.tbl */ from mydb.tbl where ((position = ?) and (name = ?)) ` test.S(t).ExpectEquals(normalizeQuery(query), normalizeQuery(expected)) test.S(t).ExpectTrue(reflect.DeepEqual(uniqueKeyArgs, []interface{}{17, "testname"})) } { uniqueKeyColumns := NewColumnList([]string{"position", "name"}) args := []interface{}{"first", 17} _, _, err := BuildDMLDeleteQuery(databaseName, tableName, tableColumns, uniqueKeyColumns, args) test.S(t).ExpectNotNil(err) } }
func TestIsSmallerMajorVersion(t *testing.T) { i55 := Instance{Version: "5.5"} i5517 := Instance{Version: "5.5.17"} i56 := Instance{Version: "5.6"} test.S(t).ExpectFalse(i55.IsSmallerMajorVersion(&i5517)) test.S(t).ExpectFalse(i56.IsSmallerMajorVersion(&i5517)) test.S(t).ExpectTrue(i55.IsSmallerMajorVersion(&i56)) }
func TestInstanceKeyMapToJSON(t *testing.T) { m := *NewInstanceKeyMap() m.AddKey(key1) m.AddKey(key2) json, err := m.ToJSON() test.S(t).ExpectNil(err) ok := (json == `[{"Hostname":"host1","Port":3306},{"Hostname":"host2","Port":3306}]`) || (json == `[{"Hostname":"host2","Port":3306},{"Hostname":"host1","Port":3306}]`) test.S(t).ExpectTrue(ok) }
func TestInstanceKeyValid(t *testing.T) { test.S(t).ExpectTrue(key1.IsValid()) i, err := ParseInstanceKey("_:3306") test.S(t).ExpectNil(err) test.S(t).ExpectFalse(i.IsValid()) i, err = ParseInstanceKey("//myhost:3306") test.S(t).ExpectNil(err) test.S(t).ExpectFalse(i.IsValid()) }
func TestParseAlterStatementTrivialRename(t *testing.T) { statement := "add column t int, change ts ts timestamp, engine=innodb" parser := NewParser() err := parser.ParseAlterStatement(statement) test.S(t).ExpectNil(err) test.S(t).ExpectFalse(parser.HasNonTrivialRenames()) test.S(t).ExpectEquals(len(parser.columnRenameMap), 1) test.S(t).ExpectEquals(parser.columnRenameMap["ts"], "ts") }
func TestIsGenerallyValidAsBinlogSource(t *testing.T) { instances, _ := generateTestInstances() for _, instance := range instances { test.S(t).ExpectFalse(isGenerallyValidAsBinlogSource(instance)) } applyGeneralGoodToGoReplicationParams(instances) for _, instance := range instances { test.S(t).ExpectTrue(isGenerallyValidAsBinlogSource(instance)) } }
func TestParseColumnList(t *testing.T) { names := "id,category,max_len" columnList := ParseColumnList(names) test.S(t).ExpectEquals(columnList.Len(), 3) test.S(t).ExpectTrue(reflect.DeepEqual(columnList.Names, []string{"id", "category", "max_len"})) test.S(t).ExpectEquals(columnList.Ordinals["id"], 0) test.S(t).ExpectEquals(columnList.Ordinals["category"], 1) test.S(t).ExpectEquals(columnList.Ordinals["max_len"], 2) }
func TestRemoveInstance(t *testing.T) { { instances := [](*Instance){&instance1, &instance2} test.S(t).ExpectEquals(len(instances), 2) instances = RemoveNilInstances(instances) test.S(t).ExpectEquals(len(instances), 2) } { instances := [](*Instance){&instance1, nil, &instance2} test.S(t).ExpectEquals(len(instances), 3) instances = RemoveNilInstances(instances) test.S(t).ExpectEquals(len(instances), 2) } { instances := [](*Instance){&instance1, &instance2} test.S(t).ExpectEquals(len(instances), 2) instances = RemoveInstance(instances, &key1) test.S(t).ExpectEquals(len(instances), 1) instances = RemoveInstance(instances, &key1) test.S(t).ExpectEquals(len(instances), 1) instances = RemoveInstance(instances, &key2) test.S(t).ExpectEquals(len(instances), 0) instances = RemoveInstance(instances, &key2) test.S(t).ExpectEquals(len(instances), 0) } }
func TestSortInstancesSameCoordinatesDifferingVersions(t *testing.T) { instances, instancesMap := generateTestInstances() for _, instance := range instances { instance.ExecBinlogCoordinates = instances[0].ExecBinlogCoordinates } instancesMap[i810Key.StringCode()].Version = "5.5.1" instancesMap[i720Key.StringCode()].Version = "5.7.8" sortInstances(instances) test.S(t).ExpectEquals(instances[0].Key, i810Key) test.S(t).ExpectEquals(instances[5].Key, i720Key) }
func TestSortInstancesSameCoordinatesDifferingBinlogFormats(t *testing.T) { instances, instancesMap := generateTestInstances() for _, instance := range instances { instance.ExecBinlogCoordinates = instances[0].ExecBinlogCoordinates instance.Binlog_format = "MIXED" } instancesMap[i810Key.StringCode()].Binlog_format = "STATEMENT" instancesMap[i720Key.StringCode()].Binlog_format = "ROW" sortInstances(instances) test.S(t).ExpectEquals(instances[0].Key, i810Key) test.S(t).ExpectEquals(instances[5].Key, i720Key) }
func TestString(t *testing.T) { { m, _ := ParseLoadMap("") s := m.String() test.S(t).ExpectEquals(s, "") } { loadList := "threads_running=20,threads_connected=10" m, _ := ParseLoadMap(loadList) s := m.String() test.S(t).ExpectEquals(s, "threads_connected=10,threads_running=20") } }
func TestCanReplicateFrom(t *testing.T) { i55 := Instance{Key: key1, Version: "5.5"} i56 := Instance{Key: key2, Version: "5.6"} var canReplicate bool canReplicate, _ = i56.CanReplicateFrom(&i55) test.S(t).ExpectEquals(canReplicate, false) //binlog not yet enabled i55.LogBinEnabled = true i55.LogSlaveUpdatesEnabled = true i56.LogBinEnabled = true i56.LogSlaveUpdatesEnabled = true canReplicate, _ = i56.CanReplicateFrom(&i55) test.S(t).ExpectEquals(canReplicate, false) //serverid not set i55.ServerID = 55 i56.ServerID = 56 canReplicate, err := i56.CanReplicateFrom(&i55) test.S(t).ExpectNil(err) test.S(t).ExpectTrue(canReplicate) canReplicate, _ = i55.CanReplicateFrom(&i56) test.S(t).ExpectFalse(canReplicate) iStatement := Instance{Key: key1, Binlog_format: "STATEMENT", ServerID: 1, Version: "5.5", LogBinEnabled: true, LogSlaveUpdatesEnabled: true} iRow := Instance{Key: key2, Binlog_format: "ROW", ServerID: 2, Version: "5.5", LogBinEnabled: true, LogSlaveUpdatesEnabled: true} canReplicate, err = iRow.CanReplicateFrom(&iStatement) test.S(t).ExpectNil(err) test.S(t).ExpectTrue(canReplicate) canReplicate, _ = iStatement.CanReplicateFrom(&iRow) test.S(t).ExpectFalse(canReplicate) }
func TestParseLoadMap(t *testing.T) { { loadList := "" m, err := ParseLoadMap(loadList) test.S(t).ExpectNil(err) test.S(t).ExpectEquals(len(m), 0) } { loadList := "threads_running=20,threads_connected=10" m, err := ParseLoadMap(loadList) test.S(t).ExpectNil(err) test.S(t).ExpectEquals(len(m), 2) test.S(t).ExpectEquals(m["threads_running"], int64(20)) test.S(t).ExpectEquals(m["threads_connected"], int64(10)) } { loadList := "threads_running=20=30,threads_connected=10" _, err := ParseLoadMap(loadList) test.S(t).ExpectNotNil(err) } { loadList := "threads_running=20,threads_connected" _, err := ParseLoadMap(loadList) test.S(t).ExpectNotNil(err) } }
func TestRecoveryPeriodBlock(t *testing.T) { { c := newConfiguration() c.RecoveryPeriodBlockSeconds = 0 c.RecoveryPeriodBlockMinutes = 0 err := c.postReadAdjustments() test.S(t).ExpectNil(err) test.S(t).ExpectEquals(c.RecoveryPeriodBlockSeconds, 0) } { c := newConfiguration() c.RecoveryPeriodBlockSeconds = 30 c.RecoveryPeriodBlockMinutes = 1 err := c.postReadAdjustments() test.S(t).ExpectNil(err) test.S(t).ExpectEquals(c.RecoveryPeriodBlockSeconds, 30) } { c := newConfiguration() c.RecoveryPeriodBlockSeconds = 0 c.RecoveryPeriodBlockMinutes = 2 err := c.postReadAdjustments() test.S(t).ExpectNil(err) test.S(t).ExpectEquals(c.RecoveryPeriodBlockSeconds, 120) } { c := newConfiguration() c.RecoveryPeriodBlockSeconds = 15 c.RecoveryPeriodBlockMinutes = 0 err := c.postReadAdjustments() test.S(t).ExpectNil(err) test.S(t).ExpectEquals(c.RecoveryPeriodBlockSeconds, 15) } }
func TestGetSynonymPath(t *testing.T) { api := HttpAPI{} { path := "relocate-slaves" synonym := api.getSynonymPath(path) test.S(t).ExpectEquals(synonym, "relocate-replicas") } { path := "relocate-slaves/:host/:port" synonym := api.getSynonymPath(path) test.S(t).ExpectEquals(synonym, "relocate-replicas/:host/:port") } }
func TestKnownCommands(t *testing.T) { Cli("help", false, "localhost:9999", "localhost:9999", "orc", "no-reason", "1m", ".", "no-alias", "no-pool", "") commandsMap := make(map[string]string) for _, command := range knownCommands { commandsMap[command.Command] = command.Section } test.S(t).ExpectEquals(commandsMap["no-such-command"], "") test.S(t).ExpectEquals(commandsMap["relocate"], "Smart relocation") test.S(t).ExpectEquals(commandsMap["relocate-slaves"], "") test.S(t).ExpectEquals(commandsMap["relocate-replicas"], "Smart relocation") for _, synonym := range commandSynonyms { test.S(t).ExpectNotEquals(commandsMap[synonym], "") } }
func TestEscapeName(t *testing.T) { names := []string{"my_table", `"my_table"`, "`my_table`"} for _, name := range names { escaped := EscapeName(name) test.S(t).ExpectEquals(escaped, "`my_table`") } }
func TestInstanceKeyMapToCommaDelimitedList(t *testing.T) { m := *NewInstanceKeyMap() m.AddKey(key1) m.AddKey(key2) res := m.ToCommaDelimitedList() ok := (res == `host1:3306,host2:3306`) || (res == `host2:3306,host1:3306`) test.S(t).ExpectTrue(ok) }
func TestIsGenerallyValidAsCandidateReplica(t *testing.T) { instances, _ := generateTestInstances() for _, instance := range instances { test.S(t).ExpectFalse(isGenerallyValidAsCandidateReplica(instance)) } for _, instance := range instances { instance.IsLastCheckValid = true instance.LogBinEnabled = true instance.LogSlaveUpdatesEnabled = false } for _, instance := range instances { test.S(t).ExpectFalse(isGenerallyValidAsCandidateReplica(instance)) } applyGeneralGoodToGoReplicationParams(instances) for _, instance := range instances { test.S(t).ExpectTrue(isGenerallyValidAsCandidateReplica(instance)) } }
func TestChooseCandidateReplicaNoCandidateReplica(t *testing.T) { instances, _ := generateTestInstances() for _, instance := range instances { instance.IsLastCheckValid = true instance.LogBinEnabled = true instance.LogSlaveUpdatesEnabled = false } _, _, _, _, _, err := chooseCandidateReplica(instances) test.S(t).ExpectNotNil(err) }
func TestBuildSetPreparedClause(t *testing.T) { { columns := []string{"c1"} clause, err := BuildSetPreparedClause(columns) test.S(t).ExpectNil(err) test.S(t).ExpectEquals(clause, "`c1`=?") } { columns := []string{"c1", "c2"} clause, err := BuildSetPreparedClause(columns) test.S(t).ExpectNil(err) test.S(t).ExpectEquals(clause, "`c1`=?, `c2`=?") } { columns := []string{} _, err := BuildSetPreparedClause(columns) test.S(t).ExpectNotNil(err) } }
func TestParseAlterStatementNonTrivial(t *testing.T) { statements := []string{ `add column b bigint, change f fl float, change i count int, engine=innodb`, "add column b bigint, change column `f` fl float, change `i` `count` int, engine=innodb", "add column b bigint, change column `f` fl float, change `i` `count` int, change ts ts timestamp, engine=innodb", `change f fl float, CHANGE COLUMN i count int, engine=innodb`, } for _, statement := range statements { parser := NewParser() err := parser.ParseAlterStatement(statement) test.S(t).ExpectNil(err) renames := parser.GetNonTrivialRenames() test.S(t).ExpectEquals(len(renames), 2) test.S(t).ExpectEquals(renames["i"], "count") test.S(t).ExpectEquals(renames["f"], "fl") } }