summaryrefslogtreecommitdiff
path: root/internal/executor
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-03-08 06:43:06 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-03-08 06:43:06 +0000
commit0ff0bf75544bbf565288e61bb8e10c3f903830f8 (patch)
tree302f152b14d3ef2a81cfebdb4925d41e734ab8d5 /internal/executor
parent5d6d79e8925693c0740d8c31c614396d70dfb8a5 (diff)
refactor: address code review notes (backward compat, Gemini tests, unknown agent test)
Diffstat (limited to 'internal/executor')
-rw-r--r--internal/executor/executor_test.go26
-rw-r--r--internal/executor/gemini_test.go103
2 files changed, 129 insertions, 0 deletions
diff --git a/internal/executor/executor_test.go b/internal/executor/executor_test.go
index 2f205f8..9ad0617 100644
--- a/internal/executor/executor_test.go
+++ b/internal/executor/executor_test.go
@@ -346,3 +346,29 @@ func TestPool_ConcurrentExecution(t *testing.T) {
t.Errorf("calls: want 3, got %d", runner.callCount())
}
}
+
+func TestPool_UnsupportedAgent(t *testing.T) {
+ store := testStore(t)
+ runners := map[string]Runner{"claude": &mockRunner{}}
+ logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
+ pool := NewPool(2, runners, store, logger)
+
+ tk := makeTask("bad-agent")
+ tk.Agent.Type = "super-ai"
+ store.CreateTask(tk)
+
+ if err := pool.Submit(context.Background(), tk); err != nil {
+ t.Fatalf("submit: %v", err)
+ }
+
+ result := <-pool.Results()
+ if result.Err == nil {
+ t.Fatal("expected error for unsupported agent")
+ }
+ if !strings.Contains(result.Err.Error(), "unsupported agent type") {
+ t.Errorf("expected 'unsupported agent type' in error, got: %v", result.Err)
+ }
+ if result.Execution.Status != "FAILED" {
+ t.Errorf("status: want FAILED, got %q", result.Execution.Status)
+ }
+}
diff --git a/internal/executor/gemini_test.go b/internal/executor/gemini_test.go
new file mode 100644
index 0000000..c7acc3c
--- /dev/null
+++ b/internal/executor/gemini_test.go
@@ -0,0 +1,103 @@
+package executor
+
+import (
+ "context"
+ "io"
+ "log/slog"
+ "strings"
+ "testing"
+
+ "github.com/thepeterstone/claudomator/internal/storage"
+ "github.com/thepeterstone/claudomator/internal/task"
+)
+
+func TestGeminiRunner_BuildArgs_BasicTask(t *testing.T) {
+ r := &GeminiRunner{}
+ tk := &task.Task{
+ Agent: task.AgentConfig{
+ Type: "gemini",
+ Instructions: "fix the bug",
+ Model: "gemini-2.0-flash",
+ SkipPlanning: true,
+ },
+ }
+
+ args := r.buildArgs(tk, &storage.Execution{ID: "test-exec"}, "/tmp/q.json")
+
+ // Gemini CLI: instructions is the first positional arg
+ if len(args) < 1 || args[0] != "fix the bug" {
+ t.Errorf("expected instructions as first arg, got: %v", args)
+ }
+
+ argMap := make(map[string]bool)
+ for _, a := range args {
+ argMap[a] = true
+ }
+ for _, want := range []string{"--output-format", "stream-json", "--model", "gemini-2.0-flash"} {
+ if !argMap[want] {
+ t.Errorf("missing arg %q in %v", want, args)
+ }
+ }
+}
+
+func TestGeminiRunner_BuildArgs_PreamblePrepended(t *testing.T) {
+ r := &GeminiRunner{}
+ tk := &task.Task{
+ Agent: task.AgentConfig{
+ Type: "gemini",
+ Instructions: "fix the bug",
+ SkipPlanning: false,
+ },
+ }
+
+ args := r.buildArgs(tk, &storage.Execution{ID: "test-exec"}, "/tmp/q.json")
+
+ if len(args) < 1 {
+ t.Fatalf("expected at least 1 arg, got: %v", args)
+ }
+ if !strings.HasPrefix(args[0], planningPreamble) {
+ t.Errorf("instructions should start with planning preamble")
+ }
+ if !strings.HasSuffix(args[0], "fix the bug") {
+ t.Errorf("instructions should end with original instructions")
+ }
+}
+
+func TestGeminiRunner_Run_InaccessibleWorkingDir_ReturnsError(t *testing.T) {
+ r := &GeminiRunner{
+ BinaryPath: "true", // would succeed if it ran
+ Logger: slog.New(slog.NewTextHandler(io.Discard, nil)),
+ LogDir: t.TempDir(),
+ }
+ tk := &task.Task{
+ Agent: task.AgentConfig{
+ Type: "gemini",
+ WorkingDir: "/nonexistent/path/does/not/exist",
+ SkipPlanning: true,
+ },
+ }
+ exec := &storage.Execution{ID: "test-exec"}
+
+ err := r.Run(context.Background(), tk, exec)
+
+ if err == nil {
+ t.Fatal("expected error for inaccessible working_dir, got nil")
+ }
+ if !strings.Contains(err.Error(), "working_dir") {
+ t.Errorf("expected 'working_dir' in error, got: %v", err)
+ }
+}
+
+func TestGeminiRunner_BinaryPath_Default(t *testing.T) {
+ r := &GeminiRunner{}
+ if r.binaryPath() != "gemini" {
+ t.Errorf("want 'gemini', got %q", r.binaryPath())
+ }
+}
+
+func TestGeminiRunner_BinaryPath_Custom(t *testing.T) {
+ r := &GeminiRunner{BinaryPath: "/usr/local/bin/gemini"}
+ if r.binaryPath() != "/usr/local/bin/gemini" {
+ t.Errorf("want custom path, got %q", r.binaryPath())
+ }
+}