<p dir="ltr">Dear David,</p>
<p dir="ltr">thank you very much! Your answers were extremely insightful.</p>
<p dir="ltr">To adapt this approach we will need to refactor our types quite a bit, but that will be well worth it.</p>
<p dir="ltr">—<br>
Kindest regards,<br>
jm</p>
<div class="gmail_quote">On Mar 31, 2016 10:10 AM, "David Turner" <<a href="mailto:dct25-561bs@mythic-beasts.com">dct25-561bs@mythic-beasts.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><p dir="ltr" style="font-size:12.8px">Hi Jonn,</p><p dir="ltr" style="font-size:12.8px">I work on a similar-sounding system. We have arranged things so that each node is a pure state machine, with outputs that are a pure function of its inputs, with separate (and simple, obviously correct) machinery for connecting these state machines over the network. This makes it rather simple to run a bunch of these state machines in a test harness that simulates all sorts of network nastiness (disconnections, dropped or reordered messages, delays, corruption etc.) on a single thread.</p><p dir="ltr" style="font-size:12.8px">One trick that proved useful was to feed in the current time as an explicit input message. This makes it possible to test things like timeouts without having to actually wait for the time to pass, which speeds things up immensely. We also make use of ContT somewhere in the tests to interleave processing and assertions, and to define a 'hypothetically' operator that lets a test run a sequence of actions and then backtrack.</p><p dir="ltr" style="font-size:12.8px">I think this idea was inspired by <a href="https://github.com/NicolasT/paxos/blob/master/bin/synod.hs" target="_blank">https://github.com/NicolasT/paxos/blob/master/bin/synod.hs</a>, at least the network nastiness simulator thing. He uses threads for that demo but the nodes' behaviour itself is pure: <a href="https://github.com/NicolasT/paxos/blob/master/src/Network/Paxos/Synod/Proposer.hs" target="_blank">https://github.com/NicolasT/paxos/blob/master/src/Network/Paxos/Synod/Proposer.hs</a> for example.</p><p dir="ltr" style="font-size:12.8px">We also have proved certain key properties of the network are implied by certain local invariants, which reduces the testing problem down to one of checking properties on each node separately. This was time consuming, but highlighted certain important corner cases that it's unlikely we would have found by random testing.</p><p dir="ltr" style="font-size:12.8px">If you're interested in Byzantine behaviour (the 'evil node' test) then you may enjoy reading James Mickens' article on the subject: <a href="https://www.usenix.org/publications/login-logout/may-2013/saddest-moment" target="_blank">https://www.usenix.org/publications/login-logout/may-2013/saddest-moment</a></p><p dir="ltr" style="font-size:12.8px">Hope that helps,</p><p dir="ltr" style="font-size:12.8px">David</p><p style="font-size:12.8px">PS a double apology: firstly for the double message (my first attempt was sent from the wrong address) and secondly for spelling your name wrong in that message!</p></div><div class="gmail_extra"><br><div class="gmail_quote">On 31 March 2016 at 00:41, Jonn Mostovoy <span dir="ltr"><<a href="mailto:jm@memorici.de" target="_blank">jm@memorici.de</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Dear friends,<br>
<br>
we have a distributed system written in Haskell, consisting of three<br>
types of nodes with dozen of instances of each of two types and a<br>
central node of the third type.<br>
<br>
Each node is started by executing a binary which sets up acid-state<br>
persistence layer and sockets over which msgpack messages are sent<br>
around.<br>
<br>
It is trivial to write low level functionality quickcheck test suites,<br>
which test properties of functions.<br>
<br>
We would like, however, to have a quickcheck-esque suite which sets up<br>
the network, then gets it to an arbitrary valid state (sending correct<br>
messages between nodes), then rigorously testing it for three<br>
high-level properties:<br>
<br>
1. Chaos monkey test (disable random node, see if certain invariants hold);<br>
2. Evil node test (make several nodes work against the system, see if<br>
certain properties hold);<br>
3. Rigorous testing of network-wide invariants, if all the nodes<br>
operate correctly.<br>
<br>
The problem we're facing is the following — if we want to inspect<br>
state of nodes in Haskell-land, we have to write a huge machinery<br>
which emulates every launch of node via thread. There will be bugs in<br>
this machinery, so we won't be able to get quality testing information<br>
before we fix those; if we want to run things as processes, then the<br>
best thing we can do is to inspect either acid-state dbs of each node<br>
(it poses resource locking problems and forces us to dump the state on<br>
every change, which is undesirable), or make an observer node, which<br>
dumps the consensus as Text and then parsing the data into Haskell<br>
terms, making decisions about the required properties based on that<br>
(so far, it feels like the best option).<br>
<br>
Am I missing something? How is something like this achieved in<br>
culture? How would you approach such a problem?<br>
<br>
Links to source files of test suites which do something similar are<br>
highly appreciated.<br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org" target="_blank">Haskell-Cafe@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
</blockquote></div><br></div>
</blockquote></div>