package database import ( "context" "fmt" "math" "testing" "time" ) const ( Mebibyte = 1024 * 1024 oneHundredMebibytes = 100 * Mebibyte fortyMebibytes = 40 * Mebibyte sixtyMebibytes = 60 * Mebibyte twoHundredMebibytes = 200 * Mebibyte compressionRatioPoint4 = 0.4 compressionRatioPoint3 = 0.3 ) func TestSnapshotRepository(t *testing.T) { db, cleanup := setupTestDB(t) defer cleanup() ctx := context.Background() repo := NewSnapshotRepository(db) // Test Create snapshot := &Snapshot{ ID: "2024-01-01T12:00:00Z", Hostname: "test-host", VaultikVersion: "1.0.0", StartedAt: time.Now().Truncate(time.Second), CompletedAt: nil, FileCount: 100, ChunkCount: 500, BlobCount: 10, TotalSize: oneHundredMebibytes, BlobSize: fortyMebibytes, CompressionRatio: compressionRatioPoint4, // 40MB / 100MB } err := repo.Create(ctx, nil, snapshot) if err != nil { t.Fatalf("failed to create snapshot: %v", err) } // Test GetByID retrieved, err := repo.GetByID(ctx, snapshot.ID) if err != nil { t.Fatalf("failed to get snapshot: %v", err) } if retrieved == nil { t.Fatal("expected snapshot, got nil") } if retrieved.ID != snapshot.ID { t.Errorf("ID mismatch: got %s, want %s", retrieved.ID, snapshot.ID) } if retrieved.Hostname != snapshot.Hostname { t.Errorf("hostname mismatch: got %s, want %s", retrieved.Hostname, snapshot.Hostname) } if retrieved.FileCount != snapshot.FileCount { t.Errorf("file count mismatch: got %d, want %d", retrieved.FileCount, snapshot.FileCount) } // Test UpdateCounts err = repo.UpdateCounts(ctx, nil, snapshot.ID, 200, 1000, 20, twoHundredMebibytes, sixtyMebibytes) if err != nil { t.Fatalf("failed to update counts: %v", err) } retrieved, err = repo.GetByID(ctx, snapshot.ID) if err != nil { t.Fatalf("failed to get updated snapshot: %v", err) } if retrieved.FileCount != 200 { t.Errorf("file count not updated: got %d, want %d", retrieved.FileCount, 200) } if retrieved.ChunkCount != 1000 { t.Errorf("chunk count not updated: got %d, want %d", retrieved.ChunkCount, 1000) } if retrieved.BlobCount != 20 { t.Errorf("blob count not updated: got %d, want %d", retrieved.BlobCount, 20) } if retrieved.TotalSize != twoHundredMebibytes { t.Errorf("total size not updated: got %d, want %d", retrieved.TotalSize, twoHundredMebibytes) } if retrieved.BlobSize != sixtyMebibytes { t.Errorf("blob size not updated: got %d, want %d", retrieved.BlobSize, sixtyMebibytes) } expectedRatio := compressionRatioPoint3 // 0.3 if math.Abs(retrieved.CompressionRatio-expectedRatio) > 0.001 { t.Errorf("compression ratio not updated: got %f, want %f", retrieved.CompressionRatio, expectedRatio) } // Test ListRecent // Add more snapshots for i := 2; i <= 5; i++ { s := &Snapshot{ ID: fmt.Sprintf("2024-01-0%dT12:00:00Z", i), Hostname: "test-host", VaultikVersion: "1.0.0", StartedAt: time.Now().Add(time.Duration(i) * time.Hour).Truncate(time.Second), CompletedAt: nil, FileCount: int64(100 * i), ChunkCount: int64(500 * i), BlobCount: int64(10 * i), } err := repo.Create(ctx, nil, s) if err != nil { t.Fatalf("failed to create snapshot %d: %v", i, err) } } // Test listing with limit recent, err := repo.ListRecent(ctx, 3) if err != nil { t.Fatalf("failed to list recent snapshots: %v", err) } if len(recent) != 3 { t.Errorf("expected 3 recent snapshots, got %d", len(recent)) } // Verify order (most recent first) for i := 0; i < len(recent)-1; i++ { if recent[i].StartedAt.Before(recent[i+1].StartedAt) { t.Error("snapshots not in descending order") } } } func TestSnapshotRepositoryNotFound(t *testing.T) { db, cleanup := setupTestDB(t) defer cleanup() ctx := context.Background() repo := NewSnapshotRepository(db) // Test GetByID with non-existent ID snapshot, err := repo.GetByID(ctx, "nonexistent") if err != nil { t.Fatalf("unexpected error: %v", err) } if snapshot != nil { t.Error("expected nil for non-existent snapshot") } // Test UpdateCounts on non-existent snapshot err = repo.UpdateCounts(ctx, nil, "nonexistent", 100, 200, 10, oneHundredMebibytes, fortyMebibytes) if err != nil { t.Fatalf("unexpected error: %v", err) } // No error expected, but no rows should be affected } func TestSnapshotRepositoryDuplicate(t *testing.T) { db, cleanup := setupTestDB(t) defer cleanup() ctx := context.Background() repo := NewSnapshotRepository(db) snapshot := &Snapshot{ ID: "2024-01-01T12:00:00Z", Hostname: "test-host", VaultikVersion: "1.0.0", StartedAt: time.Now().Truncate(time.Second), CompletedAt: nil, FileCount: 100, ChunkCount: 500, BlobCount: 10, } err := repo.Create(ctx, nil, snapshot) if err != nil { t.Fatalf("failed to create snapshot: %v", err) } // Try to create duplicate - should fail due to primary key constraint err = repo.Create(ctx, nil, snapshot) if err == nil { t.Error("expected error for duplicate snapshot") } }