Files
gastown/internal/tui/feed/mq_source_test.go
Steve Yegge 4f9bf643bd 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>
2025-12-30 01:45:04 -08:00

145 lines
3.2 KiB
Go

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
}