Description
Hi there,
I'm working on tests that rely on proper_fsm
. I'm noticing that proper_fsm:commands(?MODULE)
generates truly gigantic command sequences. I'm using a lot of inferred state, i.e. delayed symbolic evaluations to effect state and it seems that sometimes these things becoming recursive. With that I mean code like this, that uses symbolic functions to calculate state:
...
next_state_data(try_connect_client, _, S, Result, {call,_,connect,_}) ->
S#{
client_state => {call, ?MODULE, derive_client_state, [Result]}
};
next_state_data(client_connected, _, S, Result, {call,_,tcp_send,[_, Payload]}) ->
S#{
payloads_sent => {call, ?MODULE, derive_add_payload_if_sent, [S, Result, Payload]},
payload_counter => {call, ?MODULE, derive_payload_counter, [S, Result]}
};
next_state_data(client_connected, _, S, _Result, {call,_,disconnect,_}) ->
S#{client_state => disconnected}.
Some of the more extreme examples (That don't blow up):
Cmd len: 26 size: 92,736,416 bytes
If I sample a few of the outputs, you'll see the delayed evaluation calls:
{ok,{forall,[{set,{var,1},
{call,gen_tcp_test_proxy,resume,[{var,'PID'}]}},
{set,{var,2},
{call,gen_tcp_test_proxy,connect,[{var,'PID'}]}},
{set,{var,3},
{call,gen_tcp_test_proxy,tcp_send,
[{var,'PID'},
{call,gen_tcp_server_layer_tests,payload,
[#{payload_counter => 1,lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline}]}]}},
{set,{var,4},
{call,gen_tcp_test_proxy,disconnect,[{var,'PID'}]}},
{set,{var,5},
{call,gen_tcp_test_proxy,connect,[{var,'PID'}]}},
{set,{var,6},
{call,gen_tcp_test_proxy,disconnect,[{var,'PID'}]}},
{set,{var,7},
{call,gen_tcp_test_proxy,signal_from_bottom,
[{var,'PID'},layer_up]}},
{set,{var,8},
{call,gen_tcp_test_proxy,connect,[{var,'PID'}]}}],
This code works fine for shorter sequences, but the generator produces gigantic examples, that literally causes my beam VM to run out of memory.
So is there a way to limit the size of these things?
Here is a (bigger) example. There is nothing wrong with this test case, it does what it's supposed to. The issue is that the generator produces much, much bigger ones.
{ok,{forall,[{set,{var,1},
{call,gen_tcp_test_proxy,resume,[{var,'PID'}]}},
{set,{var,2},
{call,gen_tcp_test_proxy,connect,[{var,'PID'}]}},
{set,{var,3},
{call,gen_tcp_test_proxy,tcp_send,
[{var,'PID'},
{call,gen_tcp_server_layer_tests,payload,
[#{payload_counter => 1,lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline}]}]}},
{set,{var,4},
{call,gen_tcp_test_proxy,tcp_send,
[{var,'PID'},
{call,gen_tcp_server_layer_tests,payload,
[#{payloads_sent =>
{call,gen_tcp_server_layer_tests,derive_add_payload_if_sent,
[#{payload_counter => 1,lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline},
{var,3},
{call,gen_tcp_server_layer_tests,payload,
[#{payload_counter => 1,lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline}]}]},
payload_counter =>
{call,gen_tcp_server_layer_tests,derive_payload_counter,
[#{payload_counter => 1,lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline},
{var,3}]},
lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline}]}]}},
{set,{var,5},
{call,gen_tcp_test_proxy,tcp_send,
[{var,'PID'},
{call,gen_tcp_server_layer_tests,payload,
[#{payloads_sent =>
{call,gen_tcp_server_layer_tests,derive_add_payload_if_sent,
[#{payloads_sent =>
{call,gen_tcp_server_layer_tests,derive_add_payload_if_sent,
[#{payload_counter => 1,lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline},
{var,3},
{call,gen_tcp_server_layer_tests,payload,
[#{payload_counter => 1,lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline}]}]},
payload_counter =>
{call,gen_tcp_server_layer_tests,derive_payload_counter,
[#{payload_counter => 1,lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline},
{var,3}]},
lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline},
{var,4},
{call,gen_tcp_server_layer_tests,payload,
[#{payloads_sent =>
{call,gen_tcp_server_layer_tests,derive_add_payload_if_sent,
[#{payload_counter => 1,lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline},
{var,3},
{call,gen_tcp_server_layer_tests,payload,
[#{payload_counter => 1,lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline}]}]},
payload_counter =>
{call,gen_tcp_server_layer_tests,derive_payload_counter,
[#{payload_counter => 1,lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline},
{var,3}]},
lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline}]}]},
payload_counter =>
{call,gen_tcp_server_layer_tests,derive_payload_counter,
[#{payloads_sent =>
{call,gen_tcp_server_layer_tests,derive_add_payload_if_sent,
[#{payload_counter => 1,lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline},
{var,3},
{call,gen_tcp_server_layer_tests,payload,
[#{payload_counter => 1,lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline}]}]},
payload_counter =>
{call,gen_tcp_server_layer_tests,derive_payload_counter,
[#{payload_counter => 1,lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline},
{var,3}]},
lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline},
{var,4}]},
lower_layer_state => offline,
client_state =>
{call,gen_tcp_server_layer_tests,derive_client_state,
[{var,2}]},
stack_state => offline}]}]}},
{set,{var,6},
{call,gen_tcp_test_proxy,disconnect,[{var,'PID'}]}},
{set,{var,7},
{call,gen_tcp_test_proxy,signal_from_bottom,
[{var,'PID'},layer_up]}}],
#Fun<gen_tcp_server_layer_tests.2.77195010>}}
Thanks!
R