Skip to content

Limiting the size/complexity of the commands generated by proper_fsm  #315

Open
@rvangraan

Description

@rvangraan

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions