diff --git a/exercises/practice/bank-account/.meta/tests.toml b/exercises/practice/bank-account/.meta/tests.toml index 4e42d4d..e2db23e 100644 --- a/exercises/practice/bank-account/.meta/tests.toml +++ b/exercises/practice/bank-account/.meta/tests.toml @@ -59,3 +59,4 @@ description = "Cannot deposit negative" [ba0c1e0b-0f00-416f-8097-a7dfc97871ff] description = "Can handle concurrent transactions" +comment = "Tests separate concurrent deposit and withdrawal phases" diff --git a/exercises/practice/bank-account/test/bank-account-tests.lfe b/exercises/practice/bank-account/test/bank-account-tests.lfe index 39f0393..cd393ce 100644 --- a/exercises/practice/bank-account/test/bank-account-tests.lfe +++ b/exercises/practice/bank-account/test/bank-account-tests.lfe @@ -106,19 +106,36 @@ (bank-account:deposit account -50)))) (deftest can-handle-concurrent-transactions - (let* ((account (bank-account:create)) - (spawn-deposits (lambda () - (lists:foreach - (lambda (_) - (spawn (lambda () (bank-account:deposit account 1)))) - (lists:seq 1 1000)))) - (spawn-withdrawals (lambda () - (lists:foreach - (lambda (_) - (spawn (lambda () (bank-account:withdraw account 1)))) - (lists:seq 1 1000))))) - (bank-account:open account) - (funcall spawn-deposits) - (funcall spawn-withdrawals) - (timer:sleep 500) + (let ((account (bank-account:create))) + (bank-account:open account) + + (run-concurrently + 1000 + (lambda () + (bank-account:deposit account 1))) + (is-equal 1000 (bank-account:balance account)) + + (run-concurrently + 1000 + (lambda () + (bank-account:withdraw account 1))) (is-equal 0 (bank-account:balance account)))) + +(defun run-concurrently (count operation) + (lists:foreach + (lambda (_) + (spawn_monitor operation)) + (lists:seq 1 count)) + (await-workers count)) + +(defun await-workers + ([0] + 'ok) + ([remaining] + (receive + ((tuple 'DOWN _ref 'process _pid 'normal) + (await-workers (- remaining 1))) + ((tuple 'DOWN _ref 'process _pid reason) + (erlang:error reason)) + (after 2000 + (erlang:error 'timeout)))))