#lang scheme/base (require srfi/26/cut (planet untyped/unlib:3/pipeline) "snooze.ss" "test-base.ss" "test-data.ss") ; Helpers ---------------------------------------- ; When a pipeline stage is run successfully (i.e. without raising an exception), ; the struct is stored in the relevant box: (define saved (box #f)) ; (box (U pipelined #f)) (define inserted (box #f)) ; (box (U pipelined #f)) (define updated (box #f)) ; (box (U pipelined #f)) (define deleted (box #f)) ; (box (U pipelined #f)) ; Convenience procedure for clearing boxes: (define (clear-boxes) (set-box! saved #f) (set-box! inserted #f) (set-box! updated #f) (set-box! deleted #f)) ; Custom exception type (to avoid confusion with anything outside this file): (define-struct (exn:unpipelined exn) ()) ; Each stage checks the "value" field of the struct being saved/deleted. ; If the value matches a "bad value", an exception is thrown. The tests ; below seed the struct with different values to make different stages fail. (define (create-stage name box bad-value) (make-stage name (lambda (continue conn struct) (if (= (pipelined-value struct) bad-value) (raise-exn exn:unpipelined "Argh!") (begin (set-box! box struct) (continue conn struct)))))) ; Hey! It's a test entity: (define-persistent-struct pipelined ([value type:integer]) #:on-save (list (create-stage 'save saved 1)) #:on-insert (list (create-stage 'insert inserted 2)) #:on-update (list (create-stage 'update updated 3)) #:on-delete (list (create-stage 'delete deleted 4))) ; ...and a persistent struct, too: (define test-pipelined (make-pipelined 0)) ; Tests ------------------------------------------ ; snooze -> test-suite (define (make-snooze-pipeline-tests snooze) (define-snooze-interface snooze) ; test-suite (test-suite "snooze-pipeline-tests" ; ***** NOTE ***** ; Each test below depends on the tests before it. ; Add/edit tests at your peril! ; **************** ; create table for entity:pipelined #:before (lambda () (create-table entity:pipelined)) ; drop table for entity:pipelined #:after (lambda () (drop-table entity:pipelined)) (test-case "on-save and on-insert are called when saving a new struct" (set-pipelined-value! test-pipelined 0) (save! test-pipelined) ; Check which pipelines were run successfully: (check-eq? (unbox saved) test-pipelined) (check-eq? (unbox inserted) test-pipelined) (check-eq? (unbox updated) #f) (check-eq? (unbox deleted) #f) (clear-boxes)) (test-case "on-save and on-update are called when re-saving a struct" (set-pipelined-value! test-pipelined 0) (save! test-pipelined) ; Check which pipelines were run successfully: (check-eq? (unbox saved) test-pipelined) (check-eq? (unbox inserted) #f) (check-eq? (unbox updated) test-pipelined) (check-eq? (unbox deleted) #f) (clear-boxes)) (test-case "on-delete is called on delete" (set-pipelined-value! test-pipelined 0) (delete! test-pipelined) ; Check which pipelines were run successfully: (check-eq? (unbox saved) #f) (check-eq? (unbox inserted) #f) (check-eq? (unbox updated) #f) (check-eq? (unbox deleted) test-pipelined) (clear-boxes)) (test-case "saving is aborted when on-save throws an exception" (set-pipelined-value! test-pipelined 1) (check-exn exn:unpipelined? (lambda () (save! test-pipelined)) "check 2") (check-false (struct-id test-pipelined) "check 4") (check-pred null? (let-alias ([a pipelined]) (find-all (sql:select #:from a))) "check 5") ; Check which pipelines were run successfully: (check-eq? (unbox saved) #f "check 5") (check-eq? (unbox inserted) #f "check 6") (check-eq? (unbox updated) #f "check 7") (check-eq? (unbox deleted) #f "check 8")) (test-case "saving is aborted when on-insert throws an exception" (set-pipelined-value! test-pipelined 2) (check-exn exn:unpipelined? (lambda () (save! test-pipelined))) (check-false (struct-id test-pipelined)) (check-pred null? (let ([a (sql:entity 'a entity:pipelined)]) (find-all (sql:select #:from a)))) ; Check which pipelines were run successfully: (check-eq? (unbox saved) test-pipelined) (check-eq? (unbox inserted) #f) (check-eq? (unbox updated) #f) (check-eq? (unbox deleted) #f) (clear-boxes)) (test-case "saving is aborted when on-update throws an exception" (set-pipelined-value! test-pipelined 0) (save! test-pipelined) (clear-boxes) (set-pipelined-value! test-pipelined 3) (check-exn exn:unpipelined? (lambda () (save! test-pipelined))) (check-equal? (pipelined-value (find-by-id entity:pipelined (struct-id test-pipelined))) 0) ; Check which pipelines were run successfully: (check-eq? (unbox saved) test-pipelined) (check-eq? (unbox inserted) #f) (check-eq? (unbox updated) #f) (check-eq? (unbox deleted) #f) (clear-boxes)) (test-case "deleting is aborted when on-delete throws an exception" (set-pipelined-value! test-pipelined 4) (save! test-pipelined) (clear-boxes) (check-exn exn:unpipelined? (lambda () (delete! test-pipelined))) (check-equal? (pipelined-value (find-by-id entity:pipelined (struct-id test-pipelined))) 4) ; Check which pipelines were run successfully: (check-eq? (unbox saved) #f) (check-eq? (unbox inserted) #f) (check-eq? (unbox updated) #f) (check-eq? (unbox deleted) #f) (clear-boxes)))) ; Provide statements ----------------------------- (provide make-snooze-pipeline-tests)