mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-08-29 12:17:00 +00:00
192 lines
4.4 KiB
Go
192 lines
4.4 KiB
Go
package labeler
|
|
|
|
import (
|
|
"database/sql"
|
|
"testing"
|
|
"time"
|
|
|
|
_ "github.com/tursodatabase/go-libsql"
|
|
)
|
|
|
|
func newTestCache(t *testing.T) *Cache {
|
|
t.Helper()
|
|
db, err := sql.Open("libsql", ":memory:")
|
|
if err != nil {
|
|
t.Fatalf("open in-memory db: %v", err)
|
|
}
|
|
t.Cleanup(func() { _ = db.Close() })
|
|
|
|
c, err := NewCache(db)
|
|
if err != nil {
|
|
t.Fatalf("NewCache: %v", err)
|
|
}
|
|
return c
|
|
}
|
|
|
|
func TestCacheSetAndIsTakenDown(t *testing.T) {
|
|
c := newTestCache(t)
|
|
uri := "at://did:plc:alice/io.atcr.manifest/abc"
|
|
cts := time.Now().UTC().Add(-time.Hour)
|
|
|
|
if _, ok := c.IsTakenDown(uri); ok {
|
|
t.Fatalf("expected not taken down before Set")
|
|
}
|
|
if err := c.Set(uri, "did:web:labeler", cts); err != nil {
|
|
t.Fatalf("Set: %v", err)
|
|
}
|
|
|
|
got, ok := c.IsTakenDown(uri)
|
|
if !ok {
|
|
t.Fatalf("expected taken down after Set")
|
|
}
|
|
if !got.Equal(cts) {
|
|
t.Fatalf("cts = %v, want %v", got, cts)
|
|
}
|
|
}
|
|
|
|
func TestCacheNegateRemovesEntry(t *testing.T) {
|
|
c := newTestCache(t)
|
|
uri := "at://did:plc:alice/io.atcr.manifest/abc"
|
|
if err := c.Set(uri, "did:web:labeler", time.Now()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := c.Negate(uri); err != nil {
|
|
t.Fatalf("Negate: %v", err)
|
|
}
|
|
if _, ok := c.IsTakenDown(uri); ok {
|
|
t.Fatalf("expected not taken down after Negate")
|
|
}
|
|
}
|
|
|
|
func TestCacheUserLevelTakedownAppliesToAllManifests(t *testing.T) {
|
|
c := newTestCache(t)
|
|
userURI := "at://did:plc:alice"
|
|
cts := time.Now().UTC()
|
|
|
|
if err := c.Set(userURI, "did:web:labeler", cts); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
manifestURI := "at://did:plc:alice/io.atcr.manifest/anything"
|
|
got, ok := c.IsTakenDown(manifestURI)
|
|
if !ok {
|
|
t.Fatalf("user-level takedown should apply to manifest URI")
|
|
}
|
|
if !got.Equal(cts) {
|
|
t.Fatalf("cts = %v, want %v", got, cts)
|
|
}
|
|
|
|
otherURI := "at://did:plc:bob/io.atcr.manifest/x"
|
|
if _, ok := c.IsTakenDown(otherURI); ok {
|
|
t.Fatalf("user-level takedown for alice must not affect bob")
|
|
}
|
|
}
|
|
|
|
func TestCacheChoosesEarliestCtsAcrossSources(t *testing.T) {
|
|
c := newTestCache(t)
|
|
earlier := time.Now().UTC().Add(-2 * time.Hour)
|
|
later := time.Now().UTC()
|
|
|
|
manifestURI := "at://did:plc:alice/io.atcr.manifest/x"
|
|
userURI := "at://did:plc:alice"
|
|
|
|
// Per-manifest later, user-level earlier — IsTakenDown should report the earlier one.
|
|
if err := c.Set(manifestURI, "did:web:labeler", later); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := c.Set(userURI, "did:web:labeler", earlier); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, ok := c.IsTakenDown(manifestURI)
|
|
if !ok {
|
|
t.Fatalf("expected taken down")
|
|
}
|
|
if !got.Equal(earlier) {
|
|
t.Fatalf("cts = %v, want earliest (%v)", got, earlier)
|
|
}
|
|
}
|
|
|
|
func TestCachePersistsAcrossInstances(t *testing.T) {
|
|
db, err := sql.Open("libsql", ":memory:")
|
|
if err != nil {
|
|
t.Fatalf("open: %v", err)
|
|
}
|
|
t.Cleanup(func() { _ = db.Close() })
|
|
|
|
first, err := NewCache(db)
|
|
if err != nil {
|
|
t.Fatalf("first NewCache: %v", err)
|
|
}
|
|
uri := "at://did:plc:alice/io.atcr.manifest/abc"
|
|
cts := time.Now().UTC()
|
|
if err := first.Set(uri, "did:web:labeler", cts); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// New cache instance, same DB — should warm-load entry.
|
|
second, err := NewCache(db)
|
|
if err != nil {
|
|
t.Fatalf("second NewCache: %v", err)
|
|
}
|
|
if _, ok := second.IsTakenDown(uri); !ok {
|
|
t.Fatalf("second cache should see persisted takedown")
|
|
}
|
|
}
|
|
|
|
func TestCacheCursorRoundTrip(t *testing.T) {
|
|
c := newTestCache(t)
|
|
const labeler = "did:web:labeler"
|
|
|
|
got, err := c.GetCursor(labeler)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != 0 {
|
|
t.Fatalf("initial cursor = %d, want 0", got)
|
|
}
|
|
|
|
if err := c.SetCursor(labeler, 42); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err = c.GetCursor(labeler)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != 42 {
|
|
t.Fatalf("cursor = %d, want 42", got)
|
|
}
|
|
|
|
if err := c.SetCursor(labeler, 100); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err = c.GetCursor(labeler)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != 100 {
|
|
t.Fatalf("cursor after upsert = %d, want 100", got)
|
|
}
|
|
}
|
|
|
|
func TestIsExpired(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
cts time.Time
|
|
grace time.Duration
|
|
expired bool
|
|
}{
|
|
{"in-window", time.Now().Add(-time.Hour), 24 * time.Hour, false},
|
|
{"past-window", time.Now().Add(-48 * time.Hour), 24 * time.Hour, true},
|
|
{"zero grace expires immediately", time.Now(), 0, true},
|
|
{"negative grace expires immediately", time.Now(), -time.Hour, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := IsExpired(tt.cts, tt.grace); got != tt.expired {
|
|
t.Fatalf("IsExpired = %v, want %v", got, tt.expired)
|
|
}
|
|
})
|
|
}
|
|
}
|