package agentnode import ( "encoding/json" "testing" "time" ) func routeTestNode(id, status string, enabled bool, capabilities map[string]any) Node { raw, _ := json.Marshal(capabilities) return Node{ID: id, Code: id, Status: status, Enabled: enabled, Capabilities: raw, LastHeartbeatAt: func() *time.Time { now := time.Now(); return &now }()} } func TestSelectRouteCandidatesFiltersCapabilitiesAndStatus(t *testing.T) { nodes := []Node{ routeTestNode("online-capable", "online", true, map[string]any{"tool_exec": true, "region": "cn"}), routeTestNode("online-disabled-capability", "online", true, map[string]any{"tool_exec": false}), routeTestNode("online-missing-capability", "online", true, map[string]any{"region": "cn"}), routeTestNode("offline-capable", "offline", true, map[string]any{"tool_exec": true}), routeTestNode("disabled-capable", "online", false, map[string]any{"tool_exec": true}), } selected := selectRouteCandidates(nodes, "request-1", []string{"tool_exec"}) if len(selected) != 1 || selected[0].ID != "online-capable" { t.Fatalf("unexpected candidates: %#v", selected) } } func TestSelectRouteCandidatesIsDeterministic(t *testing.T) { nodes := []Node{ routeTestNode("node-a", "online", true, nil), routeTestNode("node-b", "online", true, nil), routeTestNode("node-c", "online", true, nil), } first := selectRouteCandidates(nodes, "request-42", nil) second := selectRouteCandidates([]Node{nodes[2], nodes[0], nodes[1]}, "request-42", nil) if len(first) != len(second) || len(first) == 0 { t.Fatalf("candidate lengths differ: %d %d", len(first), len(second)) } for index := range first { if first[index].ID != second[index].ID { t.Fatalf("selection order is not stable: first=%v second=%v", first, second) } } if first[0].ID == first[1].ID { t.Fatal("candidate order contains duplicates") } } func TestNormalizeRoutePreviewInput(t *testing.T) { input, err := normalizeRoutePreviewInput(RoutePreviewInput{ PoolType: " PUBLIC ", PoolCode: "shared", RequestKey: " request-1 ", RequiredCapabilities: []string{"tool_exec", " tool_exec ", ""}, }) if err != nil || input.PoolType != "public" || input.RequestKey != "request-1" || len(input.RequiredCapabilities) != 1 { t.Fatalf("normalized input=%+v err=%v", input, err) } if _, err := normalizeRoutePreviewInput(RoutePreviewInput{PoolType: "public", PoolCode: "shared"}); err == nil { t.Fatal("empty request key must be rejected") } }