package connection import ( "context" "path/filepath" "testing" "github.com/bluesky-social/indigo/atproto/syntax" atdb "atmoquest/internal/db" ) const ( didA = "did:plc:aaaaaaaaaaaaaaaaaaaaaaaa" didB = "did:plc:bbbbbbbbbbbbbbbbbbbbbbbb" didC = "did:plc:cccccccccccccccccccccccc" ) func newTestQueue(t *testing.T) *Queue { t.Helper() dir := t.TempDir() dsn := "file:" + filepath.Join(dir, "test.db") + "?_pragma=journal_mode(WAL)&_pragma=foreign_keys(ON)" conn, err := atdb.Open(dsn) if err != nil { t.Fatalf("open db: %v", err) } t.Cleanup(func() { _ = conn.Close() }) if err := atdb.Migrate(conn); err != nil { t.Fatalf("migrate: %v", err) } return NewQueue(conn) } func did(t *testing.T, s string) syntax.DID { t.Helper() d, err := syntax.ParseDID(s) if err != nil { t.Fatalf("parse DID %s: %v", s, err) } return d } func TestQueue_EnqueueAndList(t *testing.T) { q := newTestQueue(t) ctx := context.Background() target := did(t, didA) initiator := did(t, didB) if err := q.Enqueue(ctx, target, initiator, ""); err != nil { t.Fatalf("enqueue: %v", err) } items, err := q.List(ctx, target, 0) if err != nil { t.Fatalf("list: %v", err) } if len(items) != 1 { t.Fatalf("len(items) = %d, want 1", len(items)) } if items[0].TargetDID != target { t.Errorf("TargetDID = %s, want %s", items[0].TargetDID, target) } if items[0].InitiatorDID != initiator { t.Errorf("InitiatorDID = %s, want %s", items[0].InitiatorDID, initiator) } } func TestQueue_EnqueueIdempotent(t *testing.T) { q := newTestQueue(t) ctx := context.Background() target := did(t, didA) initiator := did(t, didB) for i := 0; i < 3; i++ { if err := q.Enqueue(ctx, target, initiator, ""); err != nil { t.Fatalf("enqueue #%d: %v", i, err) } } count, err := q.Count(ctx, target) if err != nil { t.Fatalf("count: %v", err) } if count != 1 { t.Errorf("count = %d, want 1 (unique index should suppress dupes)", count) } } func TestQueue_RejectsSelfConnect(t *testing.T) { q := newTestQueue(t) target := did(t, didA) err := q.Enqueue(context.Background(), target, target, "") if err == nil { t.Fatal("expected error for self-connect") } } func TestQueue_RejectsEmptyDID(t *testing.T) { q := newTestQueue(t) if err := q.Enqueue(context.Background(), "", did(t, didA), ""); err == nil { t.Error("expected error for empty target") } if err := q.Enqueue(context.Background(), did(t, didA), "", ""); err == nil { t.Error("expected error for empty initiator") } } func TestQueue_MultipleInitiatorsForSameTarget(t *testing.T) { q := newTestQueue(t) ctx := context.Background() target := did(t, didA) for _, init := range []syntax.DID{did(t, didB), did(t, didC)} { if err := q.Enqueue(ctx, target, init, ""); err != nil { t.Fatalf("enqueue: %v", err) } } items, err := q.List(ctx, target, 0) if err != nil { t.Fatalf("list: %v", err) } if len(items) != 2 { t.Fatalf("len = %d, want 2", len(items)) } } func TestQueue_ListLimit(t *testing.T) { q := newTestQueue(t) ctx := context.Background() target := did(t, didA) _ = q.Enqueue(ctx, target, did(t, didB), "") _ = q.Enqueue(ctx, target, did(t, didC), "") items, err := q.List(ctx, target, 1) if err != nil { t.Fatalf("list: %v", err) } if len(items) != 1 { t.Errorf("len with limit=1 = %d, want 1", len(items)) } } func TestQueue_Delete(t *testing.T) { q := newTestQueue(t) ctx := context.Background() target := did(t, didA) if err := q.Enqueue(ctx, target, did(t, didB), ""); err != nil { t.Fatalf("enqueue: %v", err) } items, _ := q.List(ctx, target, 0) if err := q.Delete(ctx, items[0].ID); err != nil { t.Fatalf("delete: %v", err) } count, _ := q.Count(ctx, target) if count != 0 { t.Errorf("count after delete = %d, want 0", count) } } func TestQueue_ListPreservesInsertionOrder(t *testing.T) { q := newTestQueue(t) ctx := context.Background() target := did(t, didA) order := []syntax.DID{did(t, didB), did(t, didC)} for _, init := range order { if err := q.Enqueue(ctx, target, init, ""); err != nil { t.Fatalf("enqueue: %v", err) } } items, _ := q.List(ctx, target, 0) for i, item := range items { if item.InitiatorDID != order[i] { t.Errorf("items[%d].InitiatorDID = %s, want %s", i, item.InitiatorDID, order[i]) } } } func TestQueue_CountIsolatedByTarget(t *testing.T) { q := newTestQueue(t) ctx := context.Background() _ = q.Enqueue(ctx, did(t, didA), did(t, didB), "") _ = q.Enqueue(ctx, did(t, didC), did(t, didB), "") if c, _ := q.Count(ctx, did(t, didA)); c != 1 { t.Errorf("count(A) = %d, want 1", c) } if c, _ := q.Count(ctx, did(t, didC)); c != 1 { t.Errorf("count(C) = %d, want 1", c) } }