;; lib/events/tests/notify.sx — durable notification delivery flows. (define ev-nt-pass 0) (define ev-nt-fail 0) (define ev-nt-failures (list)) (define ev-nt-check! (fn (name got expected) (if (= got expected) (set! ev-nt-pass (+ ev-nt-pass 1)) (do (set! ev-nt-fail (+ ev-nt-fail 1)) (append! ev-nt-failures (str name "\n expected: " expected "\n got: " got)))))) ;; Each case runs a Scheme flow program (notify flows preloaded) and asserts on ;; the SX-native result. Scheme symbols come back as strings. (define ev-nt-run-all! (fn () (do (ev-nt-check! "reminder delivers on the first attempt" (ev/notify-run "(define s (flow/start (ev-deliver-reminder 3) (list (quote m1) (quote alice) (quote hello))))\n (flow-run-host (lambda (k p) (list (quote ok) (quote sent))) 5)\n (list (flow/status (car (cdr s))) (flow/result (car (cdr s))))") (list "done" (list "delivered" "m1" 1))) (ev-nt-check! "reminder retries a transient failure then delivers" (ev/notify-run "(define hits 0)\n (define s (flow/start (ev-deliver-reminder 3) (list (quote m1) (quote bob) (quote hi))))\n (flow-run-host (lambda (k p) (begin (set! hits (+ hits 1)) (if (< hits 2) (list (quote retry) (quote down)) (list (quote ok) (quote sent))))) 10)\n (list (flow/result (car (cdr s))) hits)") (list (list "delivered" "m1" 2) 2)) (ev-nt-check! "reminder gives up after maxn attempts" (ev/notify-run "(define s (flow/start (ev-deliver-reminder 2) (list (quote m1) (quote x) (quote y))))\n (flow-run-host (lambda (k p) (list (quote retry) (quote down))) 10)\n (flow/result (car (cdr s)))") (list "failed" "m1" "down")) (ev-nt-check! "redelivery of the same id sends only once (at-least-once, idempotent)" (ev/notify-run "(define sent (list)) (define deliveries 0)\n (define (xport k p)\n (let ((id (ev-msg-id p)))\n (if (ev-mem id sent)\n (list (quote ok) (quote duplicate))\n (begin (set! sent (cons id sent)) (set! deliveries (+ deliveries 1)) (list (quote ok) (quote sent))))))\n (define s1 (flow/start (ev-deliver-reminder 3) (list (quote m1) (quote a) (quote hi))))\n (flow-run-host xport 5)\n (define s2 (flow/start (ev-deliver-reminder 3) (list (quote m1) (quote a) (quote hi))))\n (flow-run-host xport 5)\n (list deliveries (flow/result (car (cdr s2))))") (list 1 (list "delivered" "m1" 1))) (ev-nt-check! "digest delivers every message in the batch" (ev/notify-run "(define s (flow/start (ev-deliver-digest 3) (list (list (quote a) (quote u1) (quote hi)) (list (quote b) (quote u2) (quote yo)))))\n (flow-run-host (lambda (k p) (list (quote ok) (quote sent))) 10)\n (flow/result (car (cdr s)))") (list (list "delivered" "a" 1) (list "delivered" "b" 1))) (ev-nt-check! "digest reports per-message outcomes independently" (ev/notify-run "(define (xport k p)\n (let ((id (ev-msg-id p)))\n (if (equal? id (quote b)) (list (quote retry) (quote flaky)) (list (quote ok) (quote sent)))))\n (define s (flow/start (ev-deliver-digest 2) (list (list (quote a) (quote u1) (quote hi)) (list (quote b) (quote u2) (quote yo)) (list (quote c) (quote u3) (quote ya)))))\n (flow-run-host xport 12)\n (flow/result (car (cdr s)))") (list (list "delivered" "a" 1) (list "failed" "b" "flaky") (list "delivered" "c" 1))) (ev-nt-check! "delivery suspends until the transport responds" (ev/notify-run "(define s (flow/start (ev-deliver-reminder 3) (list (quote m1) (quote a) (quote hi))))\n (flow/status (car (cdr s)))") "suspended")))) (define ev-notify-tests-run! (fn () (do (set! ev-nt-pass 0) (set! ev-nt-fail 0) (set! ev-nt-failures (list)) (ev-nt-run-all!) {:failures ev-nt-failures :total (+ ev-nt-pass ev-nt-fail) :passed ev-nt-pass :failed ev-nt-fail})))