package store import ( "context" "testing" "gcy_hpc_server/internal/model" "gorm.io/driver/sqlite" "gorm.io/gorm" "gorm.io/gorm/logger" ) func setupBlobTestDB(t *testing.T) *gorm.DB { t.Helper() db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{ Logger: logger.Default.LogMode(logger.Silent), }) if err != nil { t.Fatalf("open sqlite: %v", err) } if err := db.AutoMigrate(&model.FileBlob{}); err != nil { t.Fatalf("migrate: %v", err) } return db } func TestBlobStore_Create(t *testing.T) { db := setupBlobTestDB(t) store := NewBlobStore(db) ctx := context.Background() blob := &model.FileBlob{ SHA256: "abc123", MinioKey: "files/abc123", FileSize: 1024, MimeType: "application/octet-stream", RefCount: 0, } if err := store.Create(ctx, blob); err != nil { t.Fatalf("Create() error = %v", err) } if blob.ID == 0 { t.Error("Create() did not set ID") } } func TestBlobStore_GetBySHA256(t *testing.T) { db := setupBlobTestDB(t) store := NewBlobStore(db) ctx := context.Background() store.Create(ctx, &model.FileBlob{SHA256: "abc", MinioKey: "files/abc", FileSize: 100, RefCount: 0}) blob, err := store.GetBySHA256(ctx, "abc") if err != nil { t.Fatalf("GetBySHA256() error = %v", err) } if blob == nil { t.Fatal("GetBySHA256() returned nil") } if blob.SHA256 != "abc" { t.Errorf("SHA256 = %q, want %q", blob.SHA256, "abc") } if blob.RefCount != 0 { t.Errorf("RefCount = %d, want 0", blob.RefCount) } } func TestBlobStore_GetBySHA256_NotFound(t *testing.T) { db := setupBlobTestDB(t) store := NewBlobStore(db) ctx := context.Background() blob, err := store.GetBySHA256(ctx, "nonexistent") if err != nil { t.Fatalf("GetBySHA256() error = %v", err) } if blob != nil { t.Error("GetBySHA256() should return nil for not found") } } func TestBlobStore_IncrementDecrementRef(t *testing.T) { db := setupBlobTestDB(t) store := NewBlobStore(db) ctx := context.Background() store.Create(ctx, &model.FileBlob{SHA256: "abc", MinioKey: "files/abc", FileSize: 100, RefCount: 0}) if err := store.IncrementRef(ctx, "abc"); err != nil { t.Fatalf("IncrementRef() error = %v", err) } blob, _ := store.GetBySHA256(ctx, "abc") if blob.RefCount != 1 { t.Errorf("RefCount after 1st increment = %d, want 1", blob.RefCount) } store.IncrementRef(ctx, "abc") blob, _ = store.GetBySHA256(ctx, "abc") if blob.RefCount != 2 { t.Errorf("RefCount after 2nd increment = %d, want 2", blob.RefCount) } refCount, err := store.DecrementRef(ctx, "abc") if err != nil { t.Fatalf("DecrementRef() error = %v", err) } if refCount != 1 { t.Errorf("DecrementRef() returned %d, want 1", refCount) } refCount, _ = store.DecrementRef(ctx, "abc") if refCount != 0 { t.Errorf("DecrementRef() returned %d, want 0", refCount) } } func TestBlobStore_Delete(t *testing.T) { db := setupBlobTestDB(t) store := NewBlobStore(db) ctx := context.Background() store.Create(ctx, &model.FileBlob{SHA256: "abc", MinioKey: "files/abc", FileSize: 100, RefCount: 0}) if err := store.Delete(ctx, "abc"); err != nil { t.Fatalf("Delete() error = %v", err) } blob, _ := store.GetBySHA256(ctx, "abc") if blob != nil { t.Error("Delete() did not remove blob") } } func TestBlobStore_SHA256_UniqueConstraint(t *testing.T) { db := setupBlobTestDB(t) store := NewBlobStore(db) ctx := context.Background() store.Create(ctx, &model.FileBlob{SHA256: "dup", MinioKey: "files/dup1", FileSize: 100}) err := store.Create(ctx, &model.FileBlob{SHA256: "dup", MinioKey: "files/dup2", FileSize: 200}) if err == nil { t.Error("expected error for duplicate SHA256, got nil") } }