package db import ( "testing" "time" ) // TestWebhookLastFiredAtRoundTrip exercises the new last_fired_at column added // for edge-triggered dispatch (currently quota webhooks). func TestWebhookLastFiredAtRoundTrip(t *testing.T) { db, err := InitDB(":memory:", LibsqlConfig{}) if err != nil { t.Fatalf("init db: %v", err) } defer db.Close() user := &User{ DID: "did:plc:webhooktest", Handle: "wh.test", PDSEndpoint: "https://pds.example", LastSeen: time.Now(), } if err := UpsertUser(db, user); err != nil { t.Fatalf("upsert user: %v", err) } // Insert a webhook with packed triggers (TriggerPush=0x08 | TriggerQuota=0x40, // threshold 90 in bits 8-15 => 0x5A48). We deliberately use the raw int to // avoid coupling this test to the webhooks package import. const packedTriggers = 0x5A48 wh := &Webhook{ ID: "wh-1", UserDID: user.DID, URL: "https://hook.example/quota", Secret: "topsecret", Triggers: packedTriggers, CreatedAt: time.Now().UTC(), } if err := InsertWebhook(db, wh); err != nil { t.Fatalf("insert webhook: %v", err) } got, err := GetWebhookByID(db, wh.ID) if err != nil { t.Fatalf("get by id: %v", err) } if got.Triggers != packedTriggers { t.Errorf("Triggers round-trip: got %#x, want %#x", got.Triggers, packedTriggers) } if got.LastFiredAt != nil { t.Errorf("LastFiredAt should be nil on fresh insert, got %v", *got.LastFiredAt) } listed, err := ListWebhooks(db, user.DID) if err != nil { t.Fatalf("list: %v", err) } if len(listed) != 1 || listed[0].LastFiredAt != nil { t.Fatalf("ListWebhooks: got %+v", listed) } fired := time.Now().UTC().Truncate(time.Second) if err := UpdateWebhookLastFiredAt(db, wh.ID, fired); err != nil { t.Fatalf("update last_fired_at: %v", err) } got, err = GetWebhookByID(db, wh.ID) if err != nil { t.Fatalf("re-get: %v", err) } if got.LastFiredAt == nil { t.Fatal("LastFiredAt should be set after Update") } if !got.LastFiredAt.Equal(fired) { t.Errorf("LastFiredAt round-trip: got %v, want %v", got.LastFiredAt, fired) } forUser, err := GetWebhooksForUser(db, user.DID) if err != nil { t.Fatalf("for user: %v", err) } if len(forUser) != 1 || forUser[0].LastFiredAt == nil { t.Fatalf("GetWebhooksForUser should include LastFiredAt; got %+v", forUser) } if err := ClearWebhookLastFiredAt(db, wh.ID); err != nil { t.Fatalf("clear: %v", err) } got, err = GetWebhookByID(db, wh.ID) if err != nil { t.Fatalf("post-clear get: %v", err) } if got.LastFiredAt != nil { t.Errorf("LastFiredAt should be nil after Clear, got %v", *got.LastFiredAt) } }