Files
Logging-System/server/server_test.go
T
weichenandCursor bed0dbf076
ci / vet-and-test (push) Successful in 4s
ci / docker-checkout-hostgateway (push) Successful in 2s
Add a structured logger and collector so runs can be traced across processes.
Sync and async sinks, redaction, and a queryable HTTP service keep concurrent logs tied to a trace id.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-29 13:51:16 +00:00

99 lines
2.5 KiB
Go

package server
import (
"bufio"
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestIngestQueryTail(t *testing.T) {
srv, err := New(t.TempDir()+"/logs.jsonl", "tok", 100)
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = srv.Close() })
ts := httptest.NewServer(srv.Handler())
defer ts.Close()
body := []byte(`{"entries":[{"ts":"2026-09-29T00:00:00Z","level":"error","service":"agent-squad","msg":"provider down","trace_id":"trace-abc-1","code":"agent.provider_unavailable","fields":{"api_key":"sk-abcdefghijklmnopqrstuvwxyz"}}]}`)
req, err := http.NewRequest(http.MethodPost, ts.URL+"/v1/logs", bytes.NewReader(body))
if err != nil {
t.Fatal(err)
}
req.Header.Set("Authorization", "Bearer tok")
res, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
}
res.Body.Close()
if res.StatusCode != http.StatusOK {
t.Fatalf("ingest %d", res.StatusCode)
}
unauth, err := http.Get(ts.URL + "/v1/logs")
if err != nil {
t.Fatal(err)
}
unauth.Body.Close()
if unauth.StatusCode != http.StatusUnauthorized {
t.Fatalf("auth %d", unauth.StatusCode)
}
req, err = http.NewRequest(http.MethodGet, ts.URL+"/v1/logs?trace_id=trace-abc-1&level=error", nil)
if err != nil {
t.Fatal(err)
}
req.Header.Set("X-Log-Token", "tok")
res, err = http.DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
}
defer res.Body.Close()
var payload struct {
Entries []Record `json:"entries"`
Next int64 `json:"next_cursor"`
}
if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
t.Fatal(err)
}
if len(payload.Entries) != 1 || payload.Entries[0].Code != "agent.provider_unavailable" {
t.Fatalf("%+v", payload.Entries)
}
raw, _ := json.Marshal(payload.Entries[0])
if strings.Contains(string(raw), "sk-abcdefghijklmnopqrstuvwxyz") {
t.Fatalf("secret leaked: %s", raw)
}
req, err = http.NewRequest(http.MethodGet, ts.URL+"/v1/logs/tail?cursor=0", nil)
if err != nil {
t.Fatal(err)
}
req.Header.Set("X-Log-Token", "tok")
tailRes, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
}
defer tailRes.Body.Close()
reader := bufio.NewReader(tailRes.Body)
line, err := reader.ReadString('\n')
if err != nil {
t.Fatal(err)
}
if !strings.HasPrefix(line, "data: ") || !strings.Contains(line, "provider down") {
t.Fatalf("sse %q", line)
}
health, err := http.Get(ts.URL + "/v1/health")
if err != nil {
t.Fatal(err)
}
health.Body.Close()
if health.StatusCode != http.StatusOK {
t.Fatal(health.StatusCode)
}
}