Files
beads/cmd/bd/sync_merge_test.go
Steve Yegge c4c5c8063a Fix: Change default JSONL filename from beads.jsonl to issues.jsonl
The canonical beads database name is issues.jsonl. Tens of thousands of users
have issues.jsonl, and beads.jsonl was only used by the Beads project itself
due to git history pollution.

Changes:
- Updated bd doctor to warn about beads.jsonl instead of issues.jsonl
- Changed default config from beads.jsonl to issues.jsonl
- Reversed precedence in checkGitForIssues to prefer issues.jsonl
- Updated git merge driver config to use issues.jsonl
- Updated all tests to expect issues.jsonl as the default

issues.jsonl is now the canonical default; beads.jsonl is legacy

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 23:34:22 -08:00

221 lines
5.5 KiB
Go

package main
import (
"context"
"os"
"path/filepath"
"testing"
"time"
"github.com/steveyegge/beads/internal/storage/sqlite"
"github.com/steveyegge/beads/internal/types"
)
// setupTestStore creates a test storage with issue_prefix configured
func setupTestStore(t *testing.T, dbPath string) *sqlite.SQLiteStorage {
t.Helper()
store, err := sqlite.New(context.Background(), dbPath)
if err != nil {
t.Fatalf("Failed to create store: %v", err)
}
ctx := context.Background()
if err := store.SetConfig(ctx, "issue_prefix", "bd"); err != nil {
store.Close()
t.Fatalf("Failed to set issue_prefix: %v", err)
}
return store
}
// TestDBNeedsExport_InSync verifies dbNeedsExport returns false when DB and JSONL are in sync
func TestDBNeedsExport_InSync(t *testing.T) {
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, "beads.db")
jsonlPath := filepath.Join(tmpDir, "issues.jsonl")
store := setupTestStore(t, dbPath)
defer store.Close()
ctx := context.Background()
// Create an issue in DB
issue := &types.Issue{
Title: "Test Issue",
Status: types.StatusOpen,
Priority: 1,
IssueType: types.TypeBug,
}
err := store.CreateIssue(ctx, issue, "test-user")
if err != nil {
t.Fatalf("Failed to create issue: %v", err)
}
// Export to JSONL
if err := exportToJSONLWithStore(ctx, store, jsonlPath); err != nil {
t.Fatalf("Failed to export: %v", err)
}
// Wait a moment to ensure DB mtime isn't newer
time.Sleep(10 * time.Millisecond)
// Touch JSONL to make it newer than DB
now := time.Now()
if err := os.Chtimes(jsonlPath, now, now); err != nil {
t.Fatalf("Failed to touch JSONL: %v", err)
}
// DB and JSONL should be in sync
needsExport, err := dbNeedsExport(ctx, store, jsonlPath)
if err != nil {
t.Fatalf("dbNeedsExport failed: %v", err)
}
if needsExport {
t.Errorf("Expected needsExport=false (DB and JSONL in sync), got true")
}
}
// TestDBNeedsExport_DBNewer verifies dbNeedsExport returns true when DB is modified
func TestDBNeedsExport_DBNewer(t *testing.T) {
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, "beads.db")
jsonlPath := filepath.Join(tmpDir, "issues.jsonl")
store := setupTestStore(t, dbPath)
defer store.Close()
ctx := context.Background()
// Create and export issue
issue1 := &types.Issue{
Title: "Test Issue",
Status: types.StatusOpen,
Priority: 1,
IssueType: types.TypeBug,
}
err := store.CreateIssue(ctx, issue1, "test-user")
if err != nil {
t.Fatalf("Failed to create issue: %v", err)
}
if err := exportToJSONLWithStore(ctx, store, jsonlPath); err != nil {
t.Fatalf("Failed to export: %v", err)
}
// Wait and modify DB
time.Sleep(10 * time.Millisecond)
issue2 := &types.Issue{
Title: "Another Issue",
Status: types.StatusOpen,
Priority: 2,
IssueType: types.TypeTask,
}
err = store.CreateIssue(ctx, issue2, "test-user")
if err != nil {
t.Fatalf("Failed to create second issue: %v", err)
}
// DB is newer, should need export
needsExport, err := dbNeedsExport(ctx, store, jsonlPath)
if err != nil {
t.Fatalf("dbNeedsExport failed: %v", err)
}
if !needsExport {
t.Errorf("Expected needsExport=true (DB modified), got false")
}
}
// TestDBNeedsExport_CountMismatch verifies dbNeedsExport returns true when counts differ
func TestDBNeedsExport_CountMismatch(t *testing.T) {
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, "beads.db")
jsonlPath := filepath.Join(tmpDir, "issues.jsonl")
store := setupTestStore(t, dbPath)
defer store.Close()
ctx := context.Background()
// Create and export issue
issue1 := &types.Issue{
Title: "Test Issue",
Status: types.StatusOpen,
Priority: 1,
IssueType: types.TypeBug,
}
err := store.CreateIssue(ctx, issue1, "test-user")
if err != nil {
t.Fatalf("Failed to create issue: %v", err)
}
if err := exportToJSONLWithStore(ctx, store, jsonlPath); err != nil {
t.Fatalf("Failed to export: %v", err)
}
// Add another issue to DB but don't export
issue2 := &types.Issue{
Title: "Another Issue",
Status: types.StatusOpen,
Priority: 2,
IssueType: types.TypeTask,
}
err = store.CreateIssue(ctx, issue2, "test-user")
if err != nil {
t.Fatalf("Failed to create second issue: %v", err)
}
// Make JSONL appear newer (but counts differ)
time.Sleep(10 * time.Millisecond)
now := time.Now().Add(1 * time.Hour) // Way in the future
if err := os.Chtimes(jsonlPath, now, now); err != nil {
t.Fatalf("Failed to touch JSONL: %v", err)
}
// Counts mismatch, should need export
needsExport, err := dbNeedsExport(ctx, store, jsonlPath)
if err != nil {
t.Fatalf("dbNeedsExport failed: %v", err)
}
if !needsExport {
t.Errorf("Expected needsExport=true (count mismatch), got false")
}
}
// TestDBNeedsExport_NoJSONL verifies dbNeedsExport returns true when JSONL doesn't exist
func TestDBNeedsExport_NoJSONL(t *testing.T) {
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, "beads.db")
jsonlPath := filepath.Join(tmpDir, "issues.jsonl")
store := setupTestStore(t, dbPath)
defer store.Close()
ctx := context.Background()
// Create issue but don't export
issue := &types.Issue{
Title: "Test Issue",
Status: types.StatusOpen,
Priority: 1,
IssueType: types.TypeBug,
}
err := store.CreateIssue(ctx, issue, "test-user")
if err != nil {
t.Fatalf("Failed to create issue: %v", err)
}
// JSONL doesn't exist, should need export
needsExport, err := dbNeedsExport(ctx, store, jsonlPath)
if err != nil {
t.Fatalf("dbNeedsExport failed: %v", err)
}
if !needsExport {
t.Fatalf("Expected needsExport=true (JSONL missing), got false")
}
}