Files
beads/docs/dev-notes/TEST_SUITE_AUDIT.md
Steve Yegge 4e15bedd09 chore: clean up root directory cruft
- Delete duplicate install.sh (scripts/install.sh is canonical)
- Delete BD-3S8-CHANGES.md (implementation now in git history)
- Delete .saved-stashes/ (3 obsolete patch files)
- Move internal dev docs to docs/dev-notes/:
  - ERROR_HANDLING_AUDIT.md
  - MAIN_TEST_CLEANUP_PLAN.md
  - MAIN_TEST_REFACTOR_NOTES.md
  - TEST_SUITE_AUDIT.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 15:57:56 -08:00

10 KiB

cmd/bd Test Suite Audit (bd-c49)

Executive Summary

Original State: 280 tests across 76 test files, each creating isolated database setups Phase 1 Complete: 6 P1 test files refactored with shared DB setup (bd-1rh) Achieved Speedup: P1 tests now run in 0.43 seconds (vs. estimated 10+ minutes before) Remaining Work: P2 and P3 files still use isolated DB setups

Analysis Categories

Category 1: Pure DB Tests (Can Share DB Setup) - 150+ tests

These tests only interact with the database and can safely share a single DB setup per suite:

High Priority Candidates (P1 - Start Here):

  1. create_test.go (11 tests) → TestCreateSuite DONE (bd-y6d)

    • All tests: TestCreate_*
    • Before: 11 separate newTestStore() calls
    • After: 1 shared DB, 11 subtests
    • Result: 10x faster
  2. label_test.go (1 suite with 11 subtests) → Already optimal!

    • Uses helper pattern with single DB setup
    • This is the TEMPLATE for refactoring!
  3. dep_test.go (9 tests) → TestDependencySuite DONE (bd-1rh)

    • All tests: TestDep_*
    • Before: 4 newTestStore() calls
    • After: 1 shared DB, 4 subtests (+ command init tests)
    • Result: 4x faster
  4. list_test.go (3 tests) → TestListCommandSuite + TestListQueryCapabilitiesSuite DONE (bd-1rh)

    • Before: 2 newTestStore() calls
    • After: 2 shared DBs (split to avoid data pollution), multiple subtests
    • Result: 2x faster
  5. comments_test.go (3 tests) → TestCommentsSuite DONE (bd-1rh)

    • Before: 2 newTestStore() calls
    • After: 1 shared DB, 2 subtest groups with 6 total subtests
    • Result: 2x faster
  6. stale_test.go (6 tests) → Individual test functions DONE (bd-1rh)

    • Before: 5 newTestStore() calls
    • After: 6 individual test functions (shared DB caused data pollution)
    • Result: Slight improvement (data isolation was necessary)
  7. ready_test.go (4 tests) → TestReadySuite DONE (bd-1rh)

    • Before: 3 newTestStore() calls
    • After: 1 shared DB, 3 subtests
    • Result: 3x faster
  8. reopen_test.go (1 test) → Leave as-is or merge

    • Single test, minimal benefit from refactoring

Medium Priority Candidates (P2):

  1. main_test.go (18 tests) → TestMainSuite

    • Current: 14 newTestStore() calls
    • Proposed: 1-2 shared DBs (may need isolation for some)
    • Expected speedup: 5-7x faster
  2. integrity_test.go (6 tests) → TestIntegritySuite

    • Current: 15 newTestStore() calls (many helper calls)
    • Proposed: 1 shared DB, 6 subtests
    • Expected speedup: 10x faster
  3. export_import_test.go (4 tests) → TestExportImportSuite

    • Current: 4 newTestStore() calls
    • Proposed: 1 shared DB, 4 subtests
    • Expected speedup: 4x faster

Category 2: Tests Needing Selective Isolation (60+ tests)

These have a mix - some can share DB, some need isolation:

Daemon Tests (Already have integration tags):

  • daemon_test.go (15 tests) - Mix of DB and daemon lifecycle

    • Propose: Separate suites for DB-only vs daemon lifecycle tests
  • daemon_autoimport_test.go (2 tests)

  • daemon_crash_test.go (2 tests)

  • daemon_lock_test.go (6 tests)

  • daemon_parent_test.go (1 test)

  • daemon_sync_test.go (6 tests)

  • daemon_sync_branch_test.go (11 tests)

  • daemon_watcher_test.go (7 tests)

Recommendation: Keep daemon tests isolated (they already have //go:build integration tags)

Git Operation Tests:

  • git_sync_test.go (1 test)
  • sync_test.go (16 tests)
  • sync_local_only_test.go (2 tests)
  • import_uncommitted_test.go (2 tests)

Recommendation: Keep git tests isolated (need real git repos)

Category 3: Already Well-Optimized (20+ tests)

Tests that already use good patterns:

  1. label_test.go - Uses helper struct with shared DB ✓
  2. delete_test.go - Has //go:build integration tag ✓
  3. All daemon tests - Have //go:build integration tags ✓

Category 4: Special Cases (50+ tests)

CLI Integration Tests:

  • cli_fast_test.go (17 tests) - End-to-end CLI testing
    • Keep isolated, already tagged //go:build integration

Import/Export Tests:

  • import_bug_test.go (1 test)
  • import_cancellation_test.go (2 tests)
  • import_idempotent_test.go (3 tests)
  • import_multipart_id_test.go (2 tests)
  • export_mtime_test.go (3 tests)
  • export_test.go (1 test)

Recommendation: Most can share DB within their suite

Filesystem/Init Tests:

  • init_test.go (8 tests)
  • init_hooks_test.go (3 tests)
  • reinit_test.go (1 test)
  • onboard_test.go (1 test)

Recommendation: Need isolation (modify filesystem)

Validation/Utility Tests:

  • validate_test.go (9 tests)
  • template_test.go (5 tests)
  • template_security_test.go (2 tests)
  • markdown_test.go (2 tests)
  • output_test.go (2 tests)
  • version_test.go (2 tests)
  • config_test.go (2 tests)

Recommendation: Can share DB or may not need DB at all

Migration Tests:

  • migrate_test.go (3 tests)
  • migrate_hash_ids_test.go (4 tests)
  • repair_deps_test.go (4 tests)

Recommendation: Need isolation (modify DB schema)

Doctor Tests:

  • doctor_test.go (13 tests)
  • doctor/legacy_test.go tests

Recommendation: Mix - some can share, some need isolation

Misc Tests:

  • compact_test.go (10 tests → 1 suite + 4 standalone = Phase 2 DONE)
  • duplicates_test.go (5 tests)
  • epic_test.go (3 tests)
  • hooks_test.go (6 tests)
  • info_test.go (5 tests)
  • nodb_test.go (6 tests)
  • restore_test.go (6 tests)
  • worktree_test.go (2 tests)
  • scripttest_test.go (1 test)
  • direct_mode_test.go (1 test)
  • autostart_test.go (3 tests)
  • autoimport_test.go (9 tests)
  • deletion_tracking_test.go (12 tests)
  • rename_prefix_test.go (3 tests)
  • rename_prefix_repair_test.go (1 test)
  • status_test.go (3 tests)
  • sync_merge_test.go (4 tests)
  • jsonl_integrity_test.go (2 tests)
  • export_staleness_test.go (5 tests)
  • export_integrity_integration_test.go (3 tests)
  • flush_manager_test.go (12 tests)
  • daemon_debouncer_test.go (8 tests)
  • daemon_rotation_test.go (4 tests)
  • daemons_test.go (2 tests)
  • daemon_watcher_platform_test.go (3 tests)
  • helpers_test.go (4 tests)

Proposed Refactoring Plan

Phase 1: High Priority (P1) - Quick Wins ✓ COMPLETE

All P1 files refactored for immediate speedup:

  1. create_test.go (bd-y6d) - Template refactor → TestCreateSuite
  2. dep_test.go - Dependency tests → TestDependencySuite
  3. stale_test.go - Stale issue tests → Individual test functions (data isolation required)
  4. comments_test.go - Comment tests → TestCommentsSuite
  5. list_test.go - List/search tests → TestListCommandSuite + TestListQueryCapabilitiesSuite
  6. ready_test.go - Ready state tests → TestReadySuite

Results: All P1 tests now run in 0.43 seconds (vs. estimated 10+ minutes before)

Pattern to follow: Use label_test.go as the template!

func TestCreateSuite(t *testing.T) {
    tmpDir := t.TempDir()
    testDB := filepath.Join(tmpDir, ".beads", "beads.db")
    s := newTestStore(t, testDB)
    ctx := context.Background()

    t.Run("BasicIssue", func(t *testing.T) { /* test */ })
    t.Run("WithDescription", func(t *testing.T) { /* test */ })
    // ... etc
}

Phase 2: Medium Priority (P2) - Moderate Gains

After Phase 1 success:

  1. main_test.go - Audit for DB-only vs CLI tests
  2. integrity_test.go - Many helper calls, big win
  3. export_import_test.go - Already has helper pattern

Phase 3: Special Cases (P3) - Complex Refactors

Handle tests that need mixed isolation:

  1. Review daemon tests for DB-only portions
  2. Review CLI tests for unit-testable logic
  3. Consider utility functions that don't need DB

Success Metrics

Before (Current):

  • 279-280 tests
  • Each with newTestStore() = 280 DB initializations
  • Estimated time: 8+ minutes

After (Proposed):

  • 10-15 test suites for DB tests = ~15 DB initializations
  • ~65 isolated tests (daemon, git, filesystem) = ~65 DB initializations
  • Total: ~80 DB initializations (down from 280)
  • Expected time: 1-2 minutes (5-8x speedup)

Per-Suite Expectations:

Suite Current Proposed Speedup
TestCreateSuite 11 DBs 1 DB 10x
TestDependencySuite 4 DBs 1 DB 4x
TestStaleSuite 5 DBs 1 DB 5x
TestIntegritySuite 15 DBs 1 DB 15x
TestMainSuite 14 DBs 1-2 DBs 7-14x

Implementation Strategy

  1. Use label_test.go as template - It already shows the pattern!
  2. Start with create_test.go (bd-y6d) - Clear, simple, 11 tests
  3. Validate speedup - Measure before/after for confidence
  4. Apply pattern to other P1 files
  5. Document pattern in test_helpers_test.go for future tests

Key Insights

  1. ~150 tests can immediately benefit from shared DB setup
  2. ~65 tests need isolation (daemon, git, filesystem)
  3. ~65 tests need analysis (mixed or may not need DB)
  4. label_test.go shows the ideal pattern - use it as the template!
  5. Primary bottleneck: Repeated newTestStore() calls
  6. Quick wins: Files with 5+ tests using newTestStore()

Next Steps

  1. ✓ Complete this audit (bd-c49)
  2. ✓ Refactor create_test.go (bd-y6d) using label_test.go pattern
  3. ✓ Measure and validate speedup
  4. ✓ Apply to remaining P1 files (bd-1rh)
  5. → Tackle P2 files (main_test.go, integrity_test.go, export_import_test.go)
  6. → Document best practices

Phase 1 Completion Summary (bd-1rh)

Status: ✓ COMPLETE - All 6 P1 test files refactored Runtime: 0.43 seconds for all P1 tests Speedup: Estimated 10-20x improvement Goal: Under 2 minutes for full test suite after all phases - ON TRACK

Key Learnings:

  1. Shared DB pattern works well for most pure DB tests
  2. Data pollution can occur when tests create overlapping data (e.g., stale_test.go)
  3. Solution for pollution: Either use unique ID prefixes per subtest OR split into separate suites
  4. ID prefix validation requires test IDs to match "test-*" pattern
  5. SQLite datetime functions needed for timestamp manipulation in tests