Skip to content

Commit 52e9b14

Browse files
easelclaude
andcommitted
test(rig): add tests for agent bead creation during rig add
Add tests to verify that rig.Manager.AddRig correctly creates witness and refinery agent beads via initAgentBeads. Also improve mock bd: - Fix mock bd to handle --no-daemon --allow-stale global flags - Return valid JSON for create commands with bead ID - Log create commands for test verification - Add TestRigAddCreatesAgentBeads integration test - Add TestAgentBeadIDs unit test for bead ID generation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3ebb111 commit 52e9b14

1 file changed

Lines changed: 140 additions & 35 deletions

File tree

internal/cmd/rig_integration_test.go

Lines changed: 140 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -101,44 +101,47 @@ func setupTestTown(t *testing.T) string {
101101

102102
// mockBdCommand creates a fake bd binary that simulates bd behavior.
103103
// This avoids needing bd installed for tests.
104-
func mockBdCommand(t *testing.T) {
104+
func mockBdCommand(t *testing.T) string {
105105
t.Helper()
106106

107107
binDir := t.TempDir()
108108
bdPath := filepath.Join(binDir, "bd")
109+
logPath := filepath.Join(binDir, "bd.log")
109110

110111
// Create a script that simulates bd init and other commands
112+
// Also logs all create commands for verification.
113+
// Note: beads.run() prepends --no-daemon --allow-stale to all commands,
114+
// so we need to find the actual command in the argument list.
111115
script := `#!/bin/sh
112116
# Mock bd for testing
113-
114-
case "$1" in
117+
LOG_FILE="` + logPath + `"
118+
119+
# Find the actual command (skip global flags like --no-daemon, --allow-stale)
120+
cmd=""
121+
for arg in "$@"; do
122+
case "$arg" in
123+
--*) ;; # skip flags
124+
*) cmd="$arg"; break ;;
125+
esac
126+
done
127+
128+
case "$cmd" in
115129
init)
116130
# Create .beads directory and config.yaml
117131
mkdir -p .beads
118132
prefix="gt"
133+
# Handle both --prefix=value and --prefix value forms
134+
next_is_prefix=false
119135
for arg in "$@"; do
120-
case "$arg" in
121-
--prefix=*) prefix="${arg#--prefix=}" ;;
122-
--prefix)
123-
# Next arg is the prefix
124-
shift
125-
if [ -n "$1" ] && [ "$1" != "--"* ]; then
126-
prefix="$1"
127-
fi
128-
;;
129-
esac
130-
shift
131-
done
132-
# Handle positional --prefix VALUE
133-
shift # skip 'init'
134-
while [ $# -gt 0 ]; do
135-
case "$1" in
136-
--prefix)
137-
shift
138-
prefix="$1"
139-
;;
140-
esac
141-
shift
136+
if [ "$next_is_prefix" = true ]; then
137+
prefix="$arg"
138+
next_is_prefix=false
139+
else
140+
case "$arg" in
141+
--prefix=*) prefix="${arg#--prefix=}" ;;
142+
--prefix) next_is_prefix=true ;;
143+
esac
144+
fi
142145
done
143146
echo "prefix: $prefix" > .beads/config.yaml
144147
exit 0
@@ -151,8 +154,17 @@ case "$1" in
151154
exit 1
152155
;;
153156
create)
154-
# Return minimal JSON for agent bead creation
155-
echo '{}'
157+
# Log all create commands for verification
158+
echo "$@" >> "$LOG_FILE"
159+
# Extract the ID from --id=xxx argument
160+
bead_id=""
161+
for arg in "$@"; do
162+
case "$arg" in
163+
--id=*) bead_id="${arg#--id=}" ;;
164+
esac
165+
done
166+
# Return valid JSON for bead creation
167+
echo "{\"id\":\"$bead_id\",\"status\":\"open\",\"created_at\":\"2025-01-01T00:00:00Z\"}"
156168
exit 0
157169
;;
158170
mol|list)
@@ -169,12 +181,14 @@ esac
169181

170182
// Prepend to PATH
171183
t.Setenv("PATH", binDir+string(os.PathListSeparator)+os.Getenv("PATH"))
184+
185+
return logPath
172186
}
173187

174188
// TestRigAddCreatesCorrectStructure verifies that gt rig add creates
175189
// the expected directory structure.
176190
func TestRigAddCreatesCorrectStructure(t *testing.T) {
177-
mockBdCommand(t)
191+
_ = mockBdCommand(t)
178192
townRoot := setupTestTown(t)
179193
gitURL := createTestGitRepo(t, "testproject")
180194

@@ -293,7 +307,7 @@ func TestRigAddCreatesCorrectStructure(t *testing.T) {
293307
// TestRigAddInitializesBeads verifies that beads is initialized with
294308
// the correct prefix.
295309
func TestRigAddInitializesBeads(t *testing.T) {
296-
mockBdCommand(t)
310+
_ = mockBdCommand(t)
297311
townRoot := setupTestTown(t)
298312
gitURL := createTestGitRepo(t, "beadstest")
299313

@@ -389,7 +403,7 @@ func TestRigAddInitializesBeads(t *testing.T) {
389403
// TestRigAddUpdatesRoutes verifies that routes.jsonl is updated
390404
// with the new rig's route.
391405
func TestRigAddUpdatesRoutes(t *testing.T) {
392-
mockBdCommand(t)
406+
_ = mockBdCommand(t)
393407
townRoot := setupTestTown(t)
394408
gitURL := createTestGitRepo(t, "routetest")
395409

@@ -458,7 +472,7 @@ func TestRigAddUpdatesRoutes(t *testing.T) {
458472
// TestRigAddUpdatesRigsJson verifies that rigs.json is updated
459473
// with the new rig entry.
460474
func TestRigAddUpdatesRigsJson(t *testing.T) {
461-
mockBdCommand(t)
475+
_ = mockBdCommand(t)
462476
townRoot := setupTestTown(t)
463477
gitURL := createTestGitRepo(t, "jsontest")
464478

@@ -510,7 +524,7 @@ func TestRigAddUpdatesRigsJson(t *testing.T) {
510524
// TestRigAddDerivesPrefix verifies that when no prefix is specified,
511525
// one is derived from the rig name.
512526
func TestRigAddDerivesPrefix(t *testing.T) {
513-
mockBdCommand(t)
527+
_ = mockBdCommand(t)
514528
townRoot := setupTestTown(t)
515529
gitURL := createTestGitRepo(t, "myproject")
516530

@@ -541,7 +555,7 @@ func TestRigAddDerivesPrefix(t *testing.T) {
541555
// TestRigAddCreatesRigConfig verifies that config.json contains
542556
// the correct rig configuration.
543557
func TestRigAddCreatesRigConfig(t *testing.T) {
544-
mockBdCommand(t)
558+
_ = mockBdCommand(t)
545559
townRoot := setupTestTown(t)
546560
gitURL := createTestGitRepo(t, "configtest")
547561

@@ -596,7 +610,7 @@ func TestRigAddCreatesRigConfig(t *testing.T) {
596610

597611
// TestRigAddCreatesAgentDirs verifies that agent state files are created.
598612
func TestRigAddCreatesAgentDirs(t *testing.T) {
599-
mockBdCommand(t)
613+
_ = mockBdCommand(t)
600614
townRoot := setupTestTown(t)
601615
gitURL := createTestGitRepo(t, "agenttest")
602616

@@ -641,7 +655,7 @@ func TestRigAddCreatesAgentDirs(t *testing.T) {
641655
// TestRigAddRejectsInvalidNames verifies that rig names with invalid
642656
// characters are rejected.
643657
func TestRigAddRejectsInvalidNames(t *testing.T) {
644-
mockBdCommand(t)
658+
_ = mockBdCommand(t)
645659
townRoot := setupTestTown(t)
646660
gitURL := createTestGitRepo(t, "validname")
647661

@@ -677,3 +691,94 @@ func TestRigAddRejectsInvalidNames(t *testing.T) {
677691
})
678692
}
679693
}
694+
695+
// TestRigAddCreatesAgentBeads verifies that gt rig add creates
696+
// witness and refinery agent beads via the manager's initAgentBeads.
697+
func TestRigAddCreatesAgentBeads(t *testing.T) {
698+
bdLogPath := mockBdCommand(t)
699+
townRoot := setupTestTown(t)
700+
gitURL := createTestGitRepo(t, "agentbeadtest")
701+
702+
rigsPath := filepath.Join(townRoot, "mayor", "rigs.json")
703+
rigsConfig, err := config.LoadRigsConfig(rigsPath)
704+
if err != nil {
705+
t.Fatalf("load rigs.json: %v", err)
706+
}
707+
708+
g := git.NewGit(townRoot)
709+
mgr := rig.NewManager(townRoot, rigsConfig, g)
710+
711+
// AddRig internally calls initAgentBeads which creates witness and refinery beads
712+
newRig, err := mgr.AddRig(rig.AddRigOptions{
713+
Name: "agentbeadtest",
714+
GitURL: gitURL,
715+
BeadsPrefix: "ab",
716+
})
717+
if err != nil {
718+
t.Fatalf("AddRig: %v", err)
719+
}
720+
721+
// Verify the mock bd was called with correct create commands
722+
logContent, err := os.ReadFile(bdLogPath)
723+
if err != nil {
724+
t.Fatalf("reading bd log: %v", err)
725+
}
726+
logStr := string(logContent)
727+
728+
// Expected bead IDs that initAgentBeads should create
729+
witnessID := beads.WitnessBeadIDWithPrefix(newRig.Config.Prefix, "agentbeadtest")
730+
refineryID := beads.RefineryBeadIDWithPrefix(newRig.Config.Prefix, "agentbeadtest")
731+
732+
expectedIDs := []struct {
733+
id string
734+
desc string
735+
}{
736+
{witnessID, "witness agent bead"},
737+
{refineryID, "refinery agent bead"},
738+
}
739+
740+
for _, expected := range expectedIDs {
741+
if !strings.Contains(logStr, expected.id) {
742+
t.Errorf("bd create log should contain %s (%s), got:\n%s", expected.id, expected.desc, logStr)
743+
}
744+
}
745+
746+
// Verify correct prefix is used (ab-)
747+
if !strings.Contains(logStr, "ab-") {
748+
t.Errorf("bd create log should contain prefix 'ab-', got:\n%s", logStr)
749+
}
750+
}
751+
752+
// TestAgentBeadIDs verifies the agent bead ID generation functions.
753+
func TestAgentBeadIDs(t *testing.T) {
754+
tests := []struct {
755+
name string
756+
fn func() string
757+
expected string
758+
}{
759+
{
760+
"WitnessBeadIDWithPrefix",
761+
func() string { return beads.WitnessBeadIDWithPrefix("ab", "myrig") },
762+
"ab-myrig-witness",
763+
},
764+
{
765+
"RefineryBeadIDWithPrefix",
766+
func() string { return beads.RefineryBeadIDWithPrefix("ab", "myrig") },
767+
"ab-myrig-refinery",
768+
},
769+
{
770+
"RigBeadIDWithPrefix",
771+
func() string { return beads.RigBeadIDWithPrefix("ab", "myrig") },
772+
"ab-rig-myrig",
773+
},
774+
}
775+
776+
for _, tc := range tests {
777+
t.Run(tc.name, func(t *testing.T) {
778+
result := tc.fn()
779+
if result != tc.expected {
780+
t.Errorf("got %q, want %q", result, tc.expected)
781+
}
782+
})
783+
}
784+
}

0 commit comments

Comments
 (0)