First migrated endpoint onto the SX host. lib/host is a thin wiring layer: a host handler is a Dream handler (request->response) that calls a subsystem public API and serialises via a shared JSON envelope. - handler.sx: host/ok, host/ok-status, host/error, host/json-status (Dream's dream-json is 200-only), host/query-int - router.sx: host/make-app assembles per-domain route groups + /health probe into one dream-router (reuses dr/flatten-routes) - feed.sx: GET /feed reads feed/all + stream combinators, recent-first, with ?actor= filter and ?limit= cap - 3 test suites incl. a golden test (body == subsystem recent stream + envelope) - conformance.sh mirrors lib/dream's runner Builds on dream-on-sx (merged, gate green 480/480) rather than a throwaway native request model; collapses most of plan Phase 4 into Phase 1. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
99 lines
3.0 KiB
Plaintext
99 lines
3.0 KiB
Plaintext
;; lib/host/tests/feed.sx — the first migrated endpoint, GET /feed. Includes a
|
|
;; golden test: the host response body must equal the feed subsystem's own
|
|
;; recent-first stream wrapped in the standard envelope — the endpoint adds the
|
|
;; HTTP/JSON shell and nothing else.
|
|
|
|
(define host-fd-pass 0)
|
|
(define host-fd-fail 0)
|
|
(define host-fd-fails (list))
|
|
|
|
(define
|
|
host-fd-test
|
|
(fn
|
|
(name actual expected)
|
|
(if
|
|
(= actual expected)
|
|
(set! host-fd-pass (+ host-fd-pass 1))
|
|
(begin
|
|
(set! host-fd-fail (+ host-fd-fail 1))
|
|
(append! host-fd-fails {:name name :actual actual :expected expected})))))
|
|
|
|
(define
|
|
host-fd-req
|
|
(fn (target) (dream-request "GET" target {} "")))
|
|
|
|
(define
|
|
host-fd-app
|
|
(host/make-app (list host/feed-routes)))
|
|
|
|
;; ── empty feed ─────────────────────────────────────────────────────
|
|
(feed/reset!)
|
|
(host-fd-test
|
|
"empty feed 200"
|
|
(dream-status (host-fd-app (host-fd-req "/feed")))
|
|
200)
|
|
(host-fd-test
|
|
"empty feed data:[]"
|
|
(contains? (dream-resp-body (host-fd-app (host-fd-req "/feed"))) "\"data\":[]")
|
|
true)
|
|
|
|
;; ── seeded feed ────────────────────────────────────────────────────
|
|
(feed/reset!)
|
|
(feed/post {:actor "alice" :verb "post" :object "p1" :at 1})
|
|
(feed/post {:actor "bob" :verb "post" :object "p2" :at 2})
|
|
(feed/post {:actor "alice" :verb "like" :object "p2" :at 3})
|
|
|
|
;; recent-first: newest activity (at 3) leads, so its object p2 appears before p1.
|
|
(host-fd-test
|
|
"timeline recent-first"
|
|
(let ((body (dream-resp-body (host-fd-app (host-fd-req "/feed")))))
|
|
(< (index-of body "\"at\":3") (index-of body "\"at\":1")))
|
|
true)
|
|
|
|
;; actor filter: only alice's two activities.
|
|
(host-fd-test
|
|
"actor filter count"
|
|
(feed/count
|
|
(feed/by-actor (feed/recent (feed/all)) "alice"))
|
|
2)
|
|
(host-fd-test
|
|
"actor filter excludes bob"
|
|
(contains?
|
|
(dream-resp-body (host-fd-app (host-fd-req "/feed?actor=alice")))
|
|
"bob")
|
|
false)
|
|
|
|
;; limit: cap to a single activity (the most recent).
|
|
(host-fd-test
|
|
"limit caps results"
|
|
(contains?
|
|
(dream-resp-body (host-fd-app (host-fd-req "/feed?limit=1")))
|
|
"\"at\":1")
|
|
false)
|
|
|
|
;; ── golden: endpoint = subsystem recent stream + envelope ───────────
|
|
(host-fd-test
|
|
"golden full timeline"
|
|
(dream-resp-body (host-fd-app (host-fd-req "/feed")))
|
|
(str
|
|
"{\"ok\":true,\"data\":"
|
|
(dream-json-encode (feed/items (feed/recent (feed/all))))
|
|
"}"))
|
|
(host-fd-test
|
|
"golden actor-filtered"
|
|
(dream-resp-body (host-fd-app (host-fd-req "/feed?actor=alice")))
|
|
(str
|
|
"{\"ok\":true,\"data\":"
|
|
(dream-json-encode
|
|
(feed/items (feed/by-actor (feed/recent (feed/all)) "alice")))
|
|
"}"))
|
|
|
|
(define
|
|
host-fd-tests-run!
|
|
(fn
|
|
()
|
|
{:total (+ host-fd-pass host-fd-fail)
|
|
:passed host-fd-pass
|
|
:failed host-fd-fail
|
|
:fails host-fd-fails}))
|