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.
127 lines
2.8 KiB
Go
127 lines
2.8 KiB
Go
package pidlock_test
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"sneak.berlin/go/vaultik/internal/pidlock"
|
|
)
|
|
|
|
func TestAcquireAndRelease(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
|
|
// Acquire lock
|
|
lock, err := pidlock.Acquire(tmpDir)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, lock)
|
|
|
|
// Verify PID file exists with our PID
|
|
pidPath := filepath.Join(tmpDir, "vaultik.pid")
|
|
data, err := os.ReadFile(pidPath) //nolint:gosec // G304: test's own temp file
|
|
require.NoError(t, err)
|
|
pid, err := strconv.Atoi(string(data))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, os.Getpid(), pid)
|
|
|
|
// Release lock
|
|
err = lock.Release()
|
|
require.NoError(t, err)
|
|
|
|
// Verify PID file is gone
|
|
_, err = os.Stat(pidPath)
|
|
assert.True(t, os.IsNotExist(err))
|
|
}
|
|
|
|
func TestAcquireBlocksSecondInstance(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
|
|
// Acquire first lock
|
|
lock1, err := pidlock.Acquire(tmpDir)
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, lock1)
|
|
defer func() { _ = lock1.Release() }()
|
|
|
|
// Try to acquire second lock - should fail
|
|
lock2, err := pidlock.Acquire(tmpDir)
|
|
require.ErrorIs(t, err, pidlock.ErrAlreadyRunning)
|
|
assert.Nil(t, lock2)
|
|
}
|
|
|
|
func TestAcquireWithStaleLock(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
|
|
// Write a stale PID file (PID that doesn't exist)
|
|
stalePID := 999999999 // Unlikely to be a real process
|
|
pidPath := filepath.Join(tmpDir, "vaultik.pid")
|
|
err := os.WriteFile(pidPath, []byte(strconv.Itoa(stalePID)), 0600)
|
|
require.NoError(t, err)
|
|
|
|
// Should be able to acquire lock (stale lock is cleaned up)
|
|
lock, err := pidlock.Acquire(tmpDir)
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, lock)
|
|
defer func() { _ = lock.Release() }()
|
|
|
|
// Verify our PID is now in the file
|
|
data, err := os.ReadFile(pidPath) //nolint:gosec // G304: test's own temp file
|
|
require.NoError(t, err)
|
|
pid, err := strconv.Atoi(string(data))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, os.Getpid(), pid)
|
|
}
|
|
|
|
func TestReleaseIsIdempotent(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
|
|
lock, err := pidlock.Acquire(tmpDir)
|
|
require.NoError(t, err)
|
|
|
|
// Release multiple times - should not error
|
|
err = lock.Release()
|
|
require.NoError(t, err)
|
|
|
|
err = lock.Release()
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestReleaseNilLock(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var lock *pidlock.Lock
|
|
|
|
err := lock.Release()
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestAcquireCreatesDirectory(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir := t.TempDir()
|
|
nestedDir := filepath.Join(tmpDir, "nested", "dir")
|
|
|
|
lock, err := pidlock.Acquire(nestedDir)
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, lock)
|
|
defer func() { _ = lock.Release() }()
|
|
|
|
// Verify directory was created
|
|
info, err := os.Stat(nestedDir)
|
|
require.NoError(t, err)
|
|
assert.True(t, info.IsDir())
|
|
}
|