2026-03-19 17:04:35 +08:00
|
|
|
package binlog
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
"github.com/starainrt/go-mysql/mysql"
|
|
|
|
|
"github.com/starainrt/go-mysql/replication"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestParseBinlogEvent_TableMapEvent(t *testing.T) {
|
|
|
|
|
ev := &replication.BinlogEvent{
|
|
|
|
|
Header: &replication.EventHeader{EventType: replication.TABLE_MAP_EVENT},
|
|
|
|
|
Event: &replication.TableMapEvent{
|
|
|
|
|
Schema: []byte("db1"),
|
|
|
|
|
Table: []byte("tb1"),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
events := ParseBinlogEvent(ev)
|
|
|
|
|
if len(events) != 1 {
|
|
|
|
|
t.Fatalf("expected 1 event, got %d", len(events))
|
|
|
|
|
}
|
|
|
|
|
if events[0].Type != "tablemap" {
|
|
|
|
|
t.Fatalf("expected tablemap event type, got %q", events[0].Type)
|
|
|
|
|
}
|
|
|
|
|
if events[0].DB != "db1" || events[0].TB != "tb1" {
|
|
|
|
|
t.Fatalf("unexpected db/table: %s.%s", events[0].DB, events[0].TB)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestParseBinlogEvent_TransactionPayloadContainsTableMap(t *testing.T) {
|
|
|
|
|
table := &replication.TableMapEvent{
|
|
|
|
|
Schema: []byte("db2"),
|
|
|
|
|
Table: []byte("tb2"),
|
|
|
|
|
ColumnType: []byte{mysql.MYSQL_TYPE_LONG},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
payload := &replication.TransactionPayloadEvent{
|
|
|
|
|
CompressionType: CompressionZSTD,
|
|
|
|
|
Events: []*replication.BinlogEvent{
|
|
|
|
|
{
|
|
|
|
|
Header: &replication.EventHeader{EventType: replication.TABLE_MAP_EVENT},
|
|
|
|
|
Event: table,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Header: &replication.EventHeader{EventType: replication.WRITE_ROWS_EVENTv2},
|
|
|
|
|
Event: &replication.RowsEvent{
|
|
|
|
|
Table: table,
|
|
|
|
|
Rows: [][]interface{}{{int32(1)}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ev := &replication.BinlogEvent{
|
|
|
|
|
Header: &replication.EventHeader{EventType: replication.TRANSACTION_PAYLOAD_EVENT},
|
|
|
|
|
Event: payload,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
events := ParseBinlogEvent(ev)
|
|
|
|
|
if len(events) != 2 {
|
|
|
|
|
t.Fatalf("expected 2 events from payload, got %d", len(events))
|
|
|
|
|
}
|
|
|
|
|
if events[0].Type != "tablemap" {
|
|
|
|
|
t.Fatalf("expected first payload event to be tablemap, got %q", events[0].Type)
|
|
|
|
|
}
|
|
|
|
|
if events[1].Type != "insert" {
|
|
|
|
|
t.Fatalf("expected second payload event to be insert, got %q", events[1].Type)
|
|
|
|
|
}
|
|
|
|
|
if events[0].CompressionType != "ZSTD" || events[1].CompressionType != "ZSTD" {
|
|
|
|
|
t.Fatalf("expected payload events to carry compression type, got %q/%q", events[0].CompressionType, events[1].CompressionType)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-05-10 14:02:53 +08:00
|
|
|
|
|
|
|
|
func TestParseBinlogEvent_NilInput(t *testing.T) {
|
|
|
|
|
if got := ParseBinlogEvent(nil); got != nil {
|
|
|
|
|
t.Fatalf("expected nil for nil event, got %#v", got)
|
|
|
|
|
}
|
|
|
|
|
if got := ParseBinlogEvent(&replication.BinlogEvent{}); got != nil {
|
|
|
|
|
t.Fatalf("expected nil for missing header, got %#v", got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestParseBinlogEvent_GTIDMetadata(t *testing.T) {
|
|
|
|
|
ev := &replication.BinlogEvent{
|
|
|
|
|
Header: &replication.EventHeader{
|
|
|
|
|
EventType: replication.GTID_EVENT,
|
|
|
|
|
ServerID: 12,
|
|
|
|
|
Timestamp: 123456,
|
|
|
|
|
LogPos: 456,
|
|
|
|
|
EventSize: 64,
|
|
|
|
|
},
|
|
|
|
|
Event: &replication.GTIDEvent{
|
|
|
|
|
SID: []byte{0x74, 0xde, 0xc5, 0xa0, 0x3a, 0xc7, 0x11, 0xf0, 0xba, 0x0c, 0xfa, 0x16, 0x3e, 0xea, 0x29, 0x9f},
|
|
|
|
|
GNO: 42,
|
|
|
|
|
LastCommitted: 40,
|
|
|
|
|
SequenceNumber: 42,
|
|
|
|
|
TransactionLength: 2048,
|
|
|
|
|
ImmediateCommitTimestamp: 1700000000000001,
|
|
|
|
|
OriginalCommitTimestamp: 1700000000000000,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
events := ParseBinlogEvent(ev)
|
|
|
|
|
if len(events) != 1 {
|
|
|
|
|
t.Fatalf("expected 1 event, got %d", len(events))
|
|
|
|
|
}
|
|
|
|
|
got := events[0]
|
|
|
|
|
if got.Type != "gtid" {
|
|
|
|
|
t.Fatalf("expected gtid event, got %q", got.Type)
|
|
|
|
|
}
|
|
|
|
|
if got.LastCommitted != 40 || got.SequenceNumber != 42 || got.TransactionLength != 2048 {
|
|
|
|
|
t.Fatalf("logical metadata mismatch: last=%d seq=%d len=%d", got.LastCommitted, got.SequenceNumber, got.TransactionLength)
|
|
|
|
|
}
|
|
|
|
|
if got.ImmediateCommitTimestamp != 1700000000000001 || got.OriginalCommitTimestamp != 1700000000000000 {
|
|
|
|
|
t.Fatalf("commit timestamps mismatch: immediate=%d original=%d", got.ImmediateCommitTimestamp, got.OriginalCommitTimestamp)
|
|
|
|
|
}
|
|
|
|
|
if got.ServerID != 12 || got.Timestamp != 123456 || got.LogPos != 456 || got.EventSize != 64 {
|
|
|
|
|
t.Fatalf("header metadata mismatch: %#v", got)
|
|
|
|
|
}
|
|
|
|
|
}
|