- 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>
43 lines
961 B
Go
43 lines
961 B
Go
package model
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestEvent_ToJSON(t *testing.T) {
|
|
e := &Event{
|
|
EventID: "uuid-123",
|
|
UserID: 100,
|
|
StarID: 1,
|
|
EventType: "asset.like",
|
|
OccurredAt: time.Unix(1700000000, 0),
|
|
ReceivedAt: time.Unix(1700000001, 0),
|
|
Properties: map[string]string{"asset_id": "456"},
|
|
}
|
|
j := e.ToJSON()
|
|
if j["event_id"] != "uuid-123" {
|
|
t.Fatal("event_id mismatch")
|
|
}
|
|
if j["user_id"].(int64) != 100 {
|
|
t.Fatal("user_id mismatch")
|
|
}
|
|
if j["event_type"] != "asset.like" {
|
|
t.Fatal("event_type mismatch")
|
|
}
|
|
if j["properties"].(map[string]string)["asset_id"] != "456" {
|
|
t.Fatal("properties mismatch")
|
|
}
|
|
if j["occurred_at"].(int64) != 1700000000*1000 {
|
|
t.Fatalf("occurred_at millis = %v, want %d", j["occurred_at"], 1700000000*1000)
|
|
}
|
|
}
|
|
|
|
func TestEvent_ToJSON_EmptyProperties(t *testing.T) {
|
|
e := &Event{EventID: "e1"}
|
|
j := e.ToJSON()
|
|
if j["properties"] == nil {
|
|
t.Fatal("properties should not be nil")
|
|
}
|
|
}
|