mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-26 12:14:17 +00:00
554 lines
15 KiB
Go
554 lines
15 KiB
Go
package db
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestNullString(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expectedValid bool
|
|
expectedStr string
|
|
}{
|
|
{
|
|
name: "empty string",
|
|
input: "",
|
|
expectedValid: false,
|
|
expectedStr: "",
|
|
},
|
|
{
|
|
name: "non-empty string",
|
|
input: "hello",
|
|
expectedValid: true,
|
|
expectedStr: "hello",
|
|
},
|
|
{
|
|
name: "whitespace string",
|
|
input: " ",
|
|
expectedValid: true,
|
|
expectedStr: " ",
|
|
},
|
|
{
|
|
name: "single character",
|
|
input: "a",
|
|
expectedValid: true,
|
|
expectedStr: "a",
|
|
},
|
|
{
|
|
name: "newline string",
|
|
input: "\n",
|
|
expectedValid: true,
|
|
expectedStr: "\n",
|
|
},
|
|
{
|
|
name: "tab string",
|
|
input: "\t",
|
|
expectedValid: true,
|
|
expectedStr: "\t",
|
|
},
|
|
{
|
|
name: "DID string",
|
|
input: "did:plc:abc123",
|
|
expectedValid: true,
|
|
expectedStr: "did:plc:abc123",
|
|
},
|
|
{
|
|
name: "URL string",
|
|
input: "https://example.com",
|
|
expectedValid: true,
|
|
expectedStr: "https://example.com",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := nullString(tt.input)
|
|
if result.Valid != tt.expectedValid {
|
|
t.Errorf("nullString(%q).Valid = %v, want %v", tt.input, result.Valid, tt.expectedValid)
|
|
}
|
|
if result.String != tt.expectedStr {
|
|
t.Errorf("nullString(%q).String = %q, want %q", tt.input, result.String, tt.expectedStr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Integration tests
|
|
|
|
func setupHoldTestDB(t *testing.T) *sql.DB {
|
|
t.Helper()
|
|
// Use a named in-memory DB unique to this test to ensure isolation between tests
|
|
safeName := strings.ReplaceAll(t.Name(), "/", "_")
|
|
db, err := InitDB(fmt.Sprintf("file:%s?mode=memory&cache=shared", safeName), LibsqlConfig{})
|
|
if err != nil {
|
|
t.Fatalf("Failed to initialize test database: %v", err)
|
|
}
|
|
// Limit to single connection to avoid race conditions in tests
|
|
db.SetMaxOpenConns(1)
|
|
t.Cleanup(func() { db.Close() })
|
|
return db
|
|
}
|
|
|
|
// TestGetCaptainRecord tests retrieving captain records
|
|
func TestGetCaptainRecord(t *testing.T) {
|
|
db := setupHoldTestDB(t)
|
|
|
|
// Insert a test record
|
|
testRecord := &HoldCaptainRecord{
|
|
HoldDID: "did:web:hold01.atcr.io",
|
|
OwnerDID: "did:plc:alice123",
|
|
Public: true,
|
|
AllowAllCrew: false,
|
|
DeployedAt: "2025-01-15",
|
|
Region: "us-west-2",
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
|
|
err := UpsertCaptainRecord(db, testRecord)
|
|
if err != nil {
|
|
t.Fatalf("UpsertCaptainRecord() error = %v", err)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
holdDID string
|
|
wantFound bool
|
|
}{
|
|
{
|
|
name: "existing record",
|
|
holdDID: "did:web:hold01.atcr.io",
|
|
wantFound: true,
|
|
},
|
|
{
|
|
name: "non-existent record",
|
|
holdDID: "did:web:unknown.atcr.io",
|
|
wantFound: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
record, err := GetCaptainRecord(db, tt.holdDID)
|
|
if err != nil {
|
|
t.Fatalf("GetCaptainRecord() error = %v", err)
|
|
}
|
|
|
|
if tt.wantFound {
|
|
if record == nil {
|
|
t.Error("Expected record, got nil")
|
|
return
|
|
}
|
|
if record.HoldDID != tt.holdDID {
|
|
t.Errorf("HoldDID = %v, want %v", record.HoldDID, tt.holdDID)
|
|
}
|
|
if record.OwnerDID != testRecord.OwnerDID {
|
|
t.Errorf("OwnerDID = %v, want %v", record.OwnerDID, testRecord.OwnerDID)
|
|
}
|
|
if record.Public != testRecord.Public {
|
|
t.Errorf("Public = %v, want %v", record.Public, testRecord.Public)
|
|
}
|
|
if record.AllowAllCrew != testRecord.AllowAllCrew {
|
|
t.Errorf("AllowAllCrew = %v, want %v", record.AllowAllCrew, testRecord.AllowAllCrew)
|
|
}
|
|
if record.DeployedAt != testRecord.DeployedAt {
|
|
t.Errorf("DeployedAt = %v, want %v", record.DeployedAt, testRecord.DeployedAt)
|
|
}
|
|
if record.Region != testRecord.Region {
|
|
t.Errorf("Region = %v, want %v", record.Region, testRecord.Region)
|
|
}
|
|
} else {
|
|
if record != nil {
|
|
t.Errorf("Expected nil, got record: %+v", record)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestGetCaptainRecord_NullableFields tests handling of NULL fields
|
|
func TestGetCaptainRecord_NullableFields(t *testing.T) {
|
|
db := setupHoldTestDB(t)
|
|
|
|
// Insert record with empty nullable fields
|
|
testRecord := &HoldCaptainRecord{
|
|
HoldDID: "did:web:hold02.atcr.io",
|
|
OwnerDID: "did:plc:bob456",
|
|
Public: false,
|
|
AllowAllCrew: true,
|
|
DeployedAt: "", // Empty - should be NULL
|
|
Region: "", // Empty - should be NULL
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
|
|
err := UpsertCaptainRecord(db, testRecord)
|
|
if err != nil {
|
|
t.Fatalf("UpsertCaptainRecord() error = %v", err)
|
|
}
|
|
|
|
record, err := GetCaptainRecord(db, testRecord.HoldDID)
|
|
if err != nil {
|
|
t.Fatalf("GetCaptainRecord() error = %v", err)
|
|
}
|
|
|
|
if record == nil {
|
|
t.Fatal("Expected record, got nil")
|
|
}
|
|
|
|
if record.DeployedAt != "" {
|
|
t.Errorf("DeployedAt = %v, want empty string", record.DeployedAt)
|
|
}
|
|
if record.Region != "" {
|
|
t.Errorf("Region = %v, want empty string", record.Region)
|
|
}
|
|
}
|
|
|
|
// TestUpsertCaptainRecord_Insert tests inserting new records
|
|
func TestUpsertCaptainRecord_Insert(t *testing.T) {
|
|
db := setupHoldTestDB(t)
|
|
|
|
record := &HoldCaptainRecord{
|
|
HoldDID: "did:web:hold03.atcr.io",
|
|
OwnerDID: "did:plc:charlie789",
|
|
Public: true,
|
|
AllowAllCrew: true,
|
|
DeployedAt: "2025-02-01",
|
|
Region: "eu-west-1",
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
|
|
err := UpsertCaptainRecord(db, record)
|
|
if err != nil {
|
|
t.Fatalf("UpsertCaptainRecord() error = %v", err)
|
|
}
|
|
|
|
// Verify it was inserted
|
|
retrieved, err := GetCaptainRecord(db, record.HoldDID)
|
|
if err != nil {
|
|
t.Fatalf("GetCaptainRecord() error = %v", err)
|
|
}
|
|
|
|
if retrieved == nil {
|
|
t.Fatal("Expected record to be inserted")
|
|
}
|
|
|
|
if retrieved.HoldDID != record.HoldDID {
|
|
t.Errorf("HoldDID = %v, want %v", retrieved.HoldDID, record.HoldDID)
|
|
}
|
|
if retrieved.OwnerDID != record.OwnerDID {
|
|
t.Errorf("OwnerDID = %v, want %v", retrieved.OwnerDID, record.OwnerDID)
|
|
}
|
|
}
|
|
|
|
// TestUpsertCaptainRecord_Update tests updating existing records
|
|
func TestUpsertCaptainRecord_Update(t *testing.T) {
|
|
db := setupHoldTestDB(t)
|
|
|
|
// Insert initial record
|
|
initialRecord := &HoldCaptainRecord{
|
|
HoldDID: "did:web:hold04.atcr.io",
|
|
OwnerDID: "did:plc:dave111",
|
|
Public: false,
|
|
AllowAllCrew: false,
|
|
DeployedAt: "2025-01-01",
|
|
Region: "us-east-1",
|
|
UpdatedAt: time.Now().Add(-1 * time.Hour),
|
|
}
|
|
|
|
err := UpsertCaptainRecord(db, initialRecord)
|
|
if err != nil {
|
|
t.Fatalf("Initial UpsertCaptainRecord() error = %v", err)
|
|
}
|
|
|
|
// Update the record
|
|
updatedRecord := &HoldCaptainRecord{
|
|
HoldDID: "did:web:hold04.atcr.io", // Same DID
|
|
OwnerDID: "did:plc:eve222", // Changed owner
|
|
Public: true, // Changed to public
|
|
AllowAllCrew: true, // Changed allow all crew
|
|
DeployedAt: "2025-03-01", // Changed date
|
|
Region: "ap-south-1", // Changed region
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
|
|
err = UpsertCaptainRecord(db, updatedRecord)
|
|
if err != nil {
|
|
t.Fatalf("Update UpsertCaptainRecord() error = %v", err)
|
|
}
|
|
|
|
// Verify it was updated
|
|
retrieved, err := GetCaptainRecord(db, updatedRecord.HoldDID)
|
|
if err != nil {
|
|
t.Fatalf("GetCaptainRecord() error = %v", err)
|
|
}
|
|
|
|
if retrieved == nil {
|
|
t.Fatal("Expected record to exist")
|
|
}
|
|
|
|
if retrieved.OwnerDID != updatedRecord.OwnerDID {
|
|
t.Errorf("OwnerDID = %v, want %v", retrieved.OwnerDID, updatedRecord.OwnerDID)
|
|
}
|
|
if retrieved.Public != updatedRecord.Public {
|
|
t.Errorf("Public = %v, want %v", retrieved.Public, updatedRecord.Public)
|
|
}
|
|
if retrieved.AllowAllCrew != updatedRecord.AllowAllCrew {
|
|
t.Errorf("AllowAllCrew = %v, want %v", retrieved.AllowAllCrew, updatedRecord.AllowAllCrew)
|
|
}
|
|
if retrieved.DeployedAt != updatedRecord.DeployedAt {
|
|
t.Errorf("DeployedAt = %v, want %v", retrieved.DeployedAt, updatedRecord.DeployedAt)
|
|
}
|
|
if retrieved.Region != updatedRecord.Region {
|
|
t.Errorf("Region = %v, want %v", retrieved.Region, updatedRecord.Region)
|
|
}
|
|
|
|
// Verify there's still only one record in the database
|
|
holds, err := ListHoldDIDs(db)
|
|
if err != nil {
|
|
t.Fatalf("ListHoldDIDs() error = %v", err)
|
|
}
|
|
if len(holds) != 1 {
|
|
t.Errorf("Expected 1 record, got %d", len(holds))
|
|
}
|
|
}
|
|
|
|
// TestListHoldDIDs tests listing all hold DIDs
|
|
func TestListHoldDIDs(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
records []*HoldCaptainRecord
|
|
wantCount int
|
|
}{
|
|
{
|
|
name: "empty database",
|
|
records: []*HoldCaptainRecord{},
|
|
wantCount: 0,
|
|
},
|
|
{
|
|
name: "single record",
|
|
records: []*HoldCaptainRecord{
|
|
{
|
|
HoldDID: "did:web:hold05.atcr.io",
|
|
OwnerDID: "did:plc:alice123",
|
|
Public: true,
|
|
AllowAllCrew: false,
|
|
UpdatedAt: time.Now(),
|
|
},
|
|
},
|
|
wantCount: 1,
|
|
},
|
|
{
|
|
name: "multiple records",
|
|
records: []*HoldCaptainRecord{
|
|
{
|
|
HoldDID: "did:web:hold06.atcr.io",
|
|
OwnerDID: "did:plc:alice123",
|
|
Public: true,
|
|
AllowAllCrew: false,
|
|
UpdatedAt: time.Now().Add(-2 * time.Hour),
|
|
},
|
|
{
|
|
HoldDID: "did:web:hold07.atcr.io",
|
|
OwnerDID: "did:plc:bob456",
|
|
Public: false,
|
|
AllowAllCrew: true,
|
|
UpdatedAt: time.Now().Add(-1 * time.Hour),
|
|
},
|
|
{
|
|
HoldDID: "did:web:hold08.atcr.io",
|
|
OwnerDID: "did:plc:charlie789",
|
|
Public: true,
|
|
AllowAllCrew: true,
|
|
UpdatedAt: time.Now(), // Most recent
|
|
},
|
|
},
|
|
wantCount: 3,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Fresh database for each test
|
|
db := setupHoldTestDB(t)
|
|
|
|
// Insert test records
|
|
for _, record := range tt.records {
|
|
err := UpsertCaptainRecord(db, record)
|
|
if err != nil {
|
|
t.Fatalf("UpsertCaptainRecord() error = %v", err)
|
|
}
|
|
}
|
|
|
|
// List holds
|
|
holds, err := ListHoldDIDs(db)
|
|
if err != nil {
|
|
t.Fatalf("ListHoldDIDs() error = %v", err)
|
|
}
|
|
|
|
if len(holds) != tt.wantCount {
|
|
t.Errorf("ListHoldDIDs() count = %d, want %d", len(holds), tt.wantCount)
|
|
}
|
|
|
|
// Verify order (most recent first)
|
|
if len(tt.records) > 1 {
|
|
// Most recent should be first (hold08)
|
|
if holds[0] != "did:web:hold08.atcr.io" {
|
|
t.Errorf("First hold = %v, want did:web:hold08.atcr.io", holds[0])
|
|
}
|
|
// Oldest should be last (hold06)
|
|
if holds[len(holds)-1] != "did:web:hold06.atcr.io" {
|
|
t.Errorf("Last hold = %v, want did:web:hold06.atcr.io", holds[len(holds)-1])
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestListHoldDIDs_OrderByUpdatedAt tests that holds are ordered correctly
|
|
func TestListHoldDIDs_OrderByUpdatedAt(t *testing.T) {
|
|
db := setupHoldTestDB(t)
|
|
|
|
// Insert records with specific update times
|
|
now := time.Now()
|
|
records := []*HoldCaptainRecord{
|
|
{
|
|
HoldDID: "did:web:oldest.atcr.io",
|
|
OwnerDID: "did:plc:test1",
|
|
Public: true,
|
|
UpdatedAt: now.Add(-3 * time.Hour),
|
|
},
|
|
{
|
|
HoldDID: "did:web:newest.atcr.io",
|
|
OwnerDID: "did:plc:test2",
|
|
Public: true,
|
|
UpdatedAt: now,
|
|
},
|
|
{
|
|
HoldDID: "did:web:middle.atcr.io",
|
|
OwnerDID: "did:plc:test3",
|
|
Public: true,
|
|
UpdatedAt: now.Add(-1 * time.Hour),
|
|
},
|
|
}
|
|
|
|
for _, record := range records {
|
|
err := UpsertCaptainRecord(db, record)
|
|
if err != nil {
|
|
t.Fatalf("UpsertCaptainRecord() error = %v", err)
|
|
}
|
|
}
|
|
|
|
holds, err := ListHoldDIDs(db)
|
|
if err != nil {
|
|
t.Fatalf("ListHoldDIDs() error = %v", err)
|
|
}
|
|
|
|
// Verify order: newest first, oldest last
|
|
expectedOrder := []string{
|
|
"did:web:newest.atcr.io",
|
|
"did:web:middle.atcr.io",
|
|
"did:web:oldest.atcr.io",
|
|
}
|
|
|
|
if len(holds) != len(expectedOrder) {
|
|
t.Fatalf("Expected %d holds, got %d", len(expectedOrder), len(holds))
|
|
}
|
|
|
|
for i, expected := range expectedOrder {
|
|
if holds[i] != expected {
|
|
t.Errorf("holds[%d] = %v, want %v", i, holds[i], expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestGetAccessibleHoldDIDs tests the viewer→hold visibility computation
|
|
// used to filter listings to what the viewer is allowed to see.
|
|
func TestGetAccessibleHoldDIDs(t *testing.T) {
|
|
db := setupHoldTestDB(t)
|
|
|
|
// Seed 4 captain records covering each visibility combo
|
|
records := []*HoldCaptainRecord{
|
|
{HoldDID: "did:web:public.example", OwnerDID: "did:plc:alice", Public: true, AllowAllCrew: false, UpdatedAt: time.Now()},
|
|
{HoldDID: "did:web:selfserv.example", OwnerDID: "did:plc:bob", Public: false, AllowAllCrew: true, UpdatedAt: time.Now()},
|
|
{HoldDID: "did:web:invite.example", OwnerDID: "did:plc:carol", Public: false, AllowAllCrew: false, UpdatedAt: time.Now()},
|
|
{HoldDID: "did:web:carol-hold.example", OwnerDID: "did:plc:carol", Public: false, AllowAllCrew: false, UpdatedAt: time.Now()},
|
|
}
|
|
for _, r := range records {
|
|
if err := UpsertCaptainRecord(db, r); err != nil {
|
|
t.Fatalf("seed captain %s: %v", r.HoldDID, err)
|
|
}
|
|
}
|
|
|
|
// dave is crew of did:web:invite.example
|
|
if err := UpsertCrewMember(db, &CrewMember{
|
|
HoldDID: "did:web:invite.example", MemberDID: "did:plc:dave", Rkey: "rk1",
|
|
}); err != nil {
|
|
t.Fatalf("seed crew: %v", err)
|
|
}
|
|
|
|
contains := func(haystack []string, needle string) bool {
|
|
return slices.Contains(haystack, needle)
|
|
}
|
|
|
|
t.Run("anonymous viewer sees public + self-service only", func(t *testing.T) {
|
|
dids, err := GetAccessibleHoldDIDs(db, "")
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if len(dids) != 2 {
|
|
t.Fatalf("expected 2 DIDs (public+self-service), got %d: %v", len(dids), dids)
|
|
}
|
|
if !contains(dids, "did:web:public.example") {
|
|
t.Errorf("missing public hold: %v", dids)
|
|
}
|
|
if !contains(dids, "did:web:selfserv.example") {
|
|
t.Errorf("missing self-service hold: %v", dids)
|
|
}
|
|
if contains(dids, "did:web:invite.example") {
|
|
t.Errorf("anon should not see invite-only hold: %v", dids)
|
|
}
|
|
})
|
|
|
|
t.Run("crew member also sees invite-only hold", func(t *testing.T) {
|
|
dids, err := GetAccessibleHoldDIDs(db, "did:plc:dave")
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if !contains(dids, "did:web:invite.example") {
|
|
t.Errorf("crew member should see invite-only hold they belong to: %v", dids)
|
|
}
|
|
if contains(dids, "did:web:carol-hold.example") {
|
|
t.Errorf("dave is not crew of carol's private hold: %v", dids)
|
|
}
|
|
})
|
|
|
|
t.Run("owner sees their own private hold", func(t *testing.T) {
|
|
dids, err := GetAccessibleHoldDIDs(db, "did:plc:carol")
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
// carol owns invite.example and carol-hold.example, both private
|
|
if !contains(dids, "did:web:invite.example") {
|
|
t.Errorf("owner should see their invite-only hold: %v", dids)
|
|
}
|
|
if !contains(dids, "did:web:carol-hold.example") {
|
|
t.Errorf("owner should see their second private hold: %v", dids)
|
|
}
|
|
})
|
|
|
|
t.Run("random authenticated viewer gets same set as anonymous", func(t *testing.T) {
|
|
dids, err := GetAccessibleHoldDIDs(db, "did:plc:nobody")
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if len(dids) != 2 {
|
|
t.Fatalf("expected 2 DIDs, got %d: %v", len(dids), dids)
|
|
}
|
|
})
|
|
}
|