Files
gastown/internal/refinery/engineer_test.go
Steve Yegge 349205eda1 feat(refinery): implement handleSuccess for merge queue
Implement success handling for the merge queue Engineer:
- Add handleSuccess method that handles successful merge completion
- Update MR body with merge_commit SHA and close_reason
- Close MR with 'merged' reason
- Close source issue with reference to MR ID
- Delete source branch if delete_merged_branches is configured
- Add DeleteRemoteBranch method to git package
- Add git client to Engineer struct
- Add tests for new functionality

Closes gt-3x1.5

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 14:48:13 -08:00

221 lines
5.2 KiB
Go

package refinery
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"time"
"github.com/steveyegge/gastown/internal/rig"
)
func TestDefaultMergeQueueConfig(t *testing.T) {
cfg := DefaultMergeQueueConfig()
if !cfg.Enabled {
t.Error("expected Enabled to be true by default")
}
if cfg.TargetBranch != "main" {
t.Errorf("expected TargetBranch to be 'main', got %q", cfg.TargetBranch)
}
if cfg.PollInterval != 30*time.Second {
t.Errorf("expected PollInterval to be 30s, got %v", cfg.PollInterval)
}
if cfg.MaxConcurrent != 1 {
t.Errorf("expected MaxConcurrent to be 1, got %d", cfg.MaxConcurrent)
}
if cfg.OnConflict != "assign_back" {
t.Errorf("expected OnConflict to be 'assign_back', got %q", cfg.OnConflict)
}
}
func TestEngineer_LoadConfig_NoFile(t *testing.T) {
// Create a temp directory without config.json
tmpDir, err := os.MkdirTemp("", "engineer-test-*")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
r := &rig.Rig{
Name: "test-rig",
Path: tmpDir,
}
e := NewEngineer(r)
// Should not error with missing config file
if err := e.LoadConfig(); err != nil {
t.Errorf("unexpected error with missing config: %v", err)
}
// Should use defaults
if e.config.PollInterval != 30*time.Second {
t.Errorf("expected default PollInterval, got %v", e.config.PollInterval)
}
}
func TestEngineer_LoadConfig_WithMergeQueue(t *testing.T) {
// Create a temp directory with config.json
tmpDir, err := os.MkdirTemp("", "engineer-test-*")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
// Write config file
config := map[string]interface{}{
"type": "rig",
"version": 1,
"name": "test-rig",
"merge_queue": map[string]interface{}{
"enabled": true,
"target_branch": "develop",
"poll_interval": "10s",
"max_concurrent": 2,
"run_tests": false,
"test_command": "make test",
},
}
data, _ := json.MarshalIndent(config, "", " ")
if err := os.WriteFile(filepath.Join(tmpDir, "config.json"), data, 0644); err != nil {
t.Fatal(err)
}
r := &rig.Rig{
Name: "test-rig",
Path: tmpDir,
}
e := NewEngineer(r)
if err := e.LoadConfig(); err != nil {
t.Errorf("unexpected error loading config: %v", err)
}
// Check that config values were loaded
if e.config.TargetBranch != "develop" {
t.Errorf("expected TargetBranch 'develop', got %q", e.config.TargetBranch)
}
if e.config.PollInterval != 10*time.Second {
t.Errorf("expected PollInterval 10s, got %v", e.config.PollInterval)
}
if e.config.MaxConcurrent != 2 {
t.Errorf("expected MaxConcurrent 2, got %d", e.config.MaxConcurrent)
}
if e.config.RunTests != false {
t.Errorf("expected RunTests false, got %v", e.config.RunTests)
}
if e.config.TestCommand != "make test" {
t.Errorf("expected TestCommand 'make test', got %q", e.config.TestCommand)
}
// Check that defaults are preserved for unspecified fields
if e.config.OnConflict != "assign_back" {
t.Errorf("expected OnConflict default 'assign_back', got %q", e.config.OnConflict)
}
}
func TestEngineer_LoadConfig_NoMergeQueueSection(t *testing.T) {
// Create a temp directory with config.json without merge_queue
tmpDir, err := os.MkdirTemp("", "engineer-test-*")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
// Write config file without merge_queue
config := map[string]interface{}{
"type": "rig",
"version": 1,
"name": "test-rig",
}
data, _ := json.MarshalIndent(config, "", " ")
if err := os.WriteFile(filepath.Join(tmpDir, "config.json"), data, 0644); err != nil {
t.Fatal(err)
}
r := &rig.Rig{
Name: "test-rig",
Path: tmpDir,
}
e := NewEngineer(r)
if err := e.LoadConfig(); err != nil {
t.Errorf("unexpected error loading config: %v", err)
}
// Should use all defaults
if e.config.PollInterval != 30*time.Second {
t.Errorf("expected default PollInterval, got %v", e.config.PollInterval)
}
}
func TestEngineer_LoadConfig_InvalidPollInterval(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "engineer-test-*")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
config := map[string]interface{}{
"merge_queue": map[string]interface{}{
"poll_interval": "not-a-duration",
},
}
data, _ := json.MarshalIndent(config, "", " ")
if err := os.WriteFile(filepath.Join(tmpDir, "config.json"), data, 0644); err != nil {
t.Fatal(err)
}
r := &rig.Rig{
Name: "test-rig",
Path: tmpDir,
}
e := NewEngineer(r)
err = e.LoadConfig()
if err == nil {
t.Error("expected error for invalid poll_interval")
}
}
func TestNewEngineer(t *testing.T) {
r := &rig.Rig{
Name: "test-rig",
Path: "/tmp/test-rig",
}
e := NewEngineer(r)
if e.rig != r {
t.Error("expected rig to be set")
}
if e.beads == nil {
t.Error("expected beads client to be initialized")
}
if e.git == nil {
t.Error("expected git client to be initialized")
}
if e.config == nil {
t.Error("expected config to be initialized with defaults")
}
if e.stopCh == nil {
t.Error("expected stopCh to be initialized")
}
}
func TestEngineer_DeleteMergedBranchesConfig(t *testing.T) {
// Test that DeleteMergedBranches is true by default
cfg := DefaultMergeQueueConfig()
if !cfg.DeleteMergedBranches {
t.Error("expected DeleteMergedBranches to be true by default")
}
}