multica/server/internal/daemon/daemon_test.go
Jiayuan Zhang 678266ec87 feat(daemon): add per-task isolated execution environments
Introduce the `execenv` package that creates isolated working directories
for each agent task. Supports git worktree mode (code tasks) and plain
directory mode (non-code tasks), with `.agent_context/issue_context.md`
injected into the workdir for Claude Code to discover.

Key changes:
- New `server/internal/daemon/execenv/` package (Prepare/Cleanup)
- `runTask()` now creates isolated env instead of using shared reposRoot
- Prompt updated to reference `.agent_context/` files
- Add `WorkspacesRoot` config (default ~/multica_workspaces)
- Add `KeepEnvAfterTask` config for debugging
- Default agent timeout increased from 20min to 2h
- `CompleteTask` now forwards branch name to server

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 12:41:52 +08:00

88 lines
2 KiB
Go

package daemon
import (
"net/http"
"strings"
"testing"
)
func TestNormalizeServerBaseURL(t *testing.T) {
t.Parallel()
got, err := NormalizeServerBaseURL("ws://localhost:8080/ws")
if err != nil {
t.Fatalf("NormalizeServerBaseURL returned error: %v", err)
}
if got != "http://localhost:8080" {
t.Fatalf("expected http://localhost:8080, got %s", got)
}
}
func TestBuildPromptIncludesIssueAndContext(t *testing.T) {
t.Parallel()
prompt := BuildPrompt(Task{
Context: TaskContext{
Issue: IssueContext{
Title: "Fix failing test",
Description: "Investigate and fix the test failure.",
AcceptanceCriteria: []string{"tests pass"},
},
Agent: AgentContext{
Name: "Local Codex",
Skills: "Be concise.",
},
},
})
for _, want := range []string{
"Fix failing test",
"Investigate and fix the test failure.",
"tests pass",
".agent_context/issue_context.md",
} {
if !strings.Contains(prompt, want) {
t.Fatalf("prompt missing %q", want)
}
}
}
func TestBuildPromptTruncatesLongDescription(t *testing.T) {
t.Parallel()
longDesc := strings.Repeat("x", 300)
prompt := BuildPrompt(Task{
Context: TaskContext{
Issue: IssueContext{
Title: "Long desc",
Description: longDesc,
},
Agent: AgentContext{Name: "Test"},
},
})
if strings.Contains(prompt, longDesc) {
t.Fatal("expected long description to be truncated in prompt")
}
if !strings.Contains(prompt, "...") {
t.Fatal("expected truncation marker")
}
}
func TestIsWorkspaceNotFoundError(t *testing.T) {
t.Parallel()
err := &requestError{
Method: http.MethodPost,
Path: "/api/daemon/register",
StatusCode: http.StatusNotFound,
Body: `{"error":"workspace not found"}`,
}
if !isWorkspaceNotFoundError(err) {
t.Fatal("expected workspace not found error to be recognized")
}
if isWorkspaceNotFoundError(&requestError{StatusCode: http.StatusInternalServerError, Body: `{"error":"workspace not found"}`}) {
t.Fatal("did not expect 500 to be treated as workspace not found")
}
}