<div dir="ltr"><div dir="ltr"><div>I'm pleased to announce a new super-major release of [dejafu][1], a</div><div>library for testing concurrent Haskell programs.</div><div><br></div><div>While there are breaking changes, common use-cases shouldn't be</div><div>affected too significantly (or not at all).  There is a brief guide to</div><div>the changes, and how to migrate if necessary, [on the website][2].</div><div><br></div><div><br></div><div>What's dejafu?</div><div>--------------</div><div><br></div><div>dejafu is a unit-testing library for concurrent Haskell programs.</div><div>Tests are deterministic, and work by systematically exploring the</div><div>possible schedules of your concurrency-using test case, allowing you</div><div>to confidently check your threaded code.</div><div><br></div><div>[HUnit][3] and [Tasty][4] bindings are available.</div><div><br></div><div>dejafu requires your test case to be written against the `MonadConc`</div><div>typeclass from the [concurrency][5] package.  This is a necessity,</div><div>dejafu cannot peek inside your `IO` or `STM` actions, so it needs to</div><div>be able to plug in an alternative implementation of the concurrency</div><div>primitives for testing.  There is some guidance for how to switch from</div><div>`IO` code to `MonadConc` code [on the website][6].</div><div><br></div><div>If you really need `IO`, you can use `MonadIO` - but make sure it's</div><div>deterministic enough to not invalidate your tests!</div><div><br></div><div>Here's a small example reproducing a deadlock found in an earlier</div><div>version of the [auto-update][7] library:</div><div><br></div><div>```</div><div>> :{</div><div>autocheck $ do</div><div>  auto <- mkAutoUpdate defaultUpdateSettings</div><div>  auto</div><div>:}</div><div>[fail] Successful</div><div>    [deadlock] S0--------S1-----------S0-</div><div>[fail] Deterministic</div><div>    [deadlock] S0--------S1-----------S0-</div><div><br></div><div>    () S0--------S1--------p0--</div><div>```</div><div><br></div><div>dejafu finds the deadlock, and gives a simplified execution trace for</div><div>each distinct result.  More in-depth traces showing exactly what each</div><div>thread did are also available.  This is using a version of auto-update</div><div>modified to use the `MonadConc` typeclass.  The source is in the</div><div>[dejafu testsuite][8].</div><div><br></div><div><br></div><div>What's new?</div><div>-----------</div><div><br></div><div>The highlights for this release are setup actions, teardown actions,</div><div>and invariants:</div><div><br></div><div>- **Setup actions** are for things which are not really a part of your</div><div>  test case, but which are needed for it (for example, setting up a</div><div>  test distributed system).  As dejafu can run a single test case many</div><div>  times, repeating this work can be a significant overhead.  By</div><div>  defining this as a setup action, dejafu can "snapshot" the state at</div><div>  the end of the action, and efficiently reload it in subsequent</div><div>  executions of the same test.</div><div><br></div><div>- **Teardown actions** are for things you want to run after your test</div><div>  case completes, in all cases, even if the test deadlocks (for</div><div>  example).  As dejafu controls the concurrent execution of the test</div><div>  case, inspecting shared state is possible even if the test case</div><div>  fails to complete.</div><div><br></div><div>- **Invariants** are effect-free atomically-checked conditions over</div><div>  shared state which must always hold.  If an invariant throws an</div><div>  exception, the test case is aborted, and any teardown action run.</div><div><br></div><div>Here is an example of a setup action with an invariant:</div><div><br></div><div>```</div><div>> :{</div><div>autocheck $</div><div>  let setup = do</div><div>        var <- newEmptyMVar</div><div>        registerInvariant $ do</div><div>          value <- inspectMVar var</div><div>          when (value == Just 1) $</div><div>            throwM Overflow</div><div>        pure var</div><div>  in withSetup setup $ \var -> do</div><div>       fork $ putMVar var 0</div><div>       fork $ putMVar var 1</div><div>       tryReadMVar var</div><div>:}</div><div>[fail] Successful</div><div>    [invariant failure] S0--P2-</div><div>[fail] Deterministic</div><div>    [invariant failure] S0--P2-</div><div><br></div><div>    Nothing S0----</div><div><br></div><div>    Just 0 S0--P1--S0--</div><div>```</div><div><br></div><div>In the `[invariant failure]` case, thread 2 is scheduled, writing the</div><div>forbidden value "1" to the MVar, which terminates the test.</div><div><br></div><div>Here is an example of a setup action with a teardown action:</div><div><br></div><div>```</div><div>> :{</div><div>autocheck $</div><div>  let setup = newMVar ()</div><div>      teardown var (Right _) = show <$> tryReadMVar var</div><div>      teardown _   (Left  e) = pure (show e)</div><div>  in withSetupAndTeardown setup teardown $ \var -> do</div><div>       fork $ takeMVar var</div><div>       takeMVar var</div><div>:}</div><div>[pass] Successful</div><div>[fail] Deterministic</div><div>    "Nothing" S0---</div><div><br></div><div>    "Deadlock" S0-P1--S0-</div><div>```</div><div><br></div><div>The teardown action can perform arbitrary concurrency effects,</div><div>including inspecting any mutable state returned by the setup action.</div><div><br></div><div>Setup and teardown actions were previously available in a slightly</div><div>different form as the `dontCheck` and `subconcurrency` functions,</div><div>which have been removed (see the migration guide if you used these).</div><div><br></div><div>[1]: <a href="http://hackage.haskell.org/package/dejafu">http://hackage.haskell.org/package/dejafu</a></div><div>[2]: <a href="https://dejafu.readthedocs.io/en/latest/migration_1x_2x.html">https://dejafu.readthedocs.io/en/latest/migration_1x_2x.html</a></div><div>[3]: <a href="http://hackage.haskell.org/package/hunit-dejafu">http://hackage.haskell.org/package/hunit-dejafu</a></div><div>[4]: <a href="http://hackage.haskell.org/package/tasty-dejafu">http://hackage.haskell.org/package/tasty-dejafu</a></div><div>[5]: <a href="http://hackage.haskell.org/package/concurrency">http://hackage.haskell.org/package/concurrency</a></div><div>[6]: <a href="https://dejafu.readthedocs.io/en/latest/typeclass.html">https://dejafu.readthedocs.io/en/latest/typeclass.html</a></div><div>[7]: <a href="http://hackage.haskell.org/package/auto-update">http://hackage.haskell.org/package/auto-update</a></div><div>[8]: <a href="https://github.com/barrucadu/dejafu/blob/master/dejafu-tests/lib/Examples/AutoUpdate.hs">https://github.com/barrucadu/dejafu/blob/master/dejafu-tests/lib/Examples/AutoUpdate.hs</a></div><br>-- <br>Michael Walker (<a href="http://www.barrucadu.co.uk">http://www.barrucadu.co.uk</a>)</div></div>