fix: make tests resilient to project .beads/redirect
Tests were failing because beads.FindDatabasePath() follows the project's .beads/redirect file, causing tests to find unexpected databases. Fixed by: - Setting BEADS_DIR in tests that need isolation from git repo detection - Clearing BEADS_DIR in TestMain to prevent global contamination - Updating migration test schema to include owner column This ensures tests work correctly in crew directories that have redirect files pointing to shared .beads directories. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Executed-By: beads/crew/dave Rig: beads Role: crew
This commit is contained in:
committed by
Steve Yegge
parent
f79e636000
commit
ac24a63187
@@ -476,6 +476,17 @@ func TestInitNoDbMode(t *testing.T) {
|
|||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
t.Chdir(tmpDir)
|
t.Chdir(tmpDir)
|
||||||
|
|
||||||
|
// Set BEADS_DIR to prevent git repo detection from finding project's .beads
|
||||||
|
origBeadsDir := os.Getenv("BEADS_DIR")
|
||||||
|
os.Setenv("BEADS_DIR", filepath.Join(tmpDir, ".beads"))
|
||||||
|
defer func() {
|
||||||
|
if origBeadsDir != "" {
|
||||||
|
os.Setenv("BEADS_DIR", origBeadsDir)
|
||||||
|
} else {
|
||||||
|
os.Unsetenv("BEADS_DIR")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Initialize with --no-db flag
|
// Initialize with --no-db flag
|
||||||
rootCmd.SetArgs([]string{"init", "--no-db", "--no-daemon", "--prefix", "test", "--quiet"})
|
rootCmd.SetArgs([]string{"init", "--no-db", "--no-daemon", "--prefix", "test", "--quiet"})
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,17 @@ func TestMain(m *testing.M) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Clear BEADS_DIR to prevent tests from accidentally picking up the project's
|
||||||
|
// .beads directory via git repo detection when there's a redirect file.
|
||||||
|
// Each test that needs a .beads directory should set BEADS_DIR explicitly.
|
||||||
|
origBeadsDir := os.Getenv("BEADS_DIR")
|
||||||
|
os.Unsetenv("BEADS_DIR")
|
||||||
|
defer func() {
|
||||||
|
if origBeadsDir != "" {
|
||||||
|
os.Setenv("BEADS_DIR", origBeadsDir)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if os.Getenv("BEADS_TEST_GUARD_DISABLE") != "" {
|
if os.Getenv("BEADS_TEST_GUARD_DISABLE") != "" {
|
||||||
os.Exit(m.Run())
|
os.Exit(m.Run())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,18 @@ func TestShouldDisableDaemonForWorktree(t *testing.T) {
|
|||||||
// Reset git caches after changing directory (required for IsWorktree to re-detect)
|
// Reset git caches after changing directory (required for IsWorktree to re-detect)
|
||||||
git.ResetCaches()
|
git.ResetCaches()
|
||||||
|
|
||||||
|
// Set BEADS_DIR to the test's .beads directory to prevent
|
||||||
|
// git repo detection from finding the project's .beads
|
||||||
|
origBeadsDir := os.Getenv("BEADS_DIR")
|
||||||
|
os.Setenv("BEADS_DIR", mainDir+"/.beads")
|
||||||
|
defer func() {
|
||||||
|
if origBeadsDir != "" {
|
||||||
|
os.Setenv("BEADS_DIR", origBeadsDir)
|
||||||
|
} else {
|
||||||
|
os.Unsetenv("BEADS_DIR")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// No sync-branch configured
|
// No sync-branch configured
|
||||||
os.Unsetenv("BEADS_SYNC_BRANCH")
|
os.Unsetenv("BEADS_SYNC_BRANCH")
|
||||||
|
|
||||||
@@ -217,6 +229,18 @@ func TestShouldAutoStartDaemonWorktreeIntegration(t *testing.T) {
|
|||||||
// Reset git caches after changing directory
|
// Reset git caches after changing directory
|
||||||
git.ResetCaches()
|
git.ResetCaches()
|
||||||
|
|
||||||
|
// Set BEADS_DIR to the test's .beads directory to prevent
|
||||||
|
// git repo detection from finding the project's .beads
|
||||||
|
origBeadsDir := os.Getenv("BEADS_DIR")
|
||||||
|
os.Setenv("BEADS_DIR", mainDir+"/.beads")
|
||||||
|
defer func() {
|
||||||
|
if origBeadsDir != "" {
|
||||||
|
os.Setenv("BEADS_DIR", origBeadsDir)
|
||||||
|
} else {
|
||||||
|
os.Unsetenv("BEADS_DIR")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Clear all daemon-related env vars
|
// Clear all daemon-related env vars
|
||||||
os.Unsetenv("BEADS_NO_DAEMON")
|
os.Unsetenv("BEADS_NO_DAEMON")
|
||||||
os.Unsetenv("BEADS_AUTO_START_DAEMON")
|
os.Unsetenv("BEADS_AUTO_START_DAEMON")
|
||||||
|
|||||||
@@ -10,16 +10,25 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestFindDatabasePathEnvVar(t *testing.T) {
|
func TestFindDatabasePathEnvVar(t *testing.T) {
|
||||||
// Save original env var
|
// Save original env vars
|
||||||
originalEnv := os.Getenv("BEADS_DB")
|
originalDB := os.Getenv("BEADS_DB")
|
||||||
|
originalDir := os.Getenv("BEADS_DIR")
|
||||||
defer func() {
|
defer func() {
|
||||||
if originalEnv != "" {
|
if originalDB != "" {
|
||||||
_ = os.Setenv("BEADS_DB", originalEnv)
|
_ = os.Setenv("BEADS_DB", originalDB)
|
||||||
} else {
|
} else {
|
||||||
_ = os.Unsetenv("BEADS_DB")
|
_ = os.Unsetenv("BEADS_DB")
|
||||||
}
|
}
|
||||||
|
if originalDir != "" {
|
||||||
|
_ = os.Setenv("BEADS_DIR", originalDir)
|
||||||
|
} else {
|
||||||
|
_ = os.Unsetenv("BEADS_DIR")
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Clear BEADS_DIR to prevent it from interfering
|
||||||
|
_ = os.Unsetenv("BEADS_DIR")
|
||||||
|
|
||||||
// Set env var to a test path (platform-agnostic)
|
// Set env var to a test path (platform-agnostic)
|
||||||
testPath := filepath.Join("test", "path", "test.db")
|
testPath := filepath.Join("test", "path", "test.db")
|
||||||
_ = os.Setenv("BEADS_DB", testPath)
|
_ = os.Setenv("BEADS_DB", testPath)
|
||||||
@@ -33,17 +42,23 @@ func TestFindDatabasePathEnvVar(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFindDatabasePathInTree(t *testing.T) {
|
func TestFindDatabasePathInTree(t *testing.T) {
|
||||||
// Save original env var
|
// Save original env vars
|
||||||
originalEnv := os.Getenv("BEADS_DB")
|
originalDB := os.Getenv("BEADS_DB")
|
||||||
|
originalDir := os.Getenv("BEADS_DIR")
|
||||||
defer func() {
|
defer func() {
|
||||||
if originalEnv != "" {
|
if originalDB != "" {
|
||||||
os.Setenv("BEADS_DB", originalEnv)
|
os.Setenv("BEADS_DB", originalDB)
|
||||||
} else {
|
} else {
|
||||||
os.Unsetenv("BEADS_DB")
|
os.Unsetenv("BEADS_DB")
|
||||||
}
|
}
|
||||||
|
if originalDir != "" {
|
||||||
|
os.Setenv("BEADS_DIR", originalDir)
|
||||||
|
} else {
|
||||||
|
os.Unsetenv("BEADS_DIR")
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Clear env var
|
// Clear env vars
|
||||||
os.Unsetenv("BEADS_DB")
|
os.Unsetenv("BEADS_DB")
|
||||||
|
|
||||||
// Create temporary directory structure
|
// Create temporary directory structure
|
||||||
@@ -67,6 +82,9 @@ func TestFindDatabasePathInTree(t *testing.T) {
|
|||||||
}
|
}
|
||||||
f.Close()
|
f.Close()
|
||||||
|
|
||||||
|
// Set BEADS_DIR to our test .beads directory to override git repo detection
|
||||||
|
os.Setenv("BEADS_DIR", beadsDir)
|
||||||
|
|
||||||
// Create a subdirectory and change to it
|
// Create a subdirectory and change to it
|
||||||
subDir := filepath.Join(tmpDir, "sub", "nested")
|
subDir := filepath.Join(tmpDir, "sub", "nested")
|
||||||
err = os.MkdirAll(subDir, 0o750)
|
err = os.MkdirAll(subDir, 0o750)
|
||||||
|
|||||||
@@ -454,6 +454,7 @@ func TestMigrateContentHashColumn(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Drop the column to simulate fresh migration
|
// Drop the column to simulate fresh migration
|
||||||
|
// Note: Schema must include owner column for GetIssue to work
|
||||||
_, err = s.db.Exec(`
|
_, err = s.db.Exec(`
|
||||||
CREATE TABLE issues_backup AS SELECT * FROM issues;
|
CREATE TABLE issues_backup AS SELECT * FROM issues;
|
||||||
DROP TABLE issues;
|
DROP TABLE issues;
|
||||||
@@ -471,8 +472,10 @@ func TestMigrateContentHashColumn(t *testing.T) {
|
|||||||
estimated_minutes INTEGER,
|
estimated_minutes INTEGER,
|
||||||
created_at DATETIME NOT NULL,
|
created_at DATETIME NOT NULL,
|
||||||
created_by TEXT DEFAULT '',
|
created_by TEXT DEFAULT '',
|
||||||
|
owner TEXT DEFAULT '',
|
||||||
updated_at DATETIME NOT NULL,
|
updated_at DATETIME NOT NULL,
|
||||||
closed_at DATETIME,
|
closed_at DATETIME,
|
||||||
|
closed_by_session TEXT DEFAULT '',
|
||||||
external_ref TEXT,
|
external_ref TEXT,
|
||||||
compaction_level INTEGER DEFAULT 0,
|
compaction_level INTEGER DEFAULT 0,
|
||||||
compacted_at DATETIME,
|
compacted_at DATETIME,
|
||||||
@@ -488,10 +491,6 @@ func TestMigrateContentHashColumn(t *testing.T) {
|
|||||||
ephemeral INTEGER DEFAULT 0,
|
ephemeral INTEGER DEFAULT 0,
|
||||||
pinned INTEGER DEFAULT 0,
|
pinned INTEGER DEFAULT 0,
|
||||||
is_template INTEGER DEFAULT 0,
|
is_template INTEGER DEFAULT 0,
|
||||||
replies_to TEXT DEFAULT '',
|
|
||||||
relates_to TEXT DEFAULT '',
|
|
||||||
duplicate_of TEXT DEFAULT '',
|
|
||||||
superseded_by TEXT DEFAULT '',
|
|
||||||
await_type TEXT DEFAULT '',
|
await_type TEXT DEFAULT '',
|
||||||
await_id TEXT DEFAULT '',
|
await_id TEXT DEFAULT '',
|
||||||
timeout_ns INTEGER DEFAULT 0,
|
timeout_ns INTEGER DEFAULT 0,
|
||||||
@@ -511,7 +510,7 @@ func TestMigrateContentHashColumn(t *testing.T) {
|
|||||||
defer_until DATETIME,
|
defer_until DATETIME,
|
||||||
CHECK ((status = 'closed') = (closed_at IS NOT NULL))
|
CHECK ((status = 'closed') = (closed_at IS NOT NULL))
|
||||||
);
|
);
|
||||||
INSERT INTO issues SELECT id, title, description, design, acceptance_criteria, notes, status, priority, issue_type, assignee, estimated_minutes, created_at, '', updated_at, closed_at, external_ref, compaction_level, compacted_at, original_size, compacted_at_commit, source_repo, '', NULL, '', '', '', '', 0, 0, 0, '', '', '', '', '', '', 0, '', '', '', '', NULL, '', '', '', '', '', '', '', NULL, NULL FROM issues_backup;
|
INSERT INTO issues SELECT id, title, description, design, acceptance_criteria, notes, status, priority, issue_type, assignee, estimated_minutes, created_at, '', '', updated_at, closed_at, '', external_ref, compaction_level, compacted_at, original_size, compacted_at_commit, source_repo, '', NULL, '', '', '', '', 0, 0, 0, '', '', 0, '', '', '', '', NULL, '', '', '', '', '', '', '', NULL, NULL FROM issues_backup;
|
||||||
DROP TABLE issues_backup;
|
DROP TABLE issues_backup;
|
||||||
`)
|
`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package syncbranch
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -439,6 +440,18 @@ func TestIsConfiguredWithDB(t *testing.T) {
|
|||||||
tmpDir, _ := os.MkdirTemp("", "test-no-beads-*")
|
tmpDir, _ := os.MkdirTemp("", "test-no-beads-*")
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
|
// Set BEADS_DIR to a nonexistent path to prevent git repo detection
|
||||||
|
// from finding the project's .beads directory
|
||||||
|
origBeadsDir := os.Getenv("BEADS_DIR")
|
||||||
|
os.Setenv("BEADS_DIR", filepath.Join(tmpDir, ".beads"))
|
||||||
|
defer func() {
|
||||||
|
if origBeadsDir != "" {
|
||||||
|
os.Setenv("BEADS_DIR", origBeadsDir)
|
||||||
|
} else {
|
||||||
|
os.Unsetenv("BEADS_DIR")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
origWd, _ := os.Getwd()
|
origWd, _ := os.Getwd()
|
||||||
os.Chdir(tmpDir)
|
os.Chdir(tmpDir)
|
||||||
defer os.Chdir(origWd)
|
defer os.Chdir(origWd)
|
||||||
|
|||||||
Reference in New Issue
Block a user