// Package echo provides the conformance fixture adapters. // // Two revisions over the same data: R-1 exposes only a collection, R-2 adds the // convenience resource. Both are ordinary deterministic HTTP handlers, which is // the point — an adapter is a normal service, and fluid-core sits in front of // it without asking anything of it. package echo import ( "encoding/json" "net/http" "sort" "time" ) // Entry is one record the fixture serves. type Entry struct { ID string `json:"id"` Title string `json:"title"` CreatedAt time.Time `json:"created_at"` } // Data returns a deterministic set of entries. // // Fixed timestamps rather than time.Now: a conformance suite whose fixture // changes between runs cannot distinguish a regression from the clock. func Data() []Entry { base := time.Date(2026, 9, 1, 12, 0, 0, 0, time.UTC) return []Entry{ {ID: "e-1", Title: "the river reached the forge", CreatedAt: base}, {ID: "e-2", Title: "nine doors stayed honest", CreatedAt: base.Add(24 * time.Hour)}, {ID: "e-3", Title: "the reviewing side", CreatedAt: base.Add(48 * time.Hour)}, } } // NewR1 returns the collection-only adapter. // // A consumer wanting the newest entry must fetch the whole collection, sort it // and discard the rest. That is the interface pressure the fixture generates. func NewR1() http.Handler { mux := http.NewServeMux() mux.HandleFunc("/v1/entries", func(w http.ResponseWriter, r *http.Request) { writeJSON(w, Data()) }) return mux } // NewR2 returns the adapter with the convenience resource added. func NewR2() http.Handler { mux := http.NewServeMux() mux.HandleFunc("/v1/entries", func(w http.ResponseWriter, r *http.Request) { writeJSON(w, Data()) }) mux.HandleFunc("/v1/entries/latest", func(w http.ResponseWriter, r *http.Request) { entries := Data() sort.Slice(entries, func(i, j int) bool { return entries[i].CreatedAt.After(entries[j].CreatedAt) }) writeJSON(w, entries[0]) }) return mux } func writeJSON(w http.ResponseWriter, v any) { w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(v) }