Files
ARTEX/agent/tools_nil_store_test.go
BaaRai e233c02314 Translate all Chinese text to English
Comments, doc comments, UI labels, log and error messages, LLM prompt
strings, markdown docs, test data and assertions. Identifiers, enum
keys, routes, placeholders and code structure are unchanged.

Notes:
- docs/漏洞流量证据.md renamed to docs/vulnerability-traffic-evidence.md
- tests that exercised CJK specific handling (GBK zip names, Chinese
  full text search) now use ASCII equivalents; go build passes and the
  test suite matches the pre translation baseline (remaining failures
  need a PostgreSQL DSN and fail identically on the original)
- frontend mention syntax now uses English kinds (finding, asset, ...)
  matching the backend, chat mentions tests pass
2026-10-08 23:14:34 +02:00

69 lines
2.4 KiB
Go

package agent
import (
"context"
"encoding/json"
"strings"
"testing"
actool "github.com/Autumn-27/norma/tool"
)
// The server-level ToolSet behind buildDomainReg carries a nil ExplorationStore,
// and the tools table can bind any of its tools to any agent — including agents
// that never run inside a task. Every domain tool must therefore survive being
// called with nil stores: a nil deref here runs on the harness's own goroutine,
// out of reach of every recover() in the server, and kills the whole process.
func TestDomainToolsSurviveNilStores(t *testing.T) {
inputs := []string{
`{}`,
`{"id":379,"asset_id":1,"goal_id":1,"evidence_id":1,"intent_id":1,"node_id":1,"work_id":1,` +
`"summary":"x","reason":"x","name":"x","severity":"low","vulnclass":"x","text":"x","q":"x"}`,
}
for _, tool := range NewToolSet(nil, "").AllDomainTools() {
for _, in := range inputs {
func() {
defer func() {
if r := recover(); r != nil {
t.Fatalf("%s panicked with nil stores on %s: %v", tool.Name(), in, r)
}
}()
if _, err := tool.Call(context.Background(), json.RawMessage(in), nil); err != nil {
t.Fatalf("%s returned a transport error: %v", tool.Name(), err)
}
}()
}
}
}
// node_detail is the one that took the process down; assert it now answers with a
// usable refusal rather than dying.
func TestExplorationToolRefusesWithoutTask(t *testing.T) {
ts := NewToolSet(nil, "")
res, err := ts.NodeDetailTool().Call(context.Background(), json.RawMessage(`{"id":379}`), nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !res.IsError || !strings.Contains(res.Flatten(), "task context") {
t.Fatalf("want an explanatory tool error, got IsError=%v %q", res.IsError, res.Flatten())
}
}
// A panicking tool must degrade to a tool error: the run continues and the process
// survives, instead of the supervisor restarting into the same crash on replay.
func TestGuardPanicConvertsPanicToToolError(t *testing.T) {
boom := actool.Build(actool.Spec{
Name: "boom",
Run: func(context.Context, json.RawMessage, *actool.ToolContext) (actool.Result, error) {
panic("nil map write")
},
})
res, err := guardPanic(boom).Call(context.Background(), json.RawMessage(`{}`), nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !res.IsError || !strings.Contains(res.Flatten(), "nil map write") {
t.Fatalf("want the panic reported as a tool error, got IsError=%v %q", res.IsError, res.Flatten())
}
}