prop_emqx_sys.erl 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
  3. %%
  4. %% Licensed under the Apache License, Version 2.0 (the "License");
  5. %% you may not use this file except in compliance with the License.
  6. %% You may obtain a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing, software
  11. %% distributed under the License is distributed on an "AS IS" BASIS,
  12. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. %% See the License for the specific language governing permissions and
  14. %% limitations under the License.
  15. %%--------------------------------------------------------------------
  16. -module(prop_emqx_sys).
  17. -include_lib("proper/include/proper.hrl").
  18. -export([ initial_state/0
  19. , command/1
  20. , precondition/2
  21. , postcondition/3
  22. , next_state/3
  23. ]).
  24. -define(mock_modules,
  25. [ emqx_metrics
  26. , emqx_stats
  27. , emqx_broker
  28. , mria_mnesia
  29. ]).
  30. -define(ALL(Vars, Types, Exprs),
  31. ?SETUP(fun() ->
  32. State = do_setup(),
  33. fun() -> do_teardown(State) end
  34. end, ?FORALL(Vars, Types, Exprs))).
  35. %%--------------------------------------------------------------------
  36. %% Properties
  37. %%--------------------------------------------------------------------
  38. prop_sys() ->
  39. ?ALL(Cmds, commands(?MODULE),
  40. begin
  41. {ok, _Pid} = emqx_sys:start_link(),
  42. {History, State, Result} = run_commands(?MODULE, Cmds),
  43. ok = emqx_sys:stop(),
  44. ?WHENFAIL(io:format("History: ~p\nState: ~p\nResult: ~p\n",
  45. [History,State,Result]),
  46. aggregate(command_names(Cmds), Result =:= ok))
  47. end).
  48. %%--------------------------------------------------------------------
  49. %% Helpers
  50. %%--------------------------------------------------------------------
  51. do_setup() ->
  52. ok = emqx_logger:set_log_level(emergency),
  53. emqx_config:put([broker, sys_msg_interval], 60000),
  54. emqx_config:put([broker, sys_heartbeat_interval], 30000),
  55. [mock(Mod) || Mod <- ?mock_modules],
  56. ok.
  57. do_teardown(_) ->
  58. ok = emqx_logger:set_log_level(error),
  59. [ok = meck:unload(Mod) || Mod <- ?mock_modules],
  60. ok.
  61. mock(Module) ->
  62. ok = meck:new(Module, [passthrough, no_history]),
  63. do_mock(Module).
  64. do_mock(emqx_broker) ->
  65. meck:expect(emqx_broker, publish,
  66. fun(Msg) -> {node(), <<"test">>, Msg} end),
  67. meck:expect(emqx_broker, safe_publish,
  68. fun(Msg) -> {node(), <<"test">>, Msg} end);
  69. do_mock(emqx_stats) ->
  70. meck:expect(emqx_stats, getstats, fun() -> [0] end);
  71. do_mock(mria_mnesia) ->
  72. meck:expect(mria_mnesia, running_nodes, fun() -> [node()] end);
  73. do_mock(emqx_metrics) ->
  74. meck:expect(emqx_metrics, all, fun() -> [{hello, 3}] end).
  75. %%--------------------------------------------------------------------
  76. %% MODEL
  77. %%--------------------------------------------------------------------
  78. %% @doc Initial model value at system start. Should be deterministic.
  79. initial_state() ->
  80. #{}.
  81. %% @doc List of possible commands to run against the system
  82. command(_State) ->
  83. oneof([{call, emqx_sys, info, []},
  84. {call, emqx_sys, version, []},
  85. {call, emqx_sys, uptime, []},
  86. {call, emqx_sys, datetime, []},
  87. {call, emqx_sys, sysdescr, []},
  88. %------------ unexpected message ----------------------%
  89. {call, emqx_sys, handle_call, [emqx_sys, other, state]},
  90. {call, emqx_sys, handle_cast, [emqx_sys, other]},
  91. {call, emqx_sys, handle_info, [info, state]}
  92. ]).
  93. precondition(_State, {call, _Mod, _Fun, _Args}) ->
  94. true.
  95. postcondition(_State, {call, emqx_sys, info, []}, Info) ->
  96. is_list(Info) andalso length(Info) =:= 4;
  97. postcondition(_State, {call, emqx_sys, version, []}, Version) ->
  98. is_list(Version);
  99. postcondition(_State, {call, emqx_sys, uptime, []}, Uptime) ->
  100. is_integer(Uptime);
  101. postcondition(_State, {call, emqx_sys, datetime, []}, Datetime) ->
  102. is_list(Datetime);
  103. postcondition(_State, {call, emqx_sys, sysdescr, []}, Sysdescr) ->
  104. is_list(Sysdescr);
  105. postcondition(_State, {call, emqx_sys, sys_interval, []}, SysInterval) ->
  106. is_integer(SysInterval) andalso SysInterval > 0;
  107. postcondition(_State, {call, emqx_sys, sys_heartbeat_interval, []}, SysHeartInterval) ->
  108. is_integer(SysHeartInterval) andalso SysHeartInterval > 0;
  109. postcondition(_State, {call, _Mod, _Fun, _Args}, _Res) ->
  110. true.
  111. next_state(State, _Res, {call, _Mod, _Fun, _Args}) ->
  112. NewState = State,
  113. NewState.