Files
multica/server/internal/daemon/task_usage_test.go
93ae552ba9 feat: add messages to active Claude Code and Codex runs (MUL-7565) (#8682)
* feat: add live run supplements (MUL-7565)

Co-authored-by: multica-agent <[email protected]>

* fix: address MUL-7565 review feedback

Co-authored-by: multica-agent <[email protected]>

* fix: resolve MUL-7565 supplement panel and receipt review

Co-authored-by: multica-agent <[email protected]>

* refactor: remove MUL-7565 supplement ordinals

Co-authored-by: multica-agent <[email protected]>

* fix: close supplement composer after run remount

* fix: exclude task supplements from completion reconciliation

* fix: build a persistent binary for local daemon launches

* feat: support Claude task supplements through SDK hooks

* refactor: simplify task supplement delivery

* test: remove redundant task supplement coverage

* fix: remove redundant supplement delivery notices

* refactor: extract local daemon launcher fix to its own PR

* fix: preserve ordinary comment size compatibility

* fix: accept empty task start acknowledgements

* fix: bound task start response decoding and retries

---------

Co-authored-by: Forge-Boy <[email protected]>
Co-authored-by: multica-agent <[email protected]>
Co-authored-by: yushen <[email protected]>
2026-09-23 16:10:07 +08:00

87 lines
3.6 KiB
Go

package daemon
import (
"context"
"fmt"
"io"
"log/slog"
"net/http"
"net/http/httptest"
"path/filepath"
"reflect"
"runtime"
"strings"
"testing"
"time"
)
// A test-created Grok ACP process carries provider cost through the real
// backend and runTask conversion, without an installed CLI or model account.
const taskUsageGrokFixture = `#!/bin/sh
case "$*" in *--version*) echo '1.0.0'; exit 0;; esac
while IFS= read -r line; do
id=$(printf '%s' "$line" | sed -n 's/.*"id":\([0-9]*\).*/\1/p')
case "$line" in
*'"method":"initialize"'*)
printf '{"jsonrpc":"2.0","id":%s,"result":{"protocolVersion":1,"authMethods":[{"id":"cached_token","name":"Test authentication"}],"agentCapabilities":{"mcpCapabilities":{"http":true,"sse":true}}}}\n' "$id";;
*'"method":"session/new"'*)
printf '{"jsonrpc":"2.0","id":%s,"result":{"sessionId":"test-session","models":{"currentModelId":"grok-4.6","availableModels":[{"modelId":"grok-4.6","name":"Test model"}]}}}\n' "$id";;
*'"method":"session/prompt"'*)
printf '%s\n' '{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"test-session","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"done"}}}}'
printf '{"jsonrpc":"2.0","id":%s,"result":{"stopReason":"end_turn","_meta":{"modelId":"grok-4.6","usage":{"inputTokens":FIXTURE_INPUT,"costUsdTicks":FIXTURE_COST}}}}\n' "$id";;
*) if [ -n "$id" ]; then printf '{"jsonrpc":"2.0","id":%s,"result":{}}\n' "$id"; fi;;
esac
done
`
func TestRunTaskPreservesProviderCostWithoutTokens(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("shell-script agent fixture is POSIX-only")
}
for _, tc := range []struct {
name string
input, cost int64
want []TaskUsageEntry
}{
{"cost_only", 0, 100000000, []TaskUsageEntry{{Provider: "grok", Model: "grok-4.6", CostUSDTicks: 100000000}}},
{"tokens_and_cost", 10, 100000000, []TaskUsageEntry{{Provider: "grok", Model: "grok-4.6", InputTokens: 10, CostUSDTicks: 100000000}}},
{"tokens_only", 10, 0, []TaskUsageEntry{{Provider: "grok", Model: "grok-4.6", InputTokens: 10}}},
{"empty", 0, 0, nil},
} {
t.Run(tc.name, func(t *testing.T) {
logger := slog.New(slog.NewTextHandler(io.Discard, nil))
fake := filepath.Join(t.TempDir(), "grok-fixture")
script := strings.NewReplacer("FIXTURE_INPUT", fmt.Sprint(tc.input), "FIXTURE_COST", fmt.Sprint(tc.cost)).Replace(taskUsageGrokFixture)
writeTestExecutable(t, fake, []byte(script))
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
_, _ = w.Write([]byte(`{}`))
}))
defer srv.Close()
d := &Daemon{
client: NewClient(srv.URL), logger: logger,
workspaces: make(map[string]*workspaceState), activeEnvRoots: make(map[string]int),
runtimeIndex: map[string]Runtime{"test-rt": {ID: "test-rt", Provider: "grok"}},
cfg: Config{
WorkspacesRoot: t.TempDir(), AgentTimeout: 5 * time.Second, ServerBaseURL: srv.URL,
Agents: map[string]AgentEntry{"grok": {Path: fake}},
},
}
task := Task{
ID: "test-task", WorkspaceID: "test-ws", RuntimeID: "test-rt", IssueID: "test-issue",
AgentID: "test-agent", AuthToken: "mat_test_usage",
Agent: &AgentData{ID: "test-agent", Name: "test", Model: "grok-4.6"},
}
result, err := d.runTask(context.Background(), task, "grok", 0, logger)
if err != nil {
t.Fatal(err)
}
if result.Status != "completed" || result.Comment != "done" {
t.Fatalf("unexpected result: %+v", result)
}
if !reflect.DeepEqual(result.Usage, tc.want) {
t.Fatalf("usage = %+v, want %+v", result.Usage, tc.want)
}
})
}
}