Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 19s
host/blog-open-create-routes mounts POST /new with error-trapping but NO auth (create-only; no PUT/DELETE), so the SX editor can publish to the host end-to-end on the experimental subdomain. VALIDATED LIVE: editor-style form-urlencoded POST -> 303 -> post renders at /<slug>/ and lists on /. Deliberate short-lived public write hole (create-only, obscure subdomain). MUST be gated before real use: Caddy basicauth on /new, or session auth. Swap host/blog-open-create-routes -> host/blog-write-routes <resolver> to gate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
143 lines
6.7 KiB
Plaintext
143 lines
6.7 KiB
Plaintext
;; lib/host/tests/blog.sx — blog on the editor's content model. Posts are
|
|
;; {slug,title,sx_content,status} records in the durable KV; a post page is
|
|
;; render-to-html(parse sx_content). Covers read/render, home index, JSON list,
|
|
;; slugify, the form-urlencoded editor ingest, and JSON CRUD (auth+ACL guarded).
|
|
|
|
(define host-bl-pass 0)
|
|
(define host-bl-fail 0)
|
|
(define host-bl-fails (list))
|
|
(define
|
|
host-bl-test
|
|
(fn (name actual expected)
|
|
(if (= actual expected)
|
|
(set! host-bl-pass (+ host-bl-pass 1))
|
|
(begin
|
|
(set! host-bl-fail (+ host-bl-fail 1))
|
|
(append! host-bl-fails {:name name :actual actual :expected expected})))))
|
|
|
|
(define host-bl-req (fn (target) (dream-request "GET" target {} "")))
|
|
(define host-bl-app (host/make-app (list host/feed-routes host/blog-routes)))
|
|
|
|
;; ── slugify ─────────────────────────────────────────────────────────
|
|
(host-bl-test "slugify" (host/blog-slugify "Hello World") "hello-world")
|
|
(host-bl-test "slugify trims spaces" (host/blog-slugify " A B ") "a-b")
|
|
|
|
;; ── render a stored post ────────────────────────────────────────────
|
|
(host/blog-use-store! (persist/open))
|
|
(host/blog-put! "hello" "Hello World"
|
|
"(article (h1 \"Hello World\") (p \"A \" (strong \"bold\") \" word.\"))" "published")
|
|
|
|
(host-bl-test "post 200" (dream-status (host-bl-app (host-bl-req "/hello/"))) 200)
|
|
(host-bl-test "post content-type html"
|
|
(contains? (dream-resp-header (host-bl-app (host-bl-req "/hello/")) "content-type") "text/html")
|
|
true)
|
|
(host-bl-test "post renders sx_content markup"
|
|
(contains? (dream-resp-body (host-bl-app (host-bl-req "/hello/"))) "<strong>bold</strong>")
|
|
true)
|
|
(host-bl-test "post title in page"
|
|
(contains? (dream-resp-body (host-bl-app (host-bl-req "/hello/"))) "<title>Hello World</title>")
|
|
true)
|
|
|
|
;; ── home + list ─────────────────────────────────────────────────────
|
|
(host-bl-test "home lists post"
|
|
(contains? (dream-resp-body (host-bl-app (host-bl-req "/"))) "href=\"/hello/\"")
|
|
true)
|
|
(host-bl-test "json list shows post"
|
|
(contains? (dream-resp-body (host-bl-app (host-bl-req "/posts"))) "\"slug\":\"hello\"")
|
|
true)
|
|
(host-bl-test "GET /new shows form"
|
|
(contains? (dream-resp-body (host-bl-app (host-bl-req "/new"))) "<form")
|
|
true)
|
|
|
|
;; ── unknown + precedence ────────────────────────────────────────────
|
|
(host-bl-test "unknown slug 404" (dream-status (host-bl-app (host-bl-req "/nope/"))) 404)
|
|
(feed/reset!)
|
|
(host-bl-test "/feed not captured by :slug"
|
|
(contains? (dream-resp-body (host-bl-app (host-bl-req "/feed"))) "\"ok\":true")
|
|
true)
|
|
|
|
;; ── writes: editor form ingest + JSON CRUD (auth+ACL) ───────────────
|
|
(acl/load! (list (acl-grant "editor" "edit" "blog")))
|
|
(define host-bl-resolve
|
|
(fn (tok) (cond ((= tok "good") "editor") ((= tok "weak") "reader") (true nil))))
|
|
(define host-bl-wapp
|
|
(host/make-app (list (host/blog-write-routes host-bl-resolve) host/blog-routes)))
|
|
(define host-bl-send
|
|
(fn (method target auth ctype body)
|
|
(dream-request method target
|
|
(merge (if auth {:authorization auth} {}) (if ctype {:content-type ctype} {})) body)))
|
|
|
|
(host/blog-use-store! (persist/open))
|
|
|
|
;; -- editor form ingest (form-urlencoded, the editor's submit shape) --
|
|
(host-bl-test "form ingest no auth -> 401"
|
|
(dream-status (host-bl-wapp (host-bl-send "POST" "/new" nil
|
|
"application/x-www-form-urlencoded" "title=X")))
|
|
401)
|
|
(host-bl-test "form ingest authed -> 303 redirect"
|
|
(dream-status (host-bl-wapp (host-bl-send "POST" "/new" "Bearer good"
|
|
"application/x-www-form-urlencoded"
|
|
"title=My+First+Post&sx_content=(article+(h1+%22My+First+Post%22)+(p+%22Hi%22))&status=published")))
|
|
303)
|
|
(host-bl-test "form ingest set Location to the new slug"
|
|
(dream-resp-header
|
|
(host-bl-wapp (host-bl-send "POST" "/new" "Bearer good"
|
|
"application/x-www-form-urlencoded"
|
|
"title=Another+One&sx_content=(p+%22x%22)&status=published"))
|
|
"location")
|
|
"/another-one/")
|
|
(host-bl-test "ingested post renders"
|
|
(contains? (dream-resp-body (host-bl-wapp (host-bl-req "/my-first-post/"))) "<h1>My First Post</h1>")
|
|
true)
|
|
|
|
;; -- JSON CRUD --
|
|
(host-bl-test "json create -> 201"
|
|
(dream-status (host-bl-wapp (host-bl-send "POST" "/posts" "Bearer good" "application/json"
|
|
"{\"title\":\"Json Post\",\"sx_content\":\"(p \\\"jp\\\")\",\"status\":\"draft\"}")))
|
|
201)
|
|
(host-bl-test "json create unpermitted -> 403"
|
|
(dream-status (host-bl-wapp (host-bl-send "POST" "/posts" "Bearer weak" "application/json"
|
|
"{\"title\":\"Nope\"}")))
|
|
403)
|
|
(host-bl-test "json create duplicate -> 409"
|
|
(dream-status (host-bl-wapp (host-bl-send "POST" "/posts" "Bearer good" "application/json"
|
|
"{\"slug\":\"json-post\",\"title\":\"Json Post\"}")))
|
|
409)
|
|
(host-bl-test "json create no title -> 400"
|
|
(dream-status (host-bl-wapp (host-bl-send "POST" "/posts" "Bearer good" "application/json" "{}")))
|
|
400)
|
|
(host-bl-test "update -> 200"
|
|
(dream-status (host-bl-wapp (host-bl-send "PUT" "/posts/json-post" "Bearer good" "application/json"
|
|
"{\"sx_content\":\"(p \\\"edited\\\")\"}")))
|
|
200)
|
|
(host-bl-test "update changed content"
|
|
(contains? (dream-resp-body (host-bl-wapp (host-bl-req "/json-post/"))) "edited")
|
|
true)
|
|
(host-bl-test "update missing -> 404"
|
|
(dream-status (host-bl-wapp (host-bl-send "PUT" "/posts/ghost" "Bearer good" "application/json" "{}")))
|
|
404)
|
|
(host-bl-test "delete -> 200"
|
|
(dream-status (host-bl-wapp (host-bl-send "DELETE" "/posts/json-post" "Bearer good" "" "")))
|
|
200)
|
|
(host-bl-test "deleted -> 404" (dream-status (host-bl-wapp (host-bl-req "/json-post/"))) 404)
|
|
(host-bl-test "delete missing -> 404"
|
|
(dream-status (host-bl-wapp (host-bl-send "DELETE" "/posts/ghost" "Bearer good" "" "")))
|
|
404)
|
|
|
|
;; -- experimental unguarded create-only route (POST /new, no auth) --
|
|
(define host-bl-oapp (host/make-app (list host/blog-open-create-routes host/blog-routes)))
|
|
(host/blog-use-store! (persist/open))
|
|
(host-bl-test "open create no auth -> 303"
|
|
(dream-status (host-bl-oapp (host-bl-send "POST" "/new" nil
|
|
"application/x-www-form-urlencoded" "title=Open+Post&sx_content=(p+%22o%22)&status=published")))
|
|
303)
|
|
(host-bl-test "open-created post renders"
|
|
(contains? (dream-resp-body (host-bl-oapp (host-bl-req "/open-post/"))) "<p>o</p>")
|
|
true)
|
|
|
|
(define
|
|
host-bl-tests-run!
|
|
(fn ()
|
|
{:total (+ host-bl-pass host-bl-fail)
|
|
:passed host-bl-pass :failed host-bl-fail :fails host-bl-fails}))
|