362 lines
11 KiB
Go
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"])
|
|
}
|
|
}
|