Remediate all lint findings under the canonical golangci-lint config
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.
This commit is contained in:
@@ -3,6 +3,7 @@ package snapshot_test
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -14,9 +15,114 @@ import (
|
||||
"sneak.berlin/go/vaultik/internal/types"
|
||||
)
|
||||
|
||||
// Shared test fixture values for the snapshot_test package.
|
||||
const (
|
||||
// testHost is the hostname recorded on test snapshot rows.
|
||||
testHost = "test-host"
|
||||
|
||||
// testVersion is the vaultik version recorded on test snapshot rows.
|
||||
testVersion = "test"
|
||||
|
||||
// testAgePublicKey is the fixed age public key used for test encryption.
|
||||
testAgePublicKey = "age1ezrjmfpwsc95svdg0y54mums3zevgzu0x0ecq2f7tp8a05gl0sjq9q9wjg"
|
||||
)
|
||||
|
||||
// TestMain initializes the shared logger once, before any tests run, so
|
||||
// parallel tests never race on the logger's global state.
|
||||
func TestMain(m *testing.M) {
|
||||
log.Initialize(log.Config{})
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
// createTestSnapshotRecord inserts an empty snapshot row used as the
|
||||
// association target for scan tests.
|
||||
func createTestSnapshotRecord(
|
||||
ctx context.Context, t *testing.T, repos *database.Repositories, snapshotID string,
|
||||
) {
|
||||
t.Helper()
|
||||
|
||||
err := repos.WithTx(ctx, func(ctx context.Context, tx *sql.Tx) error {
|
||||
snapshot := &database.Snapshot{
|
||||
ID: types.SnapshotID(snapshotID),
|
||||
Hostname: testHost,
|
||||
VaultikVersion: testVersion,
|
||||
StartedAt: time.Now(),
|
||||
CompletedAt: nil,
|
||||
FileCount: 0,
|
||||
ChunkCount: 0,
|
||||
BlobCount: 0,
|
||||
TotalSize: 0,
|
||||
BlobSize: 0,
|
||||
CompressionRatio: 1.0,
|
||||
}
|
||||
|
||||
return repos.Snapshots.Create(ctx, tx, snapshot)
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create snapshot: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// verifySimpleScanDatabase checks the database contents produced by
|
||||
// TestScannerSimpleDirectory's scan.
|
||||
func verifySimpleScanDatabase(
|
||||
ctx context.Context, t *testing.T, repos *database.Repositories,
|
||||
) {
|
||||
t.Helper()
|
||||
|
||||
// Verify files in database - includes regular files and directories
|
||||
files, err := repos.Files.ListByPrefix(ctx, "/source")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to list files: %v", err)
|
||||
}
|
||||
|
||||
// 6 regular files + 3 directories (/source, /source/subdir, /source/subdir2)
|
||||
if len(files) != 9 {
|
||||
t.Errorf("expected 9 entries in database (6 files + 3 dirs), got %d", len(files))
|
||||
}
|
||||
|
||||
// Verify specific file
|
||||
file1, err := repos.Files.GetByPath(ctx, "/source/file1.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get file1.txt: %v", err)
|
||||
}
|
||||
|
||||
if file1.Size != 13 {
|
||||
t.Errorf("expected file1.txt size 13, got %d", file1.Size)
|
||||
}
|
||||
|
||||
if file1.Mode != 0644 {
|
||||
t.Errorf("expected file1.txt mode 0644, got %o", file1.Mode)
|
||||
}
|
||||
|
||||
// Verify chunks were created
|
||||
chunks, err := repos.FileChunks.GetByFile(ctx, "/source/file1.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get chunks for file1.txt: %v", err)
|
||||
}
|
||||
|
||||
if len(chunks) != 1 { // Small file should be one chunk
|
||||
t.Errorf("expected 1 chunk for file1.txt, got %d", len(chunks))
|
||||
}
|
||||
|
||||
// Verify deduplication - file3.txt and file4.txt have different content
|
||||
// but we should still have the correct number of unique chunks
|
||||
allChunks, err := repos.Chunks.List(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to list all chunks: %v", err)
|
||||
}
|
||||
|
||||
// We should have at most 6 chunks (one per unique file content)
|
||||
// Empty file might not create a chunk
|
||||
if len(allChunks) > 6 {
|
||||
t.Errorf("expected at most 6 chunks, got %d", len(allChunks))
|
||||
}
|
||||
}
|
||||
|
||||
func TestScannerSimpleDirectory(t *testing.T) {
|
||||
// Initialize logger for tests
|
||||
log.Initialize(log.Config{})
|
||||
t.Parallel()
|
||||
|
||||
// Create in-memory filesystem
|
||||
fs := afero.NewMemMapFs()
|
||||
@@ -74,38 +180,17 @@ func TestScannerSimpleDirectory(t *testing.T) {
|
||||
Repositories: repos,
|
||||
MaxBlobSize: int64(1024 * 1024), // 1MB blobs
|
||||
CompressionLevel: 3,
|
||||
AgeRecipients: []string{"age1ezrjmfpwsc95svdg0y54mums3zevgzu0x0ecq2f7tp8a05gl0sjq9q9wjg"}, // Test public key
|
||||
AgeRecipients: []string{testAgePublicKey},
|
||||
})
|
||||
|
||||
// Create a snapshot record for testing
|
||||
ctx := context.Background()
|
||||
snapshotID := "test-snapshot-001"
|
||||
|
||||
err = repos.WithTx(ctx, func(ctx context.Context, tx *sql.Tx) error {
|
||||
snapshot := &database.Snapshot{
|
||||
ID: types.SnapshotID(snapshotID),
|
||||
Hostname: "test-host",
|
||||
VaultikVersion: "test",
|
||||
StartedAt: time.Now(),
|
||||
CompletedAt: nil,
|
||||
FileCount: 0,
|
||||
ChunkCount: 0,
|
||||
BlobCount: 0,
|
||||
TotalSize: 0,
|
||||
BlobSize: 0,
|
||||
CompressionRatio: 1.0,
|
||||
}
|
||||
|
||||
return repos.Snapshots.Create(ctx, tx, snapshot)
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create snapshot: %v", err)
|
||||
}
|
||||
createTestSnapshotRecord(ctx, t, repos, snapshotID)
|
||||
|
||||
// Scan the directory
|
||||
var result *snapshot.ScanResult
|
||||
|
||||
result, err = scanner.Scan(ctx, "/source", snapshotID)
|
||||
result, err := scanner.Scan(ctx, "/source", snapshotID)
|
||||
if err != nil {
|
||||
t.Fatalf("scan failed: %v", err)
|
||||
}
|
||||
@@ -120,58 +205,13 @@ func TestScannerSimpleDirectory(t *testing.T) {
|
||||
t.Errorf("expected at least 97 bytes scanned, got %d", result.BytesScanned)
|
||||
}
|
||||
|
||||
// Verify files in database - includes regular files and directories
|
||||
files, err := repos.Files.ListByPrefix(ctx, "/source")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to list files: %v", err)
|
||||
}
|
||||
|
||||
// 6 regular files + 3 directories (/source, /source/subdir, /source/subdir2)
|
||||
if len(files) != 9 {
|
||||
t.Errorf("expected 9 entries in database (6 files + 3 dirs), got %d", len(files))
|
||||
}
|
||||
|
||||
// Verify specific file
|
||||
file1, err := repos.Files.GetByPath(ctx, "/source/file1.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get file1.txt: %v", err)
|
||||
}
|
||||
|
||||
if file1.Size != 13 {
|
||||
t.Errorf("expected file1.txt size 13, got %d", file1.Size)
|
||||
}
|
||||
|
||||
if file1.Mode != 0644 {
|
||||
t.Errorf("expected file1.txt mode 0644, got %o", file1.Mode)
|
||||
}
|
||||
|
||||
// Verify chunks were created
|
||||
chunks, err := repos.FileChunks.GetByFile(ctx, "/source/file1.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get chunks for file1.txt: %v", err)
|
||||
}
|
||||
|
||||
if len(chunks) != 1 { // Small file should be one chunk
|
||||
t.Errorf("expected 1 chunk for file1.txt, got %d", len(chunks))
|
||||
}
|
||||
|
||||
// Verify deduplication - file3.txt and file4.txt have different content
|
||||
// but we should still have the correct number of unique chunks
|
||||
allChunks, err := repos.Chunks.List(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to list all chunks: %v", err)
|
||||
}
|
||||
|
||||
// We should have at most 6 chunks (one per unique file content)
|
||||
// Empty file might not create a chunk
|
||||
if len(allChunks) > 6 {
|
||||
t.Errorf("expected at most 6 chunks, got %d", len(allChunks))
|
||||
}
|
||||
verifySimpleScanDatabase(ctx, t, repos)
|
||||
}
|
||||
|
||||
func TestScannerLargeFile(t *testing.T) {
|
||||
// Initialize logger for tests
|
||||
log.Initialize(log.Config{})
|
||||
t.Parallel()
|
||||
|
||||
// Create in-memory filesystem
|
||||
fs := afero.NewMemMapFs()
|
||||
@@ -182,14 +222,17 @@ func TestScannerLargeFile(t *testing.T) {
|
||||
// Fill with pseudo-random data to ensure chunk boundaries
|
||||
for i := range largeContent {
|
||||
// Simple pseudo-random generator for deterministic tests
|
||||
//nolint:gosec // G115: intentional byte truncation of test data
|
||||
largeContent[i] = byte((i * 7919) ^ (i >> 3))
|
||||
}
|
||||
|
||||
if err := fs.MkdirAll("/source", 0755); err != nil {
|
||||
err := fs.MkdirAll("/source", 0755)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := afero.WriteFile(fs, "/source/large.bin", largeContent, 0644); err != nil {
|
||||
err = afero.WriteFile(fs, "/source/large.bin", largeContent, 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -214,38 +257,17 @@ func TestScannerLargeFile(t *testing.T) {
|
||||
Repositories: repos,
|
||||
MaxBlobSize: int64(1024 * 1024),
|
||||
CompressionLevel: 3,
|
||||
AgeRecipients: []string{"age1ezrjmfpwsc95svdg0y54mums3zevgzu0x0ecq2f7tp8a05gl0sjq9q9wjg"}, // Test public key
|
||||
AgeRecipients: []string{testAgePublicKey},
|
||||
})
|
||||
|
||||
// Create a snapshot record for testing
|
||||
ctx := context.Background()
|
||||
snapshotID := "test-snapshot-001"
|
||||
|
||||
err = repos.WithTx(ctx, func(ctx context.Context, tx *sql.Tx) error {
|
||||
snapshot := &database.Snapshot{
|
||||
ID: types.SnapshotID(snapshotID),
|
||||
Hostname: "test-host",
|
||||
VaultikVersion: "test",
|
||||
StartedAt: time.Now(),
|
||||
CompletedAt: nil,
|
||||
FileCount: 0,
|
||||
ChunkCount: 0,
|
||||
BlobCount: 0,
|
||||
TotalSize: 0,
|
||||
BlobSize: 0,
|
||||
CompressionRatio: 1.0,
|
||||
}
|
||||
|
||||
return repos.Snapshots.Create(ctx, tx, snapshot)
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create snapshot: %v", err)
|
||||
}
|
||||
createTestSnapshotRecord(ctx, t, repos, snapshotID)
|
||||
|
||||
// Scan the directory
|
||||
var result *snapshot.ScanResult
|
||||
|
||||
result, err = scanner.Scan(ctx, "/source", snapshotID)
|
||||
result, err := scanner.Scan(ctx, "/source", snapshotID)
|
||||
if err != nil {
|
||||
t.Fatalf("scan failed: %v", err)
|
||||
}
|
||||
@@ -257,7 +279,8 @@ func TestScannerLargeFile(t *testing.T) {
|
||||
|
||||
// The file size should be at least 1MB
|
||||
if result.BytesScanned < 1024*1024 {
|
||||
t.Errorf("expected at least %d bytes scanned, got %d", 1024*1024, result.BytesScanned)
|
||||
t.Errorf("expected at least %d bytes scanned, got %d",
|
||||
1024*1024, result.BytesScanned)
|
||||
}
|
||||
|
||||
// Verify chunks
|
||||
|
||||
Reference in New Issue
Block a user