119 lines
4.1 KiB
Go
119 lines
4.1 KiB
Go
package test
|
|
|
|
import "testing"
|
|
|
|
type sentinelPayload = map[string]any
|
|
|
|
var (
|
|
claudeCodeToolProgressFixture = sentinelPayload{
|
|
"type": "tool_progress",
|
|
"tool_use_id": "toolu_123",
|
|
"tool_name": "Bash",
|
|
"parent_tool_use_id": nil,
|
|
"elapsed_time_seconds": 2.5,
|
|
"task_id": "task_123",
|
|
"uuid": "11111111-1111-4111-8111-111111111111",
|
|
"session_id": "sess_123",
|
|
}
|
|
claudeCodeSessionStateChangedFixture = sentinelPayload{
|
|
"type": "system",
|
|
"subtype": "session_state_changed",
|
|
"state": "requires_action",
|
|
"uuid": "22222222-2222-4222-8222-222222222222",
|
|
"session_id": "sess_123",
|
|
}
|
|
claudeCodeToolUseSummaryFixture = sentinelPayload{
|
|
"type": "tool_use_summary",
|
|
"summary": "Searched in auth/",
|
|
"preceding_tool_use_ids": []any{"toolu_1", "toolu_2"},
|
|
"uuid": "33333333-3333-4333-8333-333333333333",
|
|
"session_id": "sess_123",
|
|
}
|
|
claudeCodeControlRequestCanUseToolFixture = sentinelPayload{
|
|
"type": "control_request",
|
|
"request_id": "req_123",
|
|
"request": sentinelPayload{
|
|
"subtype": "can_use_tool",
|
|
"tool_name": "Bash",
|
|
"input": sentinelPayload{"command": "npm test"},
|
|
"tool_use_id": "toolu_123",
|
|
"description": "Running npm test",
|
|
},
|
|
}
|
|
)
|
|
|
|
func requireStringField(t *testing.T, obj sentinelPayload, key string) string {
|
|
t.Helper()
|
|
value, ok := obj[key].(string)
|
|
if !ok || value == "" {
|
|
t.Fatalf("field %q missing or empty: %#v", key, obj[key])
|
|
}
|
|
return value
|
|
}
|
|
|
|
func TestClaudeCodeSentinel_ToolProgressShape(t *testing.T) {
|
|
payload := claudeCodeToolProgressFixture
|
|
if got := requireStringField(t, payload, "type"); got != "tool_progress" {
|
|
t.Fatalf("type = %q, want tool_progress", got)
|
|
}
|
|
requireStringField(t, payload, "tool_use_id")
|
|
requireStringField(t, payload, "tool_name")
|
|
requireStringField(t, payload, "session_id")
|
|
if _, ok := payload["elapsed_time_seconds"].(float64); !ok {
|
|
t.Fatalf("elapsed_time_seconds missing or non-number: %#v", payload["elapsed_time_seconds"])
|
|
}
|
|
}
|
|
|
|
func TestClaudeCodeSentinel_SessionStateShape(t *testing.T) {
|
|
payload := claudeCodeSessionStateChangedFixture
|
|
if got := requireStringField(t, payload, "type"); got != "system" {
|
|
t.Fatalf("type = %q, want system", got)
|
|
}
|
|
if got := requireStringField(t, payload, "subtype"); got != "session_state_changed" {
|
|
t.Fatalf("subtype = %q, want session_state_changed", got)
|
|
}
|
|
state := requireStringField(t, payload, "state")
|
|
switch state {
|
|
case "idle", "running", "requires_action":
|
|
default:
|
|
t.Fatalf("unexpected session state %q", state)
|
|
}
|
|
requireStringField(t, payload, "session_id")
|
|
}
|
|
|
|
func TestClaudeCodeSentinel_ToolUseSummaryShape(t *testing.T) {
|
|
payload := claudeCodeToolUseSummaryFixture
|
|
if got := requireStringField(t, payload, "type"); got != "tool_use_summary" {
|
|
t.Fatalf("type = %q, want tool_use_summary", got)
|
|
}
|
|
requireStringField(t, payload, "summary")
|
|
rawIDs, ok := payload["preceding_tool_use_ids"].([]any)
|
|
if !ok || len(rawIDs) == 0 {
|
|
t.Fatalf("preceding_tool_use_ids missing or empty: %#v", payload["preceding_tool_use_ids"])
|
|
}
|
|
for i, raw := range rawIDs {
|
|
if id, ok := raw.(string); !ok || id == "" {
|
|
t.Fatalf("preceding_tool_use_ids[%d] invalid: %#v", i, raw)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestClaudeCodeSentinel_ControlRequestCanUseToolShape(t *testing.T) {
|
|
payload := claudeCodeControlRequestCanUseToolFixture
|
|
if got := requireStringField(t, payload, "type"); got != "control_request" {
|
|
t.Fatalf("type = %q, want control_request", got)
|
|
}
|
|
requireStringField(t, payload, "request_id")
|
|
request, ok := payload["request"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("request missing or invalid: %#v", payload["request"])
|
|
}
|
|
if got := requireStringField(t, request, "subtype"); got != "can_use_tool" {
|
|
t.Fatalf("request.subtype = %q, want can_use_tool", got)
|
|
}
|
|
requireStringField(t, request, "tool_name")
|
|
requireStringField(t, request, "tool_use_id")
|
|
if input, ok := request["input"].(map[string]any); !ok || len(input) == 0 {
|
|
t.Fatalf("request.input missing or empty: %#v", request["input"])
|
|
}
|
|
}
|