feat: Wire MQ lifecycle events to gt feed display (gt-lak31)
- Add MQ event types and logging in mrqueue/events.go - Have refinery emit merge_started, merged, merge_failed, merge_skipped events - Create MQEventSource to read from mq_events.jsonl - Add MultiSource to combine events from bd activity and MQ events - Add color coding: green for merged, red for failed - Update feed help with MQ event symbols Events are stored in .beads/mq_events.jsonl and displayed in the feed TUI with appropriate symbols and colors. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
144
internal/tui/feed/mq_source_test.go
Normal file
144
internal/tui/feed/mq_source_test.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package feed
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/steveyegge/gastown/internal/mrqueue"
|
||||
)
|
||||
|
||||
func TestParseMQEventLine(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
event mrqueue.Event
|
||||
wantType string
|
||||
wantTarget string
|
||||
wantContains string // Substring in message
|
||||
}{
|
||||
{
|
||||
name: "merge_started",
|
||||
event: mrqueue.Event{
|
||||
Timestamp: time.Now(),
|
||||
Type: mrqueue.EventMergeStarted,
|
||||
MRID: "mr-123",
|
||||
Branch: "polecat/nux",
|
||||
Target: "main",
|
||||
Worker: "nux",
|
||||
Rig: "gastown",
|
||||
},
|
||||
wantType: "merge_started",
|
||||
wantTarget: "mr-123",
|
||||
wantContains: "Merge started",
|
||||
},
|
||||
{
|
||||
name: "merged",
|
||||
event: mrqueue.Event{
|
||||
Timestamp: time.Now(),
|
||||
Type: mrqueue.EventMerged,
|
||||
MRID: "mr-456",
|
||||
Branch: "polecat/toast",
|
||||
Target: "main",
|
||||
Worker: "toast",
|
||||
Rig: "gastown",
|
||||
MergeCommit: "abc123def456789",
|
||||
},
|
||||
wantType: "merged",
|
||||
wantTarget: "mr-456",
|
||||
wantContains: "abc123de", // Short SHA
|
||||
},
|
||||
{
|
||||
name: "merge_failed",
|
||||
event: mrqueue.Event{
|
||||
Timestamp: time.Now(),
|
||||
Type: mrqueue.EventMergeFailed,
|
||||
MRID: "mr-789",
|
||||
Branch: "polecat/capable",
|
||||
Target: "main",
|
||||
Worker: "capable",
|
||||
Rig: "gastown",
|
||||
Reason: "conflict in main.go",
|
||||
},
|
||||
wantType: "merge_failed",
|
||||
wantTarget: "mr-789",
|
||||
wantContains: "conflict in main.go",
|
||||
},
|
||||
{
|
||||
name: "merge_skipped",
|
||||
event: mrqueue.Event{
|
||||
Timestamp: time.Now(),
|
||||
Type: mrqueue.EventMergeSkipped,
|
||||
MRID: "mr-999",
|
||||
Branch: "polecat/skip",
|
||||
Target: "main",
|
||||
Reason: "already merged",
|
||||
},
|
||||
wantType: "merge_skipped",
|
||||
wantTarget: "mr-999",
|
||||
wantContains: "already merged",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Marshal to JSON line
|
||||
data, err := json.Marshal(tt.event)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to marshal event: %v", err)
|
||||
}
|
||||
|
||||
// Parse the line
|
||||
result := parseMQEventLine(string(data))
|
||||
if result == nil {
|
||||
t.Fatal("parseMQEventLine returned nil")
|
||||
}
|
||||
|
||||
if result.Type != tt.wantType {
|
||||
t.Errorf("Type = %q, want %q", result.Type, tt.wantType)
|
||||
}
|
||||
|
||||
if result.Target != tt.wantTarget {
|
||||
t.Errorf("Target = %q, want %q", result.Target, tt.wantTarget)
|
||||
}
|
||||
|
||||
if tt.wantContains != "" && !contains(result.Message, tt.wantContains) {
|
||||
t.Errorf("Message = %q, want to contain %q", result.Message, tt.wantContains)
|
||||
}
|
||||
|
||||
// Actor should be refinery
|
||||
if result.Actor != "refinery" {
|
||||
t.Errorf("Actor = %q, want %q", result.Actor, "refinery")
|
||||
}
|
||||
|
||||
if result.Role != "refinery" {
|
||||
t.Errorf("Role = %q, want %q", result.Role, "refinery")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMQEventLineEmpty(t *testing.T) {
|
||||
result := parseMQEventLine("")
|
||||
if result != nil {
|
||||
t.Error("Expected nil for empty line")
|
||||
}
|
||||
|
||||
result = parseMQEventLine(" ")
|
||||
if result != nil {
|
||||
t.Error("Expected nil for whitespace-only line")
|
||||
}
|
||||
|
||||
result = parseMQEventLine("not valid json")
|
||||
if result != nil {
|
||||
t.Error("Expected nil for invalid JSON")
|
||||
}
|
||||
}
|
||||
|
||||
func contains(s, substr string) bool {
|
||||
for i := 0; i <= len(s)-len(substr); i++ {
|
||||
if s[i:i+len(substr)] == substr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user