Optimize test suite performance (15-18x speedup)
- Add t.Parallel() to CLI and export/import tests for concurrent execution - Remove unnecessary 200ms sleep in daemon_autoimport_test (Execute forces sync) - Reduce filesystem settle wait from 100ms to 50ms on non-Windows - Optimize debouncer test sleeps (9 reductions, 30-50% faster) Results: - cmd/bd: 5+ minutes → 18 seconds - internal/importer: < 1 second - Most packages: < 2 seconds Closes bd-gpe7
This commit is contained in:
@@ -21,6 +21,7 @@ func setupCLITestDB(t *testing.T) string {
|
||||
}
|
||||
|
||||
func TestCLI_Ready(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := setupCLITestDB(t)
|
||||
runBD(t, tmpDir, "create", "Ready issue", "-p", "1")
|
||||
out := runBD(t, tmpDir, "ready")
|
||||
@@ -30,6 +31,7 @@ func TestCLI_Ready(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCLI_Create(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := setupCLITestDB(t)
|
||||
out := runBD(t, tmpDir, "create", "Test issue", "-p", "1", "--json")
|
||||
|
||||
@@ -43,6 +45,7 @@ func TestCLI_Create(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCLI_List(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := setupCLITestDB(t)
|
||||
runBD(t, tmpDir, "create", "First", "-p", "1")
|
||||
runBD(t, tmpDir, "create", "Second", "-p", "2")
|
||||
@@ -58,6 +61,7 @@ func TestCLI_List(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCLI_Update(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := setupCLITestDB(t)
|
||||
out := runBD(t, tmpDir, "create", "Issue to update", "-p", "1", "--json")
|
||||
|
||||
@@ -76,6 +80,7 @@ func TestCLI_Update(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCLI_Close(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := setupCLITestDB(t)
|
||||
out := runBD(t, tmpDir, "create", "Issue to close", "-p", "1", "--json")
|
||||
|
||||
@@ -94,6 +99,7 @@ func TestCLI_Close(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCLI_DepAdd(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := setupCLITestDB(t)
|
||||
|
||||
out1 := runBD(t, tmpDir, "create", "First", "-p", "1", "--json")
|
||||
@@ -113,6 +119,7 @@ func TestCLI_DepAdd(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCLI_DepRemove(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := setupCLITestDB(t)
|
||||
|
||||
out1 := runBD(t, tmpDir, "create", "First", "-p", "1", "--json")
|
||||
@@ -133,6 +140,7 @@ func TestCLI_DepRemove(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCLI_DepTree(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := setupCLITestDB(t)
|
||||
|
||||
out1 := runBD(t, tmpDir, "create", "Parent", "-p", "1", "--json")
|
||||
@@ -153,6 +161,7 @@ func TestCLI_DepTree(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCLI_Blocked(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := setupCLITestDB(t)
|
||||
|
||||
out1 := runBD(t, tmpDir, "create", "Blocker", "-p", "1", "--json")
|
||||
@@ -173,6 +182,7 @@ func TestCLI_Blocked(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCLI_Stats(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := setupCLITestDB(t)
|
||||
runBD(t, tmpDir, "create", "Issue 1", "-p", "1")
|
||||
runBD(t, tmpDir, "create", "Issue 2", "-p", "1")
|
||||
@@ -184,6 +194,7 @@ func TestCLI_Stats(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCLI_Show(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := setupCLITestDB(t)
|
||||
out := runBD(t, tmpDir, "create", "Show test", "-p", "1", "--json")
|
||||
|
||||
@@ -198,6 +209,7 @@ func TestCLI_Show(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCLI_Export(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := setupCLITestDB(t)
|
||||
runBD(t, tmpDir, "create", "Export test", "-p", "1")
|
||||
|
||||
@@ -210,6 +222,7 @@ func TestCLI_Export(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCLI_Import(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := setupCLITestDB(t)
|
||||
runBD(t, tmpDir, "create", "Import test", "-p", "1")
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ func TestDaemonAutoImportAfterGitPull(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
} else {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
|
||||
// Start daemon server in clone2
|
||||
@@ -232,10 +232,8 @@ func TestDaemonAutoImportAfterGitPull(t *testing.T) {
|
||||
// Agent B pulls
|
||||
runGitCmd(t, clone2Dir, "pull")
|
||||
|
||||
// Wait a bit for auto-import to process
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
// Query via daemon - should see priority 0
|
||||
// (Execute forces auto-import synchronously)
|
||||
socketPath := filepath.Join(clone2BeadsDir, "bd.sock")
|
||||
client, err := rpc.TryConnect(socketPath)
|
||||
if err != nil {
|
||||
|
||||
@@ -18,12 +18,12 @@ func TestDebouncer_BatchesMultipleTriggers(t *testing.T) {
|
||||
debouncer.Trigger()
|
||||
debouncer.Trigger()
|
||||
|
||||
time.Sleep(30 * time.Millisecond)
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
if got := atomic.LoadInt32(&count); got != 0 {
|
||||
t.Errorf("action fired too early: got %d, want 0", got)
|
||||
}
|
||||
|
||||
time.Sleep(40 * time.Millisecond)
|
||||
time.Sleep(35 * time.Millisecond)
|
||||
if got := atomic.LoadInt32(&count); got != 1 {
|
||||
t.Errorf("action should have fired once: got %d, want 1", got)
|
||||
}
|
||||
@@ -37,16 +37,16 @@ func TestDebouncer_ResetsTimerOnSubsequentTriggers(t *testing.T) {
|
||||
t.Cleanup(debouncer.Cancel)
|
||||
|
||||
debouncer.Trigger()
|
||||
time.Sleep(30 * time.Millisecond)
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
|
||||
debouncer.Trigger()
|
||||
time.Sleep(30 * time.Millisecond)
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
|
||||
if got := atomic.LoadInt32(&count); got != 0 {
|
||||
t.Errorf("action fired too early after timer reset: got %d, want 0", got)
|
||||
}
|
||||
|
||||
time.Sleep(30 * time.Millisecond)
|
||||
time.Sleep(35 * time.Millisecond)
|
||||
if got := atomic.LoadInt32(&count); got != 1 {
|
||||
t.Errorf("action should have fired once after final timer: got %d, want 1", got)
|
||||
}
|
||||
@@ -60,7 +60,7 @@ func TestDebouncer_CancelDuringWait(t *testing.T) {
|
||||
t.Cleanup(debouncer.Cancel)
|
||||
|
||||
debouncer.Trigger()
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
debouncer.Cancel()
|
||||
|
||||
@@ -80,7 +80,7 @@ func TestDebouncer_CancelWithNoPendingAction(t *testing.T) {
|
||||
debouncer.Cancel()
|
||||
|
||||
debouncer.Trigger()
|
||||
time.Sleep(70 * time.Millisecond)
|
||||
time.Sleep(60 * time.Millisecond)
|
||||
if got := atomic.LoadInt32(&count); got != 1 {
|
||||
t.Errorf("action should fire normally after cancel with no pending action: got %d, want 1", got)
|
||||
}
|
||||
@@ -108,7 +108,7 @@ func TestDebouncer_ThreadSafety(t *testing.T) {
|
||||
close(start)
|
||||
wg.Wait()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
time.Sleep(70 * time.Millisecond)
|
||||
|
||||
got := atomic.LoadInt32(&count)
|
||||
if got != 1 {
|
||||
@@ -157,19 +157,19 @@ func TestDebouncer_MultipleSequentialTriggerCycles(t *testing.T) {
|
||||
t.Cleanup(debouncer.Cancel)
|
||||
|
||||
debouncer.Trigger()
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
time.Sleep(40 * time.Millisecond)
|
||||
if got := atomic.LoadInt32(&count); got != 1 {
|
||||
t.Errorf("first cycle: got %d, want 1", got)
|
||||
}
|
||||
|
||||
debouncer.Trigger()
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
time.Sleep(40 * time.Millisecond)
|
||||
if got := atomic.LoadInt32(&count); got != 2 {
|
||||
t.Errorf("second cycle: got %d, want 2", got)
|
||||
}
|
||||
|
||||
debouncer.Trigger()
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
time.Sleep(40 * time.Millisecond)
|
||||
if got := atomic.LoadInt32(&count); got != 3 {
|
||||
t.Errorf("third cycle: got %d, want 3", got)
|
||||
}
|
||||
@@ -185,7 +185,7 @@ func TestDebouncer_CancelImmediatelyAfterTrigger(t *testing.T) {
|
||||
debouncer.Trigger()
|
||||
debouncer.Cancel()
|
||||
|
||||
time.Sleep(80 * time.Millisecond)
|
||||
time.Sleep(60 * time.Millisecond)
|
||||
if got := atomic.LoadInt32(&count); got != 0 {
|
||||
t.Errorf("action should not fire after immediate cancel: got %d, want 0", got)
|
||||
}
|
||||
|
||||
@@ -133,6 +133,7 @@ func (h *exportImportHelper) validateJSONLines(buf *bytes.Buffer, expectedCount
|
||||
}
|
||||
|
||||
func TestExportImport(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := t.TempDir()
|
||||
dbPath := filepath.Join(tmpDir, "test.db")
|
||||
store := newTestStoreWithPrefix(t, dbPath, "test")
|
||||
@@ -199,6 +200,7 @@ func TestExportImport(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestExportEmpty(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := t.TempDir()
|
||||
dbPath := filepath.Join(tmpDir, "empty.db")
|
||||
store := newTestStore(t, dbPath)
|
||||
@@ -216,6 +218,7 @@ func TestExportEmpty(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestImportInvalidJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
invalidJSON := []string{
|
||||
`{"id":"test-1"`, // Incomplete JSON
|
||||
`{"id":"test-1","title":}`, // Invalid syntax
|
||||
@@ -233,6 +236,7 @@ func TestImportInvalidJSON(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRoundTrip(t *testing.T) {
|
||||
t.Parallel()
|
||||
tmpDir := t.TempDir()
|
||||
dbPath := filepath.Join(tmpDir, "original.db")
|
||||
store := newTestStoreWithPrefix(t, dbPath, "test")
|
||||
|
||||
Reference in New Issue
Block a user