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) } } 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) } }