//go:build mysql package mysql import ( "database/sql" "strings" "testing" ) type recordingGroupSchemaExecutor struct { statements []string } func (e *recordingGroupSchemaExecutor) Exec(query string, _ ...any) (sql.Result, error) { e.statements = append(e.statements, query) return nil, nil } func TestEnsureIMGroupBusinessTablesUsesSelectedTenantDatabase(t *testing.T) { exec := &recordingGroupSchemaExecutor{} if err := ensureIMGroupBusinessTables(exec); err != nil { t.Fatal(err) } if len(exec.statements) != 25 { t.Fatalf("executed %d group schema statements, want 25", len(exec.statements)) } for _, statement := range exec.statements { if strings.Contains(strings.ToLower(statement), "tinode.") || strings.Contains(strings.ToLower(statement), "create database") { t.Fatalf("group schema must use the selected tenant database: %s", statement) } } joined := strings.ToLower(strings.Join(exec.statements, "\n")) if strings.Contains(joined, "im_group_events_outbox") { t.Fatal("group event outbox table must not be created") } for _, expected := range []string{ "primary key(id), unique index uk_im_group_settings_topic(topic)", "primary key(id), unique index uk_im_group_announcement_reads_announcement_user(announcement_id, user_id)", "primary key(id), unique index uk_im_group_mutes_topic_user(topic, user_id)", } { if !strings.Contains(joined, expected) { t.Fatalf("group schema is missing snowflake primary-key definition %q", expected) } } if !strings.Contains(joined, "json_set(public, '$.fn'") { t.Fatal("group schema is missing historical public.fn backfill") } for _, expected := range []string{"im_group_message_shards", "im_group_message_topic_shards", "im_group_message_dedup", "primary key(message_id)"} { if !strings.Contains(joined, expected) { t.Fatalf("group shard schema is missing %q", expected) } } } func TestGroupMessageShardTableRejectsUnsafeMonth(t *testing.T) { if table, ok := groupMessageShardTable("202609"); !ok || table != "im_group_messages_202609" { t.Fatalf("unexpected valid shard: table=%q ok=%v", table, ok) } for _, month := range []string{"", "20269", "202613", "2026_09", "202609;DROP TABLE im_users"} { if table, ok := groupMessageShardTable(month); ok || table != "" { t.Fatalf("unsafe shard month accepted: month=%q table=%q", month, table) } } }