Fix every finding surfaced by the canonical .golangci.yml with golangci-lint v2.12.2 (refs #61), behavior-preserving throughout: - err113: dynamic errors replaced with package-level sentinels and %w wrapping; direct comparisons converted to errors.Is - goprintffuncname: printf-style helpers renamed with an f suffix (ui.Writer message methods, cli.ReportErrorf, database.Fatalf, vaultik stdoutf) and all call sites updated - revive: stuttering type names renamed (blob.Handler, blob.WithReader, blob.ChunkPosition, storage.URL, storage.Info), doc comments added, unused parameters blanked, package comments added - contextcheck/noctx: ctx threaded through blob.Packer (AddChunk/Flush/FinalizeBlob/PackChunks) and scanner call sites; context-aware exec and sql variants used - funlen/cyclop/gocognit/nestif/dupl: oversized or duplicated functions split into focused helpers across production and test code - paralleltest/tparallel/thelper/usetesting/testpackage: tests parallelized where safe (global log.Initialize kept in the serial phase), helpers marked, t.TempDir adopted, external test packages where only exported API is used - gosec: integer conversions clamped or justified, header timeouts added, remaining findings suppressed with per-site justifications - mnd/goconst/lll/wsl_v5/nlreturn/noinlineerr/errcheck and other mechanical findings fixed directly Remove the deprecated log.LogOptions alias (callers migrated to log.Options). make check is green.
172 lines
3.9 KiB
Go
172 lines
3.9 KiB
Go
package database_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"sneak.berlin/go/vaultik/internal/database"
|
|
"sneak.berlin/go/vaultik/internal/types"
|
|
)
|
|
|
|
func TestBlobRepository(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db, cleanup := setupTestDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
repo := database.NewBlobRepository(db)
|
|
|
|
// Test Create
|
|
blob := &database.Blob{
|
|
ID: types.NewBlobID(),
|
|
Hash: types.BlobHash("blobhash123"),
|
|
CreatedTS: time.Now().Truncate(time.Second),
|
|
}
|
|
|
|
err := repo.Create(ctx, nil, blob)
|
|
if err != nil {
|
|
t.Fatalf("failed to create blob: %v", err)
|
|
}
|
|
|
|
// Test GetByHash
|
|
retrieved, err := repo.GetByHash(ctx, blob.Hash.String())
|
|
if err != nil {
|
|
t.Fatalf("failed to get blob: %v", err)
|
|
}
|
|
|
|
if retrieved == nil {
|
|
t.Fatal("expected blob, got nil")
|
|
}
|
|
|
|
if retrieved.Hash != blob.Hash {
|
|
t.Errorf("blob hash mismatch: got %s, want %s", retrieved.Hash, blob.Hash)
|
|
}
|
|
|
|
if !retrieved.CreatedTS.Equal(blob.CreatedTS) {
|
|
t.Errorf("created timestamp mismatch: got %v, want %v",
|
|
retrieved.CreatedTS, blob.CreatedTS)
|
|
}
|
|
|
|
// Test GetByID
|
|
retrievedByID, err := repo.GetByID(ctx, blob.ID.String())
|
|
if err != nil {
|
|
t.Fatalf("failed to get blob by ID: %v", err)
|
|
}
|
|
|
|
if retrievedByID == nil {
|
|
t.Fatal("expected blob, got nil")
|
|
}
|
|
|
|
if retrievedByID.ID != blob.ID {
|
|
t.Errorf("blob ID mismatch: got %s, want %s", retrievedByID.ID, blob.ID)
|
|
}
|
|
|
|
// Test with second blob
|
|
blob2 := &database.Blob{
|
|
ID: types.NewBlobID(),
|
|
Hash: types.BlobHash("blobhash456"),
|
|
CreatedTS: time.Now().Truncate(time.Second),
|
|
}
|
|
|
|
err = repo.Create(ctx, nil, blob2)
|
|
if err != nil {
|
|
t.Fatalf("failed to create second blob: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestBlobRepositoryUpdates(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db, cleanup := setupTestDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
repo := database.NewBlobRepository(db)
|
|
|
|
blob := &database.Blob{
|
|
ID: types.NewBlobID(),
|
|
Hash: types.BlobHash("blobhash123"),
|
|
CreatedTS: time.Now().Truncate(time.Second),
|
|
}
|
|
|
|
err := repo.Create(ctx, nil, blob)
|
|
if err != nil {
|
|
t.Fatalf("failed to create blob: %v", err)
|
|
}
|
|
|
|
// Test UpdateFinished
|
|
now := time.Now()
|
|
|
|
err = repo.UpdateFinished(ctx, nil, blob.ID.String(), blob.Hash.String(), 1000, 500)
|
|
if err != nil {
|
|
t.Fatalf("failed to update blob as finished: %v", err)
|
|
}
|
|
|
|
// Verify update
|
|
updated, err := repo.GetByID(ctx, blob.ID.String())
|
|
if err != nil {
|
|
t.Fatalf("failed to get updated blob: %v", err)
|
|
}
|
|
|
|
if updated.FinishedTS == nil {
|
|
t.Fatal("expected finished timestamp to be set")
|
|
}
|
|
|
|
if updated.UncompressedSize != 1000 {
|
|
t.Errorf("expected uncompressed size 1000, got %d", updated.UncompressedSize)
|
|
}
|
|
|
|
if updated.CompressedSize != 500 {
|
|
t.Errorf("expected compressed size 500, got %d", updated.CompressedSize)
|
|
}
|
|
|
|
// Test UpdateUploaded
|
|
err = repo.UpdateUploaded(ctx, nil, blob.ID.String())
|
|
if err != nil {
|
|
t.Fatalf("failed to update blob as uploaded: %v", err)
|
|
}
|
|
|
|
// Verify upload update
|
|
uploaded, err := repo.GetByID(ctx, blob.ID.String())
|
|
if err != nil {
|
|
t.Fatalf("failed to get uploaded blob: %v", err)
|
|
}
|
|
|
|
if uploaded.UploadedTS == nil {
|
|
t.Fatal("expected uploaded timestamp to be set")
|
|
}
|
|
// Allow 1 second tolerance for timestamp comparison
|
|
if uploaded.UploadedTS.Before(now.Add(-1 * time.Second)) {
|
|
t.Error("uploaded timestamp should be around test time")
|
|
}
|
|
}
|
|
|
|
func TestBlobRepositoryDuplicate(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db, cleanup := setupTestDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
repo := database.NewBlobRepository(db)
|
|
|
|
blob := &database.Blob{
|
|
ID: types.NewBlobID(),
|
|
Hash: types.BlobHash("duplicate_blob"),
|
|
CreatedTS: time.Now().Truncate(time.Second),
|
|
}
|
|
|
|
err := repo.Create(ctx, nil, blob)
|
|
if err != nil {
|
|
t.Fatalf("failed to create blob: %v", err)
|
|
}
|
|
|
|
// Try to create duplicate - should fail due to unique constraint
|
|
err = repo.Create(ctx, nil, blob)
|
|
if err == nil {
|
|
t.Error("expected error for duplicate blob")
|
|
}
|
|
}
|