atlas-iac/services/hermes/router/session_snapshot_test.go
2026-08-17 14:39:21 +00:00

114 lines
3.4 KiB
Go

package main
import (
"encoding/json"
"errors"
"io"
"net/http"
"strings"
"testing"
"testing/iotest"
)
func snapshotResponse(target, body string) *http.Response {
request, _ := http.NewRequest(http.MethodGet, target, nil)
return &http.Response{
StatusCode: http.StatusOK,
Header: make(http.Header),
Body: io.NopCloser(strings.NewReader(body)),
Request: request,
}
}
func TestBoundSessionSnapshotKeepsOnlyRecentMessages(t *testing.T) {
messages := make([]map[string]int, 30)
for index := range messages {
messages[index] = map[string]int{"index": index}
}
body, _ := json.Marshal(map[string]any{
"session_id": "resolved", "messages": messages,
})
response := snapshotResponse(
"http://tenant/api/sessions/root/messages?limit=24&hermes_fallback=1",
string(body),
)
response.Header.Set("ETag", "stale")
if err := boundSessionSnapshot(response); err != nil {
t.Fatal(err)
}
var bounded sessionSnapshot
if err := json.NewDecoder(response.Body).Decode(&bounded); err != nil {
t.Fatal(err)
}
if len(bounded.Messages) != 24 || bounded.TotalMessages != 30 {
t.Fatalf("snapshot was not bounded: %#v", bounded)
}
var first map[string]int
if err := json.Unmarshal(bounded.Messages[0], &first); err != nil || first["index"] != 6 {
t.Fatalf("snapshot did not retain the recent tail: %#v, %v", first, err)
}
if response.Header.Get("Cache-Control") != "no-store" || response.Header.Get("ETag") != "" {
t.Fatal("bounded snapshot retained cache metadata")
}
}
func TestBoundSessionSnapshotPreservesLargerReportedTotal(t *testing.T) {
response := snapshotResponse(
"http://tenant/api/sessions/root/messages?hermes_fallback=1",
`{"session_id":"leaf","messages":[],"total_messages":100}`,
)
if err := boundSessionSnapshot(response); err != nil {
t.Fatal(err)
}
var bounded sessionSnapshot
if err := json.NewDecoder(response.Body).Decode(&bounded); err != nil {
t.Fatal(err)
}
if bounded.SessionID != "leaf" || bounded.TotalMessages != 100 {
t.Fatalf("reported total was lost: %#v", bounded)
}
}
func TestBoundSessionSnapshotFailsClosedOnMalformedOrOversizedBody(t *testing.T) {
for name, body := range map[string]string{
"malformed": `{`,
"oversized": strings.Repeat("x", sessionSnapshotBytes+1),
} {
t.Run(name, func(t *testing.T) {
response := snapshotResponse(
"http://tenant/api/sessions/root/messages?hermes_fallback=1",
body,
)
if err := boundSessionSnapshot(response); err == nil {
t.Fatal("unsafe snapshot was accepted")
}
})
}
response := snapshotResponse(
"http://tenant/api/sessions/root/messages?hermes_fallback=1", `{}`,
)
response.Body = io.NopCloser(iotest.ErrReader(errors.New("read failed")))
if err := boundSessionSnapshot(response); err == nil {
t.Fatal("snapshot body read failure was ignored")
}
}
func TestBoundSessionSnapshotLeavesNativeAndErrorResponsesUntouched(t *testing.T) {
for _, response := range []*http.Response{
{StatusCode: http.StatusOK},
snapshotResponse("http://tenant/api/sessions/root/messages", `{}`),
snapshotResponse("http://tenant/api/sessions/root", `{}`),
} {
if err := boundSessionSnapshot(response); err != nil {
t.Fatal(err)
}
}
errorResponse := snapshotResponse(
"http://tenant/api/sessions/root/messages?hermes_fallback=1", `{}`,
)
errorResponse.StatusCode = http.StatusNotFound
if err := boundSessionSnapshot(errorResponse); err != nil {
t.Fatal(err)
}
}