Files
at-container-registry/pkg/appview/db/annotations_test.go
2025-10-28 20:39:57 -05:00

362 lines
11 KiB
Go

package db
import (
"database/sql"
"testing"
)
func TestAnnotations_Placeholder(t *testing.T) {
// Placeholder test for annotations package
// GetRepositoryAnnotations returns map[string]string
annotations := make(map[string]string)
annotations["test"] = "value"
if annotations["test"] != "value" {
t.Error("Expected annotation value to be stored")
}
}
// Integration tests
func setupAnnotationsTestDB(t *testing.T) *sql.DB {
t.Helper()
// Use file::memory: with cache=shared to ensure all connections share the same in-memory DB
db, err := InitDB("file::memory:?cache=shared", true)
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
}
func createAnnotationTestUser(t *testing.T, db *sql.DB, did, handle string) {
t.Helper()
_, err := db.Exec(`
INSERT OR IGNORE INTO users (did, handle, pds_endpoint, last_seen)
VALUES (?, ?, ?, datetime('now'))
`, did, handle, "https://pds.example.com")
if err != nil {
t.Fatalf("Failed to create test user: %v", err)
}
}
// TestGetRepositoryAnnotations_Empty tests retrieving from empty repository
func TestGetRepositoryAnnotations_Empty(t *testing.T) {
db := setupAnnotationsTestDB(t)
annotations, err := GetRepositoryAnnotations(db, "did:plc:alice123", "myapp")
if err != nil {
t.Fatalf("GetRepositoryAnnotations() error = %v", err)
}
if len(annotations) != 0 {
t.Errorf("Expected empty annotations, got %d entries", len(annotations))
}
}
// TestGetRepositoryAnnotations_WithData tests retrieving existing annotations
func TestGetRepositoryAnnotations_WithData(t *testing.T) {
db := setupAnnotationsTestDB(t)
createAnnotationTestUser(t, db, "did:plc:alice123", "alice.bsky.social")
// Insert test annotations
testAnnotations := map[string]string{
"org.opencontainers.image.title": "My App",
"org.opencontainers.image.description": "A test application",
"org.opencontainers.image.version": "1.0.0",
}
err := UpsertRepositoryAnnotations(db, "did:plc:alice123", "myapp", testAnnotations)
if err != nil {
t.Fatalf("UpsertRepositoryAnnotations() error = %v", err)
}
// Retrieve annotations
annotations, err := GetRepositoryAnnotations(db, "did:plc:alice123", "myapp")
if err != nil {
t.Fatalf("GetRepositoryAnnotations() error = %v", err)
}
if len(annotations) != len(testAnnotations) {
t.Errorf("Expected %d annotations, got %d", len(testAnnotations), len(annotations))
}
for key, expectedValue := range testAnnotations {
if actualValue, ok := annotations[key]; !ok {
t.Errorf("Missing annotation key: %s", key)
} else if actualValue != expectedValue {
t.Errorf("Annotation[%s] = %v, want %v", key, actualValue, expectedValue)
}
}
}
// TestUpsertRepositoryAnnotations_Insert tests inserting new annotations
func TestUpsertRepositoryAnnotations_Insert(t *testing.T) {
db := setupAnnotationsTestDB(t)
createAnnotationTestUser(t, db, "did:plc:bob456", "bob.bsky.social")
annotations := map[string]string{
"key1": "value1",
"key2": "value2",
}
err := UpsertRepositoryAnnotations(db, "did:plc:bob456", "testapp", annotations)
if err != nil {
t.Fatalf("UpsertRepositoryAnnotations() error = %v", err)
}
// Verify annotations were inserted
retrieved, err := GetRepositoryAnnotations(db, "did:plc:bob456", "testapp")
if err != nil {
t.Fatalf("GetRepositoryAnnotations() error = %v", err)
}
if len(retrieved) != len(annotations) {
t.Errorf("Expected %d annotations, got %d", len(annotations), len(retrieved))
}
for key, expectedValue := range annotations {
if actualValue := retrieved[key]; actualValue != expectedValue {
t.Errorf("Annotation[%s] = %v, want %v", key, actualValue, expectedValue)
}
}
}
// TestUpsertRepositoryAnnotations_Update tests updating existing annotations
func TestUpsertRepositoryAnnotations_Update(t *testing.T) {
db := setupAnnotationsTestDB(t)
createAnnotationTestUser(t, db, "did:plc:charlie789", "charlie.bsky.social")
// Insert initial annotations
initial := map[string]string{
"key1": "oldvalue1",
"key2": "oldvalue2",
"key3": "oldvalue3",
}
err := UpsertRepositoryAnnotations(db, "did:plc:charlie789", "updateapp", initial)
if err != nil {
t.Fatalf("Initial UpsertRepositoryAnnotations() error = %v", err)
}
// Update with new annotations (completely replaces old ones)
updated := map[string]string{
"key1": "newvalue1", // Updated
"key4": "newvalue4", // New key (key2 and key3 removed)
}
err = UpsertRepositoryAnnotations(db, "did:plc:charlie789", "updateapp", updated)
if err != nil {
t.Fatalf("Update UpsertRepositoryAnnotations() error = %v", err)
}
// Verify annotations were replaced
retrieved, err := GetRepositoryAnnotations(db, "did:plc:charlie789", "updateapp")
if err != nil {
t.Fatalf("GetRepositoryAnnotations() error = %v", err)
}
if len(retrieved) != len(updated) {
t.Errorf("Expected %d annotations, got %d", len(updated), len(retrieved))
}
// Verify new values
if retrieved["key1"] != "newvalue1" {
t.Errorf("key1 = %v, want newvalue1", retrieved["key1"])
}
if retrieved["key4"] != "newvalue4" {
t.Errorf("key4 = %v, want newvalue4", retrieved["key4"])
}
// Verify old keys were removed
if _, exists := retrieved["key2"]; exists {
t.Error("key2 should have been removed")
}
if _, exists := retrieved["key3"]; exists {
t.Error("key3 should have been removed")
}
}
// TestUpsertRepositoryAnnotations_EmptyMap tests upserting with empty map
func TestUpsertRepositoryAnnotations_EmptyMap(t *testing.T) {
db := setupAnnotationsTestDB(t)
createAnnotationTestUser(t, db, "did:plc:dave111", "dave.bsky.social")
// Insert initial annotations
initial := map[string]string{
"key1": "value1",
"key2": "value2",
}
err := UpsertRepositoryAnnotations(db, "did:plc:dave111", "emptyapp", initial)
if err != nil {
t.Fatalf("Initial UpsertRepositoryAnnotations() error = %v", err)
}
// Upsert with empty map (should delete all)
empty := make(map[string]string)
err = UpsertRepositoryAnnotations(db, "did:plc:dave111", "emptyapp", empty)
if err != nil {
t.Fatalf("Empty UpsertRepositoryAnnotations() error = %v", err)
}
// Verify all annotations were deleted
retrieved, err := GetRepositoryAnnotations(db, "did:plc:dave111", "emptyapp")
if err != nil {
t.Fatalf("GetRepositoryAnnotations() error = %v", err)
}
if len(retrieved) != 0 {
t.Errorf("Expected 0 annotations after empty upsert, got %d", len(retrieved))
}
}
// TestUpsertRepositoryAnnotations_MultipleRepos tests isolation between repositories
func TestUpsertRepositoryAnnotations_MultipleRepos(t *testing.T) {
db := setupAnnotationsTestDB(t)
createAnnotationTestUser(t, db, "did:plc:eve222", "eve.bsky.social")
// Insert annotations for repo1
repo1Annotations := map[string]string{
"repo": "repo1",
"key1": "value1",
}
err := UpsertRepositoryAnnotations(db, "did:plc:eve222", "repo1", repo1Annotations)
if err != nil {
t.Fatalf("UpsertRepositoryAnnotations(repo1) error = %v", err)
}
// Insert annotations for repo2 (same DID, different repo)
repo2Annotations := map[string]string{
"repo": "repo2",
"key2": "value2",
}
err = UpsertRepositoryAnnotations(db, "did:plc:eve222", "repo2", repo2Annotations)
if err != nil {
t.Fatalf("UpsertRepositoryAnnotations(repo2) error = %v", err)
}
// Verify repo1 annotations unchanged
retrieved1, err := GetRepositoryAnnotations(db, "did:plc:eve222", "repo1")
if err != nil {
t.Fatalf("GetRepositoryAnnotations(repo1) error = %v", err)
}
if len(retrieved1) != len(repo1Annotations) {
t.Errorf("repo1: Expected %d annotations, got %d", len(repo1Annotations), len(retrieved1))
}
if retrieved1["repo"] != "repo1" {
t.Errorf("repo1: Expected repo=repo1, got %v", retrieved1["repo"])
}
// Verify repo2 annotations
retrieved2, err := GetRepositoryAnnotations(db, "did:plc:eve222", "repo2")
if err != nil {
t.Fatalf("GetRepositoryAnnotations(repo2) error = %v", err)
}
if len(retrieved2) != len(repo2Annotations) {
t.Errorf("repo2: Expected %d annotations, got %d", len(repo2Annotations), len(retrieved2))
}
if retrieved2["repo"] != "repo2" {
t.Errorf("repo2: Expected repo=repo2, got %v", retrieved2["repo"])
}
}
// TestDeleteRepositoryAnnotations tests deleting annotations
func TestDeleteRepositoryAnnotations(t *testing.T) {
db := setupAnnotationsTestDB(t)
createAnnotationTestUser(t, db, "did:plc:frank333", "frank.bsky.social")
// Insert annotations
annotations := map[string]string{
"key1": "value1",
"key2": "value2",
}
err := UpsertRepositoryAnnotations(db, "did:plc:frank333", "deleteapp", annotations)
if err != nil {
t.Fatalf("UpsertRepositoryAnnotations() error = %v", err)
}
// Verify annotations exist
retrieved, err := GetRepositoryAnnotations(db, "did:plc:frank333", "deleteapp")
if err != nil {
t.Fatalf("GetRepositoryAnnotations() error = %v", err)
}
if len(retrieved) != 2 {
t.Fatalf("Expected 2 annotations before delete, got %d", len(retrieved))
}
// Delete annotations
err = DeleteRepositoryAnnotations(db, "did:plc:frank333", "deleteapp")
if err != nil {
t.Fatalf("DeleteRepositoryAnnotations() error = %v", err)
}
// Verify annotations were deleted
retrieved, err = GetRepositoryAnnotations(db, "did:plc:frank333", "deleteapp")
if err != nil {
t.Fatalf("GetRepositoryAnnotations() after delete error = %v", err)
}
if len(retrieved) != 0 {
t.Errorf("Expected 0 annotations after delete, got %d", len(retrieved))
}
}
// TestDeleteRepositoryAnnotations_NonExistent tests deleting non-existent annotations
func TestDeleteRepositoryAnnotations_NonExistent(t *testing.T) {
db := setupAnnotationsTestDB(t)
// Delete from non-existent repository (should not error)
err := DeleteRepositoryAnnotations(db, "did:plc:ghost999", "nonexistent")
if err != nil {
t.Errorf("DeleteRepositoryAnnotations() for non-existent repo should not error, got: %v", err)
}
}
// TestAnnotations_DifferentDIDs tests isolation between different DIDs
func TestAnnotations_DifferentDIDs(t *testing.T) {
db := setupAnnotationsTestDB(t)
createAnnotationTestUser(t, db, "did:plc:alice123", "alice.bsky.social")
createAnnotationTestUser(t, db, "did:plc:bob456", "bob.bsky.social")
// Insert annotations for alice
aliceAnnotations := map[string]string{
"owner": "alice",
"key1": "alice-value1",
}
err := UpsertRepositoryAnnotations(db, "did:plc:alice123", "sharedname", aliceAnnotations)
if err != nil {
t.Fatalf("UpsertRepositoryAnnotations(alice) error = %v", err)
}
// Insert annotations for bob (same repo name, different DID)
bobAnnotations := map[string]string{
"owner": "bob",
"key1": "bob-value1",
}
err = UpsertRepositoryAnnotations(db, "did:plc:bob456", "sharedname", bobAnnotations)
if err != nil {
t.Fatalf("UpsertRepositoryAnnotations(bob) error = %v", err)
}
// Verify alice's annotations unchanged
aliceRetrieved, err := GetRepositoryAnnotations(db, "did:plc:alice123", "sharedname")
if err != nil {
t.Fatalf("GetRepositoryAnnotations(alice) error = %v", err)
}
if aliceRetrieved["owner"] != "alice" {
t.Errorf("alice: Expected owner=alice, got %v", aliceRetrieved["owner"])
}
// Verify bob's annotations
bobRetrieved, err := GetRepositoryAnnotations(db, "did:plc:bob456", "sharedname")
if err != nil {
t.Fatalf("GetRepositoryAnnotations(bob) error = %v", err)
}
if bobRetrieved["owner"] != "bob" {
t.Errorf("bob: Expected owner=bob, got %v", bobRetrieved["owner"])
}
}