Files
at-container-registry/pkg/appview/db/hold_store_test.go
T

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)
}
})
}