566ae22e
test: end-to-end save-to-stamp integration
a73x 2026-04-29 06:01
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
diff --git a/cmd/filewatch-mcp/integration_test.go b/cmd/filewatch-mcp/integration_test.go new file mode 100644 index 0000000..c6a063d --- /dev/null +++ b/cmd/filewatch-mcp/integration_test.go @@ -0,0 +1,101 @@ package main import ( "bufio" "encoding/json" "fmt" "os" "os/exec" "path/filepath" "strings" "testing" "time" ) // TestEndToEnd boots the binary as a subprocess, simulates a save, and // verifies a notifications/claude/channel frame appears on stdout AND the // file gets rewritten with [fw-XXXXXXXX]. func TestEndToEnd(t *testing.T) { if testing.Short() { t.Skip("integration") } if _, err := exec.LookPath("go"); err != nil { t.Skip("go toolchain not on PATH") } dir := t.TempDir() target := filepath.Join(dir, "foo.go") if err := os.WriteFile(target, []byte("package foo\n"), 0o644); err != nil { t.Fatal(err) } cmd := exec.Command("go", "run", ".", "--root", dir, "--debounce", "100ms") stdin, err := cmd.StdinPipe() if err != nil { t.Fatal(err) } stdout, err := cmd.StdoutPipe() if err != nil { t.Fatal(err) } cmd.Stderr = os.Stderr if err := cmd.Start(); err != nil { t.Fatal(err) } defer func() { stdin.Close() _ = cmd.Process.Kill() _ = cmd.Wait() }() // Send initialize so srv.Run completes the handshake. fmt.Fprintln(stdin, `{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{}}}`) sc := bufio.NewScanner(stdout) sc.Buffer(make([]byte, 1<<16), 1<<16) if !sc.Scan() { t.Fatal("no init response") } // Trigger an atomic save (tmpfile + rename) to be realistic. tmp := target + ".tmp" if err := os.WriteFile(tmp, []byte("// @claude please review\npackage foo\n"), 0o644); err != nil { t.Fatal(err) } if err := os.Rename(tmp, target); err != nil { t.Fatal(err) } // Look for the channel notification in subsequent frames. deadline := time.Now().Add(5 * time.Second) var sawChannel bool for time.Now().Before(deadline) { if !sc.Scan() { break } var f map[string]any if err := json.Unmarshal(sc.Bytes(), &f); err != nil { continue } if f["method"] == "notifications/claude/channel" { sawChannel = true break } } if !sawChannel { t.Fatal("no notifications/claude/channel frame on stdout") } // Verify the file got stamped. Allow a brief moment for the rewriter // to run after the notification was emitted. deadline = time.Now().Add(2 * time.Second) var got []byte for time.Now().Before(deadline) { got, _ = os.ReadFile(target) if strings.Contains(string(got), "@claude[fw-") { return } time.Sleep(50 * time.Millisecond) } t.Errorf("file not stamped:\n%s", got) }