AtlatestRepositorysigil-web

sigil-web / tree / testtest-live-sse-repro.sgl

1;; Regression test for the live-stream SSE endpoint 500 ("car: expected pair").
2;;
3;; `stream-events-handler` called `http-response/sse-broadcast` while OMITTING
4;; the broadcast handler positional, relying on it defaulting to the identity
5;; function. That default only exists in the `. opts` form of
6;; `http-response/sse-broadcast` (sigil-http 0.16.7+). In releases 0.16.1–0.16.6
7;; the signature was a `keys:` form with `handler` as a *required* positional;
8;; omitting it (and jumping to the `on-connect:` keyword) crashed the SSE connect
9;; with `type-error: car: expected pair` — a 500 on GET /feed. The fix passes the
10;; identity handler EXPLICITLY, which is valid for every release.
11;;
12;; NOTE: fully invoking the handler starts the lazy heartbeat via `(go ...)`,
13;; which needs a live scheduler and never terminates, so we can't drive it from
14;; a plain `sigil test`. Instead we pin the two things the fix actually depends
15;; on: (1) the exact `http-response/sse-broadcast` call SHAPE the handler now
16;; uses builds a well-formed streaming SSE response, and (2) `live-routes` wires
17;; a handler for both a stream and a collection. End-to-end proof (GET /feed ->
18;; 200 text/event-stream on a real server) is recorded in the task note.
20(import (sigil test)
21 (sigil core)
22 (sigil channels)
23 (sigil web live)
24 (sigil web routes)
25 (sigil http request)
26 (sigil http response))
28(test-group "live-stream SSE endpoint (regression: /feed 500)"
29 ;; This is the call shape stream-events-handler now emits. Under the keys-form
30 ;; sigil-http releases this exact shape is what avoids the "car: expected pair"
31 ;; crash (the handler positional is supplied); under the `. opts` form it is the
32 ;; identity handler, matching the previous default behaviour.
33 (test "sse-broadcast with an explicit identity handler + on-connect: builds an SSE response"
34 (let* ((hub (make-broadcast))
35 (resp (http-response/sse-broadcast hub identity on-connect: #f)))
36 (assert-true (http-response? resp))
37 (assert-equal 200 (http-response-status resp))
38 ;; streaming responses carry a procedure body (write-chunk close) ...
39 (assert-true (procedure? (http-response-body resp)))
40 ;; ... and advertise the SSE content type.
41 (assert-equal "text/event-stream"
42 (dict-ref (http-response-headers resp) content-type:))))
44 (test "live-routes wires a handler for a plain stream"
45 (let* ((feed (live-stream path: "/feed"))
46 (app (live-routes feed)))
47 (assert-true (procedure? app))))
49 (test "live-routes wires a handler for a collection"
50 (let* ((coll (live-collection render: (lambda (item) `(li ,(dict-ref item text:)))
51 container: "#list" path: "/events"))
52 (app (live-routes coll)))
53 (assert-true (procedure? app)))))