Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 54s
Realistic flows composing every phase: an order pipeline (validate via attempt -> payment suspend -> branch -> ledger federation via remote-node) and an onboarding flow, each run through the full lifecycle including a simulated crash (export/wipe/ import) and a peer handoff mid-flow, with flow/pending|status|result introspection. 142/142 across 9 suites. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
116 lines
4.8 KiB
Plaintext
116 lines
4.8 KiB
Plaintext
;; lib/flow/tests/integration.sx — Phase 7: end-to-end flows composing every phase.
|
|
|
|
(define flow-int-pass 0)
|
|
(define flow-int-fail 0)
|
|
(define flow-int-fails (list))
|
|
|
|
(define
|
|
flow-int-test
|
|
(fn
|
|
(name actual expected)
|
|
(if
|
|
(= actual expected)
|
|
(set! flow-int-pass (+ flow-int-pass 1))
|
|
(begin
|
|
(set! flow-int-fail (+ flow-int-fail 1))
|
|
(append! flow-int-fails {:name name :expected expected :actual actual})))))
|
|
|
|
(define flow-i (fn (src) (flow-run src)))
|
|
|
|
;; The order-processing flow, defined once per program via this prelude string:
|
|
;; validate amount (attempt: fail if <= 0)
|
|
;; -> suspend for payment confirmation (resume value = confirmed amount)
|
|
;; -> branch: confirmed>0 ? record on the ledger peer : declined failure
|
|
(define
|
|
order-prelude
|
|
"(flow-peer-register! (quote ledger) (list (list (quote record) (lambda (amt) (list (quote recorded) amt)))))\n (defflow order\n (attempt\n (lambda (amt) (if (> amt 0) amt (fail (quote invalid-amount))))\n (lambda (amt) (suspend (quote await-payment)))\n (branch (lambda (amt) (> amt 0))\n (remote-node (quote ledger) (quote record))\n (flow-const (fail (quote declined))))))")
|
|
|
|
;; ── happy path through every phase ──────────────────────────────
|
|
(flow-int-test
|
|
"order: validate -> suspend -> resume -> branch -> federate"
|
|
(flow-i
|
|
(str
|
|
order-prelude
|
|
"(define id (car (cdr (flow/start order 100)))) (flow/resume id 250)"))
|
|
(list "recorded" 250))
|
|
(flow-int-test
|
|
"order: starting suspends awaiting payment"
|
|
(flow-i
|
|
(str
|
|
order-prelude
|
|
"(define s (flow/start order 100)) (list (car s) (car (cdr (cdr s))))"))
|
|
(list "flow-suspended" "await-payment"))
|
|
(flow-int-test
|
|
"order: invalid amount fails up front and never suspends"
|
|
(flow-i
|
|
(str
|
|
order-prelude
|
|
"(define r (flow/start order -5)) (list (failed? r) (fail-reason r))"))
|
|
(list true "invalid-amount"))
|
|
(flow-int-test
|
|
"order: a declined payment yields a failure value"
|
|
(flow-i
|
|
(str
|
|
order-prelude
|
|
"(define id (car (cdr (flow/start order 100)))) (failed? (flow/resume id 0))"))
|
|
true)
|
|
|
|
;; ── crash recovery mid-flow ─────────────────────────────────────
|
|
(flow-int-test
|
|
"order: survives a simulated crash between suspend and resume"
|
|
(flow-i
|
|
(str
|
|
order-prelude
|
|
"(define id (car (cdr (flow/start order 100)))) (define saved (flow-store-export)) (set! flow-store (list)) (flow-store-import! saved) (flow/resume id 250)"))
|
|
(list "recorded" 250))
|
|
|
|
;; ── handoff to a peer mid-flow ──────────────────────────────────
|
|
(flow-int-test
|
|
"order: hands off to a peer that resumes and completes"
|
|
(flow-i
|
|
(str
|
|
order-prelude
|
|
"(define id (car (cdr (flow/start order 100)))) (flow-replicate-to (quote nodeB)) (set! flow-store (list)) (flow-restore-from (quote nodeB)) (flow/resume id 250)"))
|
|
(list "recorded" 250))
|
|
|
|
;; ── introspection during the flow's life ────────────────────────
|
|
(flow-int-test
|
|
"order: pending shows what the flow awaits, then result after resume"
|
|
(flow-i
|
|
(str
|
|
order-prelude
|
|
"(define id (car (cdr (flow/start order 100)))) (define p (flow/pending)) (flow/resume id 250) (list p (flow/status id) (flow/result id))"))
|
|
(list
|
|
(list (list 1 "await-payment"))
|
|
"done"
|
|
(list "recorded" 250)))
|
|
|
|
;; ── onboarding: two human steps + cancellation ──────────────────
|
|
(define
|
|
onboard-prelude
|
|
"(defflow onboard\n (sequence\n (lambda (user) (+ user 1))\n (lambda (x) (suspend (quote confirm-email)))\n (lambda (x) (suspend (quote complete-profile)))\n (lambda (x) (list (quote onboarded) x))))")
|
|
|
|
(flow-int-test
|
|
"onboard: two suspends resume in order to completion"
|
|
(flow-i
|
|
(str
|
|
onboard-prelude
|
|
"(define id (car (cdr (flow/start onboard 0)))) (flow/resume id 7) (flow/resume id 9)"))
|
|
(list "onboarded" 9))
|
|
(flow-int-test
|
|
"onboard: the second pending tag appears after the first resume"
|
|
(flow-i
|
|
(str
|
|
onboard-prelude
|
|
"(define id (car (cdr (flow/start onboard 0)))) (flow/resume id 7) (car (cdr (car (flow/pending))))"))
|
|
"complete-profile")
|
|
(flow-int-test
|
|
"onboard: cancelling abandons the flow"
|
|
(flow-i
|
|
(str
|
|
onboard-prelude
|
|
"(define id (car (cdr (flow/start onboard 0)))) (flow/cancel id) (list (flow/status id) (car (flow/resume id 7)))"))
|
|
(list "cancelled" "flow-error"))
|
|
|
|
(define flow-int-tests-run! (fn () {:total (+ flow-int-pass flow-int-fail) :passed flow-int-pass :failed flow-int-fail :fails flow-int-fails}))
|