func TestRowReplication(t *testing.T) {
	newConnection := myreplication.NewConnection()
	serverId := uint32(2)
	err := newConnection.ConnectAndAuth(HOST, PORT, REPLICATION_USERNAME, REPLICATION_PASSWORD)

	if err != nil {
		t.Fatal("Client not connected and not autentificate to master server with error:", err.Error())
	}
	pos, filename, err := newConnection.GetMasterStatus()

	if err != nil {
		t.Fatal("Master status fail: ", err.Error())
	}

	el, err := newConnection.StartBinlogDump(pos, filename, serverId)

	if err != nil {
		t.Fatal("Cant start bin log: ", err.Error())
	}
	events := el.GetEventChan()

	go func() {
		con, err := sql.Open("mysql", fmt.Sprintf(
			"%s:%s@tcp(%s:%d)/%s",
			REPLICATION_USERNAME,
			REPLICATION_PASSWORD,
			HOST,
			PORT,
			DATABASE,
		))
		defer con.Close()
		if err != nil {
			t.Fatal(err.Error())
		}

		_, err = con.Exec("TRUNCATE new_table")
		if err != nil {
			t.Fatal(err.Error())
		}
		query := (<-events).(*myreplication.QueryEvent).GetQuery()
		expectedQuery := "TRUNCATE new_table"

		if expectedQuery != query {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect query", "expected", expectedQuery, "got", query)
		}

		maxId := 1
		expectedTable := "new_table"
		expectedSchema := "test"

		t.Log("Write test")

		con.Exec("INSERT INTO new_table(text_field, num_field) values(?,?)", "Hello!", 10)

		expectedQuery = "BEGIN"

		query = (<-events).(*myreplication.QueryEvent).GetQuery()

		if expectedQuery != query {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect query", "expected", expectedQuery, "got", query)
		}

		writeQuery := (<-events).(*myreplication.WriteEvent)

		if expectedTable != writeQuery.GetTable() {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect table name", "expected", expectedTable, "got", writeQuery.GetTable())
		}

		if expectedSchema != writeQuery.GetSchema() {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect schema", "expected", expectedSchema, "got", writeQuery.GetTable())
		}

		rows := writeQuery.GetRows()

		expectedRowsCount := 1
		if expectedRowsCount != len(rows) {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect rows count", "expected", expectedRowsCount, "got", len(rows))
		}

		columns := rows[0]
		expectedColumnsCount := 3

		if expectedColumnsCount != len(columns) {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect columns count", "expected", expectedColumnsCount, "got", len(columns))
		}

		tests := []*columnTest{
			&columnTest{0, myreplication.MYSQL_TYPE_LONG, uint32(maxId), false},
			&columnTest{1, myreplication.MYSQL_TYPE_VARCHAR, "Hello!", false},
			&columnTest{2, myreplication.MYSQL_TYPE_LONG, uint32(10), false},
		}

		for i, column := range columns {
			if tests[i].columnId != column.GetColumnId() {
				newConnection.Connection().Close()
				t.Fatal(
					"Write event. Got incorrect column id at column",
					i, "expected", tests[i].columnId, "got", column.GetColumnId(),
				)
			}

			if tests[i].columnType != column.GetType() {
				newConnection.Connection().Close()
				t.Fatal(
					"Write event. Got incorrect column type at column",
					i, "expected", tests[i].columnType, "got", column.GetType(),
				)
			}

			if tests[i].isNil != column.IsNil() {
				newConnection.Connection().Close()
				t.Fatal(
					"Write event. Got column nil value incorrect",
					i, "expected", tests[i].isNil, "got", column.IsNil(),
				)
			}

			if column.IsNil() {
				continue
			}

			if !reflect.DeepEqual(tests[i].columnValue, column.GetValue()) {
				newConnection.Connection().Close()
				t.Fatal(
					"Write event. Got incorrect column value at column",
					i, "expected", tests[i].columnValue, "got", column.GetValue(),
				)
			}
		}

		t.Log("Update test")
		_, err = con.Exec("UPDATE new_table SET text_field = ? WHERE id = ?", "World!", maxId)

		if err != nil {
			newConnection.Connection().Close()
			t.Fatal(err.Error())
		}

		expectedQuery = "BEGIN"

		query = (<-events).(*myreplication.QueryEvent).GetQuery()

		if expectedQuery != query {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect query", "expected", expectedQuery, "got", query)
		}

		updateEvent := (<-events).(*myreplication.UpdateEvent)

		if expectedTable != updateEvent.GetTable() {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect table name", "expected", expectedTable, "got", writeQuery.GetTable())
		}

		if expectedSchema != updateEvent.GetSchema() {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect schema", "expected", expectedSchema, "got", writeQuery.GetTable())
		}

		t.Log("Update test: check old row version")

		rows = updateEvent.GetRows()
		expectedRowsCount = 1
		if expectedRowsCount != len(rows) {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect rows count", "expected", expectedRowsCount, "got", len(rows))
		}

		columns = rows[0]
		expectedColumnsCount = 3

		if expectedColumnsCount != len(columns) {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect columns count", "expected", expectedColumnsCount, "got", len(columns))
		}

		for i, column := range columns {
			if tests[i].columnId != column.GetColumnId() {
				newConnection.Connection().Close()
				t.Fatal(
					"Update event. Got incorrect column id at column",
					i, "expected", tests[i].columnId, "got", column.GetColumnId(),
				)
			}

			if tests[i].columnType != column.GetType() {
				newConnection.Connection().Close()
				t.Fatal(
					"Update event. Got incorrect column type at column",
					i, "expected", tests[i].columnType, "got", column.GetType(),
				)
			}

			if tests[i].isNil != column.IsNil() {
				newConnection.Connection().Close()
				t.Fatal(
					"Update event. Got column nil value incorrect",
					i, "expected", tests[i].isNil, "got", column.IsNil(),
				)
			}

			if column.IsNil() {
				continue
			}

			if !reflect.DeepEqual(tests[i].columnValue, column.GetValue()) {
				newConnection.Connection().Close()
				t.Fatal(
					"Update event. Got incorrect column value at column",
					i, "expected", tests[i].columnValue, "got", column.GetValue(),
				)
			}
		}

		t.Log("Update test: check new row version")

		rows = updateEvent.GetNewRows()
		expectedRowsCount = 1
		if expectedRowsCount != len(rows) {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect rows count", "expected", expectedRowsCount, "got", len(rows))
		}

		columns = rows[0]
		expectedColumnsCount = 3

		if expectedColumnsCount != len(columns) {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect columns count", "expected", expectedColumnsCount, "got", len(columns))
		}

		tests = []*columnTest{
			&columnTest{0, myreplication.MYSQL_TYPE_LONG, uint32(maxId), false},
			&columnTest{1, myreplication.MYSQL_TYPE_VARCHAR, "World!", false},
			&columnTest{2, myreplication.MYSQL_TYPE_LONG, uint32(10), false},
		}

		for i, column := range columns {
			if tests[i].columnId != column.GetColumnId() {
				newConnection.Connection().Close()
				t.Fatal(
					"Update event. Got incorrect column id at column",
					i, "expected", tests[i].columnId, "got", column.GetColumnId(),
				)
			}

			if tests[i].columnType != column.GetType() {
				newConnection.Connection().Close()
				t.Fatal(
					"Update event. Got incorrect column type at column",
					i, "expected", tests[i].columnType, "got", column.GetType(),
				)
			}

			if tests[i].isNil != column.IsNil() {
				newConnection.Connection().Close()
				t.Fatal(
					"Update event. Got column nil value incorrect",
					i, "expected", tests[i].isNil, "got", column.IsNil(),
				)
			}

			if column.IsNil() {
				continue
			}

			if !reflect.DeepEqual(tests[i].columnValue, column.GetValue()) {
				newConnection.Connection().Close()
				t.Fatal(
					"Update event. Got incorrect column value at column",
					i, "expected", tests[i].columnValue, "got", column.GetValue(),
				)
			}
		}

		t.Log("Delete test")

		_, err = con.Exec("DELETE FROM new_table WHERE id = ?", maxId)
		if err != nil {
			newConnection.Connection().Close()
			t.Fatal(err.Error())
		}

		expectedQuery = "BEGIN"

		query = (<-events).(*myreplication.QueryEvent).GetQuery()
		if expectedQuery != query {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect query", "expected", expectedQuery, "got", query)
		}

		deleteEvent := (<-events).(*myreplication.DeleteEvent)

		if expectedTable != deleteEvent.GetTable() {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect table name", "expected", expectedTable, "got", writeQuery.GetTable())
		}

		if expectedSchema != deleteEvent.GetSchema() {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect schema", "expected", expectedSchema, "got", writeQuery.GetTable())
		}

		rows = deleteEvent.GetRows()
		expectedRowsCount = 1
		if expectedRowsCount != len(rows) {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect rows count", "expected", expectedRowsCount, "got", len(rows))
		}

		columns = rows[0]
		expectedColumnsCount = 3

		if expectedColumnsCount != len(columns) {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect columns count", "expected", expectedColumnsCount, "got", len(columns))
		}

		for i, column := range columns {
			if tests[i].columnId != column.GetColumnId() {
				newConnection.Connection().Close()
				t.Fatal(
					"Delete event. Got incorrect column id at column",
					i, "expected", tests[i].columnId, "got", column.GetColumnId(),
				)
			}

			if tests[i].columnType != column.GetType() {
				newConnection.Connection().Close()
				t.Fatal(
					"Delete event. Got incorrect column type at column",
					i, "expected", tests[i].columnType, "got", column.GetType(),
				)
			}

			if tests[i].isNil != column.IsNil() {
				newConnection.Connection().Close()
				t.Fatal(
					"Delete event. Got column nil value incorrect",
					i, "expected", tests[i].isNil, "got", column.IsNil(),
				)
			}

			if column.IsNil() {
				continue
			}

			if !reflect.DeepEqual(tests[i].columnValue, column.GetValue()) {
				newConnection.Connection().Close()
				t.Fatal(
					"Delete event. Got incorrect column value at column",
					i, "expected", tests[i].columnValue, "got", column.GetValue(),
				)
			}
		}

		os.Exit(0)
	}()

	err = el.Start()

	if err != nil {
		t.Fatal("Start error", err)
	}
}
func TestStatementReplication(t *testing.T) {
	newConnection := myreplication.NewConnection()
	serverId := uint32(2)
	err := newConnection.ConnectAndAuth(HOST, PORT, REPLICATION_USERNAME, REPLICATION_PASSWORD)

	if err != nil {
		t.Fatal("Client not connected and not autentificate to master server with error:", err.Error())
	}
	pos, filename, err := newConnection.GetMasterStatus()

	if err != nil {
		t.Fatal("Master status fail: ", err.Error())
	}

	el, err := newConnection.StartBinlogDump(pos, filename, serverId)

	if err != nil {
		t.Fatal("Cant start bin log: ", err.Error())
	}
	events := el.GetEventChan()

	go func() {
		con, err := sql.Open("mysql", fmt.Sprintf(
			"%s:%s@tcp(%s:%d)/%s",
			REPLICATION_USERNAME,
			REPLICATION_PASSWORD,
			HOST,
			PORT,
			DATABASE,
		))
		defer con.Close()
		if err != nil {
			t.Fatal(err)
		}

		r, err := con.Query("SELECT max(id) FROM new_table")
		var maxId uint64

		if r.Next() {
			r.Scan(&maxId)
		}

		con.Exec("INSERT INTO new_table(text_field, num_field) values(?,?)", "Hello!", 10)

		expectedQuery := "BEGIN"

		if expectedQuery != (<-events).(*myreplication.QueryEvent).GetQuery() {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect query")
		}

		if (<-events).(*myreplication.IntVarEvent).GetValue() != (maxId + 1) {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect IntEvent")
		}

		expectedQuery = "INSERT INTO new_table(text_field, num_field) values('Hello!',10)"

		if expectedQuery != (<-events).(*myreplication.QueryEvent).GetQuery() {
			newConnection.Connection().Close()
			t.Fatal("Got incorrect query")
		}

		os.Exit(0)
	}()

	err = el.Start()

	if err != nil {
		t.Fatal("Start error", err)
	}
}
Example #3
0
func main() {
	newConnection := myreplication.NewConnection()
	serverId := uint32(2)
	err := newConnection.ConnectAndAuth(host, port, username, password)

	if err != nil {
		panic("Client not connected and not autentificate to master server with error:" + err.Error())
	}
	//Get position and file name
	pos, filename, err := newConnection.GetMasterStatus()

	if err != nil {
		panic("Master status fail: " + err.Error())
	}

	el, err := newConnection.StartBinlogDump(pos, filename, serverId)

	if err != nil {
		panic("Cant start bin log: " + err.Error())
	}
	events := el.GetEventChan()
	go func() {
		for {
			event := <-events

			switch e := event.(type) {
			case *myreplication.QueryEvent:
				//Output query event
				println(e.GetQuery())
			case *myreplication.IntVarEvent:
				//Output last insert_id  if statement based replication
				println(e.GetValue())
			case *myreplication.WriteEvent:
				//Output Write (insert) event
				println("Write", e.GetTable())
				//Rows loop
				for i, row := range e.GetRows() {
					//Columns loop
					for j, col := range row {
						//Output row number, column number, column type and column value
						println(fmt.Sprintf("%d %d %d %v", i, j, col.GetType(), col.GetValue()))
					}
				}
			case *myreplication.DeleteEvent:
				//Output delete event
				println("Delete", e.GetTable())
				for i, row := range e.GetRows() {
					for j, col := range row {
						println(fmt.Sprintf("%d %d %d %v", i, j, col.GetType(), col.GetValue()))
					}
				}
			case *myreplication.UpdateEvent:
				//Output update event
				println("Update", e.GetTable())
				//Output old data before update
				for i, row := range e.GetRows() {
					for j, col := range row {
						println(fmt.Sprintf("%d %d %d %v", i, j, col.GetType(), col.GetValue()))
					}
				}
				//Output new
				for i, row := range e.GetNewRows() {
					for j, col := range row {
						println(fmt.Sprintf("%d %d %d %v", i, j, col.GetType(), col.GetValue()))
					}
				}
			default:
			}
		}
	}()
	err = el.Start()
	println(err.Error())
}