package api import ( "palette/internal/store" "testing" "time" ) // insertPasteWithSlug creates a paste directly with a custom slug and controlled // created_at/expires_at, bypassing the API's timestamp handling. func insertPasteWithSlug(t *testing.T, s *store.Store, slug string, createdAt, expiresAt int64) string { t.Helper() id := store.GenSlug(6) if _, err := s.Exec(`INSERT INTO pastes (id, custom_slug, content, content_type, created_at, expires_at) VALUES (?, ?, ?, ?, ?, ?)`, id, slug, "x", "text/plain", createdAt, expiresAt); err != nil { t.Fatal(err) } return id } func strPtr(s string) *string { return &s } func TestReleaseSlugOnExpiredPaste(t *testing.T) { s := testServer(t) now := time.Now().Unix() insertPasteWithSlug(t, s.store, "release-notes", now-3600, now-60) if n, err := s.store.ReleaseCustomSlugs(store.SlugReservationDays); err != nil || n != 1 { t.Fatalf("released %d err %v, want 1", n, err) } if taken, _ := s.store.SlugTaken("release-notes"); taken { t.Fatal("slug should be released after expiry") } // slug must be reusable by a new paste p, err := s.store.CreatePaste(&store.Paste{Content: "new", CustomSlug: strPtr("release-notes")}) if err != nil { t.Fatalf("reuse slug: %v", err) } if p.CustomSlug == nil || *p.CustomSlug != "release-notes" { t.Fatal("new paste did not claim released slug") } } func TestReleaseSlugOnOldPaste(t *testing.T) { s := testServer(t) now := time.Now().Unix() // created 31 days ago, no expiry -> released by 30-day reservation rule insertPasteWithSlug(t, s.store, "old-url", now-31*86400, 0) if n, err := s.store.ReleaseCustomSlugs(store.SlugReservationDays); err != nil || n != 1 { t.Fatalf("released %d err %v, want 1", n, err) } if taken, _ := s.store.SlugTaken("old-url"); taken { t.Fatal("slug should be released after 30-day reservation") } } func TestKeepSlugOnRecentUnexpiredPaste(t *testing.T) { s := testServer(t) now := time.Now().Unix() insertPasteWithSlug(t, s.store, "fresh-url", now-3600, now+86400) insertPasteWithSlug(t, s.store, "fresh-url2", now-3600, 0) if n, err := s.store.ReleaseCustomSlugs(store.SlugReservationDays); err != nil || n != 0 { t.Fatalf("released %d err %v, want 0", n, err) } for _, slug := range []string{"fresh-url", "fresh-url2"} { if taken, _ := s.store.SlugTaken(slug); !taken { t.Fatalf("slug %q should still be held", slug) } } } func TestSweeperTickerReleasesSlugs(t *testing.T) { s := testServer(t) now := time.Now().Unix() insertPasteWithSlug(t, s.store, "ticker-url", now-7200, now-3600) s.store.StartSweeper(10*time.Millisecond, store.SlugReservationDays) deadline := time.Now().Add(2 * time.Second) for time.Now().Before(deadline) { if taken, _ := s.store.SlugTaken("ticker-url"); !taken { return } time.Sleep(10 * time.Millisecond) } t.Fatal("ticker did not release slug in time") }