test: extraer resolveWorkDir y tests unitarios de aislamiento
Extraer la logica de resolucion de working_dir a una funcion resolveWorkDir() separada para hacerla testeable. Tres tests cubren: - WorkingDir vacio → crea tmpdir con prefijo claude-agent-* - WorkingDir configurado → crea el directorio y lo usa - WorkingDir ya existente → lo usa sin error Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+24
-18
@@ -59,24 +59,7 @@ func NewClaudeCodeComplete(cfg config.ClaudeCodeCfg, log *slog.Logger) coretypes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Resolve working directory once at init time.
|
// Resolve working directory once at init time.
|
||||||
workDir := cfg.WorkingDir
|
workDir := resolveWorkDir(cfg.WorkingDir, log)
|
||||||
if workDir == "" {
|
|
||||||
tmp, err := os.MkdirTemp("", "claude-agent-*")
|
|
||||||
if err != nil {
|
|
||||||
log.Error("claude-code: failed to create temp working dir", "err", err)
|
|
||||||
// Fall through — cmd.Dir will remain empty (inherits CWD).
|
|
||||||
} else {
|
|
||||||
workDir = tmp
|
|
||||||
log.Warn("claude-code working_dir is empty, using temporary directory",
|
|
||||||
"dir", workDir,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Ensure configured directory exists.
|
|
||||||
if err := os.MkdirAll(workDir, 0o755); err != nil {
|
|
||||||
log.Error("claude-code: failed to create working dir", "dir", workDir, "err", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return func(ctx context.Context, req coretypes.CompletionRequest) (coretypes.CompletionResponse, error) {
|
return func(ctx context.Context, req coretypes.CompletionRequest) (coretypes.CompletionResponse, error) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||||
@@ -141,6 +124,29 @@ func NewClaudeCodeComplete(cfg config.ClaudeCodeCfg, log *slog.Logger) coretypes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resolveWorkDir determines the working directory for the claude subprocess.
|
||||||
|
// If configured is empty, it creates a temporary directory to avoid inheriting the launcher's CWD.
|
||||||
|
// If configured is non-empty, it ensures the directory exists.
|
||||||
|
func resolveWorkDir(configured string, log *slog.Logger) string {
|
||||||
|
if configured == "" {
|
||||||
|
tmp, err := os.MkdirTemp("", "claude-agent-*")
|
||||||
|
if err != nil {
|
||||||
|
log.Error("claude-code: failed to create temp working dir", "err", err)
|
||||||
|
return "" // Fall through — cmd.Dir will remain empty (inherits CWD).
|
||||||
|
}
|
||||||
|
log.Warn("claude-code working_dir is empty, using temporary directory",
|
||||||
|
"dir", tmp,
|
||||||
|
)
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure configured directory exists.
|
||||||
|
if err := os.MkdirAll(configured, 0o755); err != nil {
|
||||||
|
log.Error("claude-code: failed to create working dir", "dir", configured, "err", err)
|
||||||
|
}
|
||||||
|
return configured
|
||||||
|
}
|
||||||
|
|
||||||
// buildClaudeArgs constructs the CLI arguments for claude -p.
|
// buildClaudeArgs constructs the CLI arguments for claude -p.
|
||||||
func buildClaudeArgs(cfg config.ClaudeCodeCfg, req coretypes.CompletionRequest) []string {
|
func buildClaudeArgs(cfg config.ClaudeCodeCfg, req coretypes.CompletionRequest) []string {
|
||||||
args := []string{"--print", "--output-format", "json"}
|
args := []string{"--print", "--output-format", "json"}
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -318,6 +321,56 @@ func TestFilterEnv_PrefixSafety(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── resolveWorkDir ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
func TestResolveWorkDir_EmptyCreatesTempDir(t *testing.T) {
|
||||||
|
dir := resolveWorkDir("", discardLog)
|
||||||
|
if dir == "" {
|
||||||
|
t.Fatal("expected a temp directory, got empty string")
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
if !strings.Contains(dir, "claude-agent-") {
|
||||||
|
t.Errorf("temp dir %q should contain 'claude-agent-' prefix", dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := os.Stat(dir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("temp dir should exist: %v", err)
|
||||||
|
}
|
||||||
|
if !info.IsDir() {
|
||||||
|
t.Error("temp dir should be a directory")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveWorkDir_ConfiguredValueUsed(t *testing.T) {
|
||||||
|
want := filepath.Join(t.TempDir(), "custom-workdir")
|
||||||
|
|
||||||
|
got := resolveWorkDir(want, discardLog)
|
||||||
|
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("got %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := os.Stat(got)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("configured dir should be created: %v", err)
|
||||||
|
}
|
||||||
|
if !info.IsDir() {
|
||||||
|
t.Error("configured dir should be a directory")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveWorkDir_ConfiguredAlreadyExists(t *testing.T) {
|
||||||
|
want := t.TempDir() // already exists
|
||||||
|
|
||||||
|
got := resolveWorkDir(want, discardLog)
|
||||||
|
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("got %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── helpers ──────────────────────────────────────────────────────────────
|
// ── helpers ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
func contains(s, substr string) bool {
|
func contains(s, substr string) bool {
|
||||||
|
|||||||
Reference in New Issue
Block a user