test(03-02): add failing tests for hook server integration and poll slowdown
- TestHookServerStartsWithDaemon, TestHookServerStopsWithDaemon - TestHookServerPortBusy (graceful degradation) - TestPollSlowdown (20s when hooks active, 5s otherwise) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
127
daemon_test.go
127
daemon_test.go
@@ -2,9 +2,13 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -212,7 +216,128 @@ func newTestDaemon(t *testing.T) *Daemon {
|
||||
t.Fatalf("labels: %v", err)
|
||||
}
|
||||
|
||||
return NewDaemon(sockPath, procDir, claudeDir, labels)
|
||||
d := NewDaemon(sockPath, procDir, claudeDir, labels)
|
||||
d.hookPort = 0 // disable hook server by default in tests
|
||||
return d
|
||||
}
|
||||
|
||||
func TestHookServerStartsWithDaemon(t *testing.T) {
|
||||
d := newTestDaemon(t)
|
||||
|
||||
// Assign a dynamic port for the hook server
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("listen: %v", err)
|
||||
}
|
||||
port := ln.Addr().(*net.TCPAddr).Port
|
||||
ln.Close()
|
||||
|
||||
d.hookPort = port
|
||||
|
||||
if err := d.Start(); err != nil {
|
||||
t.Fatalf("start: %v", err)
|
||||
}
|
||||
defer d.Stop()
|
||||
|
||||
// POST to /hook should return 200
|
||||
url := fmt.Sprintf("http://127.0.0.1:%d/hook", port)
|
||||
resp, err := http.Post(url, "application/json", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("POST /hook: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
// Empty body -> 400 (bad JSON), but the server is alive
|
||||
// A valid POST should return 200
|
||||
body := `{"session_id":"test","hook_event_name":"Stop","cwd":"/tmp"}`
|
||||
resp2, err := http.Post(url, "application/json", io.NopCloser(
|
||||
io.Reader(strings.NewReader(body)),
|
||||
))
|
||||
if err != nil {
|
||||
t.Fatalf("POST /hook valid: %v", err)
|
||||
}
|
||||
defer resp2.Body.Close()
|
||||
if resp2.StatusCode != http.StatusOK {
|
||||
t.Errorf("status = %d, want 200", resp2.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHookServerStopsWithDaemon(t *testing.T) {
|
||||
d := newTestDaemon(t)
|
||||
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("listen: %v", err)
|
||||
}
|
||||
port := ln.Addr().(*net.TCPAddr).Port
|
||||
ln.Close()
|
||||
|
||||
d.hookPort = port
|
||||
|
||||
if err := d.Start(); err != nil {
|
||||
t.Fatalf("start: %v", err)
|
||||
}
|
||||
|
||||
d.Stop()
|
||||
|
||||
// Give a moment for shutdown
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
// Port should no longer be listening
|
||||
url := fmt.Sprintf("http://127.0.0.1:%d/hook", port)
|
||||
_, err = http.Post(url, "application/json", nil)
|
||||
if err == nil {
|
||||
t.Error("expected connection error after Stop, but POST succeeded")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHookServerPortBusy(t *testing.T) {
|
||||
d := newTestDaemon(t)
|
||||
|
||||
// Occupy a port
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("listen: %v", err)
|
||||
}
|
||||
defer ln.Close()
|
||||
port := ln.Addr().(*net.TCPAddr).Port
|
||||
|
||||
d.hookPort = port
|
||||
|
||||
// Start should succeed despite port being busy (graceful degradation)
|
||||
if err := d.Start(); err != nil {
|
||||
t.Fatalf("start should succeed even with port busy: %v", err)
|
||||
}
|
||||
defer d.Stop()
|
||||
}
|
||||
|
||||
func TestPollSlowdown(t *testing.T) {
|
||||
d := newTestDaemon(t)
|
||||
|
||||
// No hook received -> default 5s
|
||||
got := d.currentPollInterval()
|
||||
if got != 5*time.Second {
|
||||
t.Errorf("default poll = %v, want 5s", got)
|
||||
}
|
||||
|
||||
// Simulate recent hook
|
||||
d.mu.Lock()
|
||||
d.lastHookTime = time.Now()
|
||||
d.mu.Unlock()
|
||||
|
||||
got = d.currentPollInterval()
|
||||
if got != 20*time.Second {
|
||||
t.Errorf("after hook poll = %v, want 20s", got)
|
||||
}
|
||||
|
||||
// Simulate hook > 60s ago
|
||||
d.mu.Lock()
|
||||
d.lastHookTime = time.Now().Add(-61 * time.Second)
|
||||
d.mu.Unlock()
|
||||
|
||||
got = d.currentPollInterval()
|
||||
if got != 5*time.Second {
|
||||
t.Errorf("after 60s poll = %v, want 5s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDaemonStartStop(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user