a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
104 lines
3.4 KiB
Go
104 lines
3.4 KiB
Go
package hooks
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/zzet/gortex/internal/daemon"
|
|
)
|
|
|
|
func TestNormalizeExternalEvent(t *testing.T) {
|
|
cases := map[string]string{
|
|
"SessionStart": "sessionstart",
|
|
"sessionstart": "sessionstart",
|
|
"AfterTool": "aftertool",
|
|
"PostToolUse": "aftertool",
|
|
"BeforeTool": "",
|
|
"": "",
|
|
}
|
|
for in, want := range cases {
|
|
if got := normalizeExternalEvent(in); got != want {
|
|
t.Errorf("normalizeExternalEvent(%q)=%q want %q", in, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestHandleExternalAgent_SessionStartEmitsOrientation(t *testing.T) {
|
|
withFakeStatus(t, func() (*daemon.StatusResponse, error) {
|
|
return &daemon.StatusResponse{
|
|
Version: "1.0.0", Ready: true,
|
|
TrackedRepos: []daemon.TrackedRepoStatus{{Name: "repo", Path: "/tmp/repo", Workspace: "repo", Nodes: 10}},
|
|
Workspaces: []daemon.WorkspaceSummary{{Slug: "repo"}},
|
|
}, nil
|
|
})
|
|
out := captureStdout(t, func() {
|
|
handleExternalAgent([]byte(`{"hook_event_name":"SessionStart","cwd":"/tmp/repo"}`))
|
|
})
|
|
var payload HookOutput
|
|
if err := json.Unmarshal([]byte(out), &payload); err != nil {
|
|
t.Fatalf("invalid HookOutput JSON: %v\n%s", err, out)
|
|
}
|
|
if payload.HookSpecificOutput.HookEventName != "SessionStart" {
|
|
t.Errorf("hookEventName=%q", payload.HookSpecificOutput.HookEventName)
|
|
}
|
|
if !strings.Contains(payload.HookSpecificOutput.AdditionalContext, "Gortex Session Orientation") {
|
|
t.Errorf("expected the orientation block, got:\n%s", payload.HookSpecificOutput.AdditionalContext)
|
|
}
|
|
}
|
|
|
|
func TestHandleExternalAgent_AfterToolDaemonDown(t *testing.T) {
|
|
withFakeStatus(t, func() (*daemon.StatusResponse, error) {
|
|
return nil, errDaemonUnreachable
|
|
})
|
|
out := captureStdout(t, func() {
|
|
handleExternalAgent([]byte(`{"hook_event_name":"AfterTool","tool_name":"run_shell_command","cwd":"/tmp/repo"}`))
|
|
})
|
|
var payload HookOutput
|
|
if err := json.Unmarshal([]byte(out), &payload); err != nil {
|
|
t.Fatalf("invalid JSON: %v\n%s", err, out)
|
|
}
|
|
if !strings.Contains(payload.HookSpecificOutput.AdditionalContext, "daemon is not running") {
|
|
t.Errorf("expected a daemon-down hint, got:\n%s", payload.HookSpecificOutput.AdditionalContext)
|
|
}
|
|
}
|
|
|
|
func TestHandleExternalAgent_AfterToolQuietWhenReadyAndCovered(t *testing.T) {
|
|
withFakeStatus(t, func() (*daemon.StatusResponse, error) {
|
|
return &daemon.StatusResponse{
|
|
Ready: true,
|
|
TrackedRepos: []daemon.TrackedRepoStatus{{Name: "repo", Path: "/tmp/repo"}},
|
|
}, nil
|
|
})
|
|
out := captureStdout(t, func() {
|
|
handleExternalAgent([]byte(`{"hook_event_name":"AfterTool","cwd":"/tmp/repo"}`))
|
|
})
|
|
if strings.TrimSpace(out) != "" {
|
|
t.Errorf("AfterTool should stay quiet when the graph is fresh and the cwd is covered, got:\n%s", out)
|
|
}
|
|
}
|
|
|
|
func TestHandleExternalAgent_AfterToolHintsUncoveredCwd(t *testing.T) {
|
|
withFakeStatus(t, func() (*daemon.StatusResponse, error) {
|
|
return &daemon.StatusResponse{
|
|
Ready: true,
|
|
TrackedRepos: []daemon.TrackedRepoStatus{{Name: "other", Path: "/some/other/repo"}},
|
|
}, nil
|
|
})
|
|
out := captureStdout(t, func() {
|
|
handleExternalAgent([]byte(`{"hook_event_name":"AfterTool","cwd":"/tmp/untracked"}`))
|
|
})
|
|
if !strings.Contains(out, "is not tracked") {
|
|
t.Errorf("expected an untracked-cwd hint, got:\n%s", out)
|
|
}
|
|
}
|
|
|
|
func TestHandleExternalAgent_UnknownEventNoOutput(t *testing.T) {
|
|
out := captureStdout(t, func() {
|
|
handleExternalAgent([]byte(`{"hook_event_name":"BeforeTool"}`))
|
|
})
|
|
if out != "" {
|
|
t.Errorf("unknown event should be a no-op, got: %q", out)
|
|
}
|
|
}
|