topfans/backend/services/statisticService/worker/materializer_test.go
zerosaturation bed8f8e578 feat(statistic): T4-T8 event collection framework (Event + Sink + Repo + Service + Workers)
- Event model + ToJSON
- EventSink interface + ChannelEventSink (non-blocking Submit)
- event_repo: batch INSERT ON CONFLICT DO NOTHING dedup
- event_service: 7-type whitelist + 1KB props limit + ReceivedAt auto-fill
- event_flusher: 100/1s batch + sync metric_recent_level_ups on level_up
- metric_weekly + metric_upcoming workers (5min/15min with pg_try_advisory_lock)
- partitioner: 7-day pre-create + 30-day cleanup (00:05 create / 00:30 cleanup)
- 22 unit + integration tests (model/repo/service/sink/worker)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 17:20:53 +08:00

66 lines
1.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package worker
import (
"context"
"database/sql"
"fmt"
"os"
"testing"
_ "github.com/lib/pq"
)
func setupMaterializerDB(t *testing.T) (*sql.DB, string, func()) {
dsn := os.Getenv("TEST_DATABASE_URL")
if dsn == "" {
t.Skip("TEST_DATABASE_URL not set")
}
db, err := sql.Open("postgres", dsn)
if err != nil {
t.Fatal(err)
}
if err := db.Ping(); err != nil {
t.Skipf("DB ping failed: %v", err)
}
schema := "statistic_test_mat_" + sanitizeName(t.Name())
db.Exec("CREATE SCHEMA IF NOT EXISTS " + schema)
// refresh_log 表MV DDL 不需要建,因为只测 RefreshOne 对 refresh_log 的写)
db.Exec(fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s.refresh_log (
id BIGSERIAL PRIMARY KEY,
mv_name VARCHAR(128) NOT NULL,
started_at TIMESTAMPTZ NOT NULL,
finished_at TIMESTAMPTZ,
row_count BIGINT,
status VARCHAR(16) NOT NULL,
error_message TEXT
)`, schema))
cleanup := func() {
db.Exec("DROP SCHEMA IF EXISTS " + schema + " CASCADE")
db.Close()
}
return db, schema, cleanup
}
func TestMaterializer_RefreshOne_LogsToRefreshLog(t *testing.T) {
db, schema, cleanup := setupMaterializerDB(t)
defer cleanup()
m := NewMaterializer(db, schema)
// 用一个不存在的 MV 名(期望失败但 refresh_log 仍写入)
err := m.RefreshOne(context.Background(), "mv_does_not_exist")
if err == nil {
t.Fatal("expected error for non-existent MV")
}
// 验证 refresh_log 有 failed 记录
var status string
if err := db.QueryRow(
"SELECT status FROM "+schema+`.refresh_log WHERE mv_name='mv_does_not_exist' ORDER BY id DESC LIMIT 1`,
).Scan(&status); err != nil {
t.Fatal(err)
}
if status != "failed" {
t.Fatalf("expected status=failed, got %s", status)
}
}