f99010fae1
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Windows) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Has been cancelled
212 lines
5.4 KiB
Go
212 lines
5.4 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/gofrs/flock"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.kenn.io/agentsview/internal/config"
|
|
"go.kenn.io/agentsview/internal/db"
|
|
)
|
|
|
|
func writeDBConfigForTest(t *testing.T) (string, config.Config) {
|
|
t.Helper()
|
|
dataDir := t.TempDir()
|
|
return dataDir, config.Config{
|
|
DataDir: dataDir,
|
|
DBPath: filepath.Join(dataDir, "sessions.db"),
|
|
}
|
|
}
|
|
|
|
func acquireWriteOwnerLockForTest(
|
|
t *testing.T,
|
|
dataDir string,
|
|
) *writeOwnerLock {
|
|
t.Helper()
|
|
lock, err := tryAcquireWriteOwnerLock(dataDir)
|
|
require.NoError(t, err)
|
|
return lock
|
|
}
|
|
|
|
func holdWriteOwnerLockForTest(
|
|
t *testing.T,
|
|
dataDir string,
|
|
) *writeOwnerLock {
|
|
t.Helper()
|
|
lock := acquireWriteOwnerLockForTest(t, dataDir)
|
|
t.Cleanup(func() { require.NoError(t, lock.Close()) })
|
|
return lock
|
|
}
|
|
|
|
func assertOpenWriteDBRefused(
|
|
t *testing.T,
|
|
cfg config.Config,
|
|
wantSubstrings ...string,
|
|
) error {
|
|
t.Helper()
|
|
database, lock, err := openWriteDB(context.Background(), cfg)
|
|
require.Error(t, err)
|
|
require.Nil(t, database)
|
|
require.Nil(t, lock)
|
|
assertErrorContainsAll(t, err, wantSubstrings...)
|
|
return err
|
|
}
|
|
|
|
func requireOpenWriteDBForTest(
|
|
t *testing.T,
|
|
cfg config.Config,
|
|
) (*db.DB, *writeOwnerLock) {
|
|
t.Helper()
|
|
database, lock, err := openWriteDB(context.Background(), cfg)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, database)
|
|
require.NotNil(t, lock)
|
|
return database, lock
|
|
}
|
|
|
|
func holdBackgroundLaunchLockForTest(t *testing.T, dataDir string) *flock.Flock {
|
|
t.Helper()
|
|
require.NoError(t, os.MkdirAll(dataDir, 0o700))
|
|
launchLock, ok := acquireBackgroundLaunchLock(dataDir)
|
|
require.True(t, ok)
|
|
t.Cleanup(func() { require.NoError(t, launchLock.Unlock()) })
|
|
return launchLock
|
|
}
|
|
|
|
func holdExternalStartupLockForTest(t *testing.T, dataDir string) *flock.Flock {
|
|
t.Helper()
|
|
lockPath, err := runtimeStore(dataDir).LockPath()
|
|
require.NoError(t, err)
|
|
startLock := flock.New(lockPath)
|
|
locked, err := startLock.TryLock()
|
|
require.NoError(t, err)
|
|
require.True(t, locked)
|
|
t.Cleanup(func() { require.NoError(t, startLock.Unlock()) })
|
|
return startLock
|
|
}
|
|
|
|
func assertErrorContainsAll(
|
|
t *testing.T,
|
|
err error,
|
|
substrings ...string,
|
|
) {
|
|
t.Helper()
|
|
require.Error(t, err)
|
|
for _, substr := range substrings {
|
|
assert.Contains(t, err.Error(), substr)
|
|
}
|
|
}
|
|
|
|
func TestWriteOwnerLockPathUsesDataDir(t *testing.T) {
|
|
dataDir := filepath.Join(t.TempDir(), "agentsview-data")
|
|
|
|
assert.Equal(
|
|
t,
|
|
filepath.Join(dataDir, "db.write.lock"),
|
|
writeOwnerLockPath(dataDir),
|
|
)
|
|
}
|
|
|
|
func TestAcquireWriteOwnerLockExcludesSecondOwner(t *testing.T) {
|
|
dataDir := t.TempDir()
|
|
|
|
first, err := acquireWriteOwnerLock(context.Background(), dataDir)
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() { require.NoError(t, first.Close()) })
|
|
|
|
second, err := tryAcquireWriteOwnerLock(dataDir)
|
|
require.Error(t, err)
|
|
require.Nil(t, second)
|
|
assertErrorContainsAll(t, err, writeOwnerLockPath(dataDir),
|
|
"agentsview daemon stop")
|
|
}
|
|
|
|
func TestWriteOwnerLockReleaseAllowsNextOwner(t *testing.T) {
|
|
dataDir := t.TempDir()
|
|
|
|
first := acquireWriteOwnerLockForTest(t, dataDir)
|
|
require.NoError(t, first.Close())
|
|
|
|
second := acquireWriteOwnerLockForTest(t, dataDir)
|
|
require.NoError(t, second.Close())
|
|
}
|
|
|
|
func TestWriteOwnerLockErrorMentionsDaemonStop(t *testing.T) {
|
|
dataDir := t.TempDir()
|
|
|
|
holdWriteOwnerLockForTest(t, dataDir)
|
|
|
|
_, err := tryAcquireWriteOwnerLock(dataDir)
|
|
assertErrorContainsAll(t, err, "agentsview daemon stop", "idle timeout")
|
|
}
|
|
|
|
func TestOpenWriteDBRefusesSecondOwner(t *testing.T) {
|
|
dataDir, cfg := writeDBConfigForTest(t)
|
|
|
|
holdWriteOwnerLockForTest(t, dataDir)
|
|
|
|
assertOpenWriteDBRefused(t, cfg, writeOwnerLockPath(dataDir))
|
|
}
|
|
|
|
func TestOpenWriteDBReleasesOwnerAfterClose(t *testing.T) {
|
|
dataDir, cfg := writeDBConfigForTest(t)
|
|
|
|
database, lock := requireOpenWriteDBForTest(t, cfg)
|
|
closeWriteDB(database, lock)
|
|
|
|
next := acquireWriteOwnerLockForTest(t, dataDir)
|
|
require.NoError(t, next.Close())
|
|
}
|
|
|
|
func TestOpenWriteDBRefusesLiveWritableRuntime(t *testing.T) {
|
|
dataDir, cfg := writeDBConfigForTest(t)
|
|
_, err := WriteDaemonRuntime(dataDir, "127.0.0.1", 9, "test", false)
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() { RemoveDaemonRuntime(dataDir) })
|
|
|
|
assertOpenWriteDBRefused(t, cfg, "refusing to write directly",
|
|
"agentsview daemon stop")
|
|
}
|
|
|
|
func TestOpenWriteDBAllowsStartupLockHeldByCurrentServe(t *testing.T) {
|
|
dataDir, cfg := writeDBConfigForTest(t)
|
|
MarkDaemonStarting(dataDir)
|
|
t.Cleanup(func() { UnmarkDaemonStarting(dataDir) })
|
|
|
|
database, lock := requireOpenWriteDBForTest(t, cfg)
|
|
closeWriteDB(database, lock)
|
|
}
|
|
|
|
func TestOpenWriteDBRefusesExternalStartupLock(t *testing.T) {
|
|
dataDir, cfg := writeDBConfigForTest(t)
|
|
holdExternalStartupLockForTest(t, dataDir)
|
|
|
|
err := assertOpenWriteDBRefused(t, cfg)
|
|
assert.EqualError(t, err,
|
|
"local daemon is starting and owns the SQLite archive; refusing to "+
|
|
"write directly. Retry once it is ready")
|
|
}
|
|
|
|
func TestOpenWriteDBRefusesBackgroundLaunchLock(t *testing.T) {
|
|
dataDir, cfg := writeDBConfigForTest(t)
|
|
holdBackgroundLaunchLockForTest(t, dataDir)
|
|
|
|
err := assertOpenWriteDBRefused(t, cfg)
|
|
assert.EqualError(t, err,
|
|
"local daemon launch is in progress and owns the SQLite archive; "+
|
|
"refusing to write directly. Retry once it is ready")
|
|
}
|
|
|
|
func TestOpenWriteDBAllowsBackgroundChildWithLaunchLock(t *testing.T) {
|
|
dataDir, cfg := writeDBConfigForTest(t)
|
|
t.Setenv(backgroundChildEnvVar, "1")
|
|
holdBackgroundLaunchLockForTest(t, dataDir)
|
|
|
|
database, lock := requireOpenWriteDBForTest(t, cfg)
|
|
closeWriteDB(database, lock)
|
|
}
|