test: add ephemeral flag tests for spawnMolecule (bd-phin)
- Add TestSpawnMoleculeEphemeralFlag: verifies DB-based spawn - Add TestSpawnMoleculeFromFormulaEphemeral: verifies formula-based spawn - Both tests confirm Ephemeral flag is set correctly - Tests also verify ephemeral issues excluded from ready work 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2364,3 +2364,166 @@ func TestCalculateBlockingDepths(t *testing.T) {
|
||||
t.Errorf("step3 depth = %d, want 3", depths["step3"])
|
||||
}
|
||||
}
|
||||
|
||||
// TestSpawnMoleculeEphemeralFlag verifies that spawnMolecule with ephemeral=true
|
||||
// creates issues with the Ephemeral flag set (bd-phin)
|
||||
func TestSpawnMoleculeEphemeralFlag(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
dbPath := t.TempDir() + "/test.db"
|
||||
s, err := sqlite.New(ctx, dbPath)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create store: %v", err)
|
||||
}
|
||||
defer s.Close()
|
||||
if err := s.SetConfig(ctx, "issue_prefix", "test"); err != nil {
|
||||
t.Fatalf("Failed to set config: %v", err)
|
||||
}
|
||||
|
||||
// Create a template with a child (IDs will be auto-generated)
|
||||
root := &types.Issue{
|
||||
Title: "Template Epic",
|
||||
Status: types.StatusOpen,
|
||||
Priority: 2,
|
||||
IssueType: types.TypeEpic,
|
||||
Labels: []string{MoleculeLabel}, // Required for loadTemplateSubgraph
|
||||
}
|
||||
child := &types.Issue{
|
||||
Title: "Template Task",
|
||||
Status: types.StatusOpen,
|
||||
Priority: 2,
|
||||
IssueType: types.TypeTask,
|
||||
}
|
||||
|
||||
if err := s.CreateIssue(ctx, root, "test"); err != nil {
|
||||
t.Fatalf("Failed to create template root: %v", err)
|
||||
}
|
||||
if err := s.CreateIssue(ctx, child, "test"); err != nil {
|
||||
t.Fatalf("Failed to create template child: %v", err)
|
||||
}
|
||||
|
||||
// Add parent-child dependency
|
||||
if err := s.AddDependency(ctx, &types.Dependency{
|
||||
IssueID: child.ID,
|
||||
DependsOnID: root.ID,
|
||||
Type: types.DepParentChild,
|
||||
}, "test"); err != nil {
|
||||
t.Fatalf("Failed to add parent-child dependency: %v", err)
|
||||
}
|
||||
|
||||
// Load subgraph
|
||||
subgraph, err := loadTemplateSubgraph(ctx, s, root.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to load subgraph: %v", err)
|
||||
}
|
||||
|
||||
// Spawn with ephemeral=true
|
||||
result, err := spawnMolecule(ctx, s, subgraph, nil, "", "test", true, "eph")
|
||||
if err != nil {
|
||||
t.Fatalf("spawnMolecule failed: %v", err)
|
||||
}
|
||||
|
||||
// Verify all spawned issues have Ephemeral=true
|
||||
for oldID, newID := range result.IDMapping {
|
||||
spawned, err := s.GetIssue(ctx, newID)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get spawned issue %s: %v", newID, err)
|
||||
}
|
||||
if !spawned.Ephemeral {
|
||||
t.Errorf("Spawned issue %s (from %s) should have Ephemeral=true, got false", newID, oldID)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify spawned issues have the correct prefix
|
||||
for _, newID := range result.IDMapping {
|
||||
if !strings.HasPrefix(newID, "test-eph-") {
|
||||
t.Errorf("Spawned issue ID %s should have prefix 'test-eph-'", newID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestSpawnMoleculeFromFormulaEphemeral verifies that spawning from a cooked formula
|
||||
// with ephemeral=true creates issues with the Ephemeral flag set (bd-phin)
|
||||
func TestSpawnMoleculeFromFormulaEphemeral(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
dbPath := t.TempDir() + "/test.db"
|
||||
s, err := sqlite.New(ctx, dbPath)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create store: %v", err)
|
||||
}
|
||||
defer s.Close()
|
||||
if err := s.SetConfig(ctx, "issue_prefix", "test"); err != nil {
|
||||
t.Fatalf("Failed to set config: %v", err)
|
||||
}
|
||||
|
||||
// Create a minimal in-memory subgraph (simulating cookFormulaToSubgraph output)
|
||||
root := &types.Issue{
|
||||
ID: "test-formula",
|
||||
Title: "Test Formula",
|
||||
Status: types.StatusOpen,
|
||||
Priority: 2,
|
||||
IssueType: types.TypeEpic,
|
||||
IsTemplate: true,
|
||||
}
|
||||
step := &types.Issue{
|
||||
ID: "test-formula.step1",
|
||||
Title: "Step 1",
|
||||
Status: types.StatusOpen,
|
||||
Priority: 2,
|
||||
IssueType: types.TypeTask,
|
||||
IsTemplate: true,
|
||||
}
|
||||
|
||||
subgraph := &TemplateSubgraph{
|
||||
Root: root,
|
||||
Issues: []*types.Issue{root, step},
|
||||
Dependencies: []*types.Dependency{
|
||||
{
|
||||
IssueID: step.ID,
|
||||
DependsOnID: root.ID,
|
||||
Type: types.DepParentChild,
|
||||
},
|
||||
},
|
||||
IssueMap: map[string]*types.Issue{
|
||||
root.ID: root,
|
||||
step.ID: step,
|
||||
},
|
||||
}
|
||||
|
||||
// Spawn with ephemeral=true (simulating bd mol wisp <formula>)
|
||||
result, err := spawnMolecule(ctx, s, subgraph, nil, "", "test", true, "eph")
|
||||
if err != nil {
|
||||
t.Fatalf("spawnMolecule failed: %v", err)
|
||||
}
|
||||
|
||||
// Verify all spawned issues have Ephemeral=true
|
||||
for oldID, newID := range result.IDMapping {
|
||||
spawned, err := s.GetIssue(ctx, newID)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get spawned issue %s: %v", newID, err)
|
||||
}
|
||||
if !spawned.Ephemeral {
|
||||
t.Errorf("Spawned issue %s (from %s) should have Ephemeral=true, got false", newID, oldID)
|
||||
}
|
||||
t.Logf("Issue %s: Ephemeral=%v", newID, spawned.Ephemeral)
|
||||
}
|
||||
|
||||
// Verify they have the correct prefix
|
||||
for _, newID := range result.IDMapping {
|
||||
if !strings.HasPrefix(newID, "test-eph-") {
|
||||
t.Errorf("Spawned issue ID %s should have prefix 'test-eph-'", newID)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify ephemeral issues are excluded from ready work
|
||||
readyWork, err := s.GetReadyWork(ctx, types.WorkFilter{})
|
||||
if err != nil {
|
||||
t.Fatalf("GetReadyWork failed: %v", err)
|
||||
}
|
||||
for _, issue := range readyWork {
|
||||
for _, spawnedID := range result.IDMapping {
|
||||
if issue.ID == spawnedID {
|
||||
t.Errorf("Ephemeral issue %s should not appear in ready work", spawnedID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user