[erlang-questions] How to mimic Erlang nodes in PropEr statem test

Stavros Aronis <>
Fri Jan 25 14:46:17 CET 2019


Hi Gergő (and list),

before summer I was involved in writing a library for simulating
distributed Erlang systems on a single node:
https://github.com/klarna/vnet

Perhaps you may find some ideas from there useful. You can read a
paper about it (published in Erlang '18) by following the "Modelling
Distributed Erlang within a Single Node" link in
https://concuerror.com/publications (indirect link given to avoid ACMs
access restrictions).

An (admittedly poorly documented) example of its use (also discussed
in the paper) is available here:
https://github.com/klarna/vnet/tree/master/test/counter_server_example

Regards,
Stavros

On Fri, Jan 25, 2019 at 2:03 PM Fred Hebert <> wrote:
>
> On 01/23, Nyirő Gergő wrote:
> >
> >Right now I have only one gen_server (crdt_server) per node, but I would
> >like to add an event handler (crdt_event) which could persist the content
> >of the crdt set or log the executed commands.
> >
>
> Okay, so that's essentially duplicating the messages: send them to the
> server, but you want to asynchronously log with another process. Do I
> understand this right?
>
> >crdt_event could be registered with a fix name then all the
> >crdt_server processes
> >in the proper statem test will send the events to the same event handler, so
> >the event has to be extended with a reference to the sender (e.g: the name
> >or pid of the crdt_server). It seems too complicated for my situation.
>
> Is the event handler only required for the tests? If so, that can make
> sense. If you're working with the same design for your production
> system, it would generally be a better idea to have one process that
> handles the logging per CRDT server, assuming what you end up with is
> one file per server, in order.
>
> Using the same handler for multiple servers is a possibility, but you
> have a lot more risk and complexity—as you noted, you'd need to start
> identifying each message, rather than just giving the event manager a
> destination where to output traffic—while coupling the runtime of
> unrelated files.
>
> >
> >Other solution would be to pass the NameOrPid of the crdt_event processes to
> >crdt_server processes, but a process registry could be a more elegant solution.
> >
>
> This is a possibility. There are other options such as:
>
> - Each crdt_server is spawned under a crdt_sup. The crdt_sup works by
>   booting two processes: crdt_log (first) and crdt_server (second). Each
>   is passed a name that identifies the server ("crdt_1", `node_a`, or
>   whatever)
> - By using a dynamic process registry like gproc (see
>   https://hex.pm/packages/gproc) and replacing the name registration
>   from {local, Name} to {via, gproc, {n, l, {crdt_log, Name}}} and {via,
>   gproc, {n, l, {crdt_server, Name}}} you can give them unique names
>   that they can "know"
> - On every call the crdt_server wants to log, it can call a function
>   from the crdt_log module, such as crdt_log:do_log(Name, Contents)
>
> If you implement the latter function as:
>
>     -module(crdt_log).
>
>     ...
>
>     start_link(Name) ->
>         %% {n, l, Name} stands for "{name, local, ActualName}" but gproc
>         %% uses shorthand
>         gen_server:start_link({via, gproc, {n, l, {crdt_log, Name}}},
>                               ?MODULE, [], []).
>
>     ...
>
>     do_log(Name, Event) ->
>         gen_server:cast({via, gproc, {n, l, {crdt_log, Name}}}, Event).
>
>     ...
>
> Then you'll be able to call the log process from within the other one
> and send asynchronous events this way. You can then consider both
> processes as one unit that fits under one supervisor. For your test, you
> now want to boot 3 of these supervisors instead of only 3 servers, and
> you should get a rather transparent layer added otherwise.
>
>
> >Should I use ct_property_test [1] instead?
> >
>
> This is an experimental call or module to integrate the results of your
> properties to the common test flow. You're free to use it if you want to
> integrate everything into CT.
>
> I personally maintain the rebar3 plugin for PropEr and I tend to prefer
> it for some of the additional features it adds:
>
> - meta functions
>   https://github.com/ferd/rebar3_proper#per-properties-meta-functions
>   (which I might need to contribute upstream to PropEr instead)
> - The ability to run a `rebar3 proper --retry` to get the last failing
>   case run again
> - The `rebar3 proper --store` call, which can be called after a failure
>   to store the failing cases in a file that can be used to test
>   regressions
> - The `rebar3 proper --regressions` switch, which replays the previously
>   stored couterexamples.
>
> You can, of course, get all of this by doing more manual work in CT or
> by transcribing counterexamples by hand into regression tests. I
> personally just use the proper and CT commands distinctly, and instead
> add a rebar3 alias for both:
>
>     {alias, [{check, [ct, proper]}]}.
>
> Which then lets me call 'rebar3 check' and runs both the CT and the
> PropEr test suites.
>
> Regards,
> Fred.
> _______________________________________________
> erlang-questions mailing list
> 
> http://erlang.org/mailman/listinfo/erlang-questions


More information about the erlang-questions mailing list