emqx_modules_SUITE.erl 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2020-2021 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(emqx_modules_SUITE).
  17. -compile(export_all).
  18. -compile(nowarn_export_all).
  19. -include_lib("eunit/include/eunit.hrl").
  20. -define(CONTENT_TYPE, "application/x-www-form-urlencoded").
  21. -define(HOST, "http://127.0.0.1:8081/").
  22. -define(API_VERSION, "v4").
  23. -define(BASE_PATH, "api").
  24. all() -> emqx_ct:all(?MODULE).
  25. init_per_suite(Config) ->
  26. emqx_ct_helpers:start_apps([emqx_management, emqx_modules], fun set_special_cfg/1),
  27. emqx_ct_http:create_default_app(),
  28. Config.
  29. set_special_cfg(_) ->
  30. application:set_env(emqx, modules_loaded_file, emqx_ct_helpers:deps_path(emqx, "test/emqx_SUITE_data/loaded_modules")),
  31. ok.
  32. end_per_suite(_Config) ->
  33. emqx_ct_http:delete_default_app(),
  34. emqx_ct_helpers:stop_apps([emqx_modules, emqx_management]).
  35. t_load(_) ->
  36. ?assertEqual(ok, emqx_modules:unload()),
  37. ?assertEqual(ok, emqx_modules:load()),
  38. ?assertEqual({error, not_found}, emqx_modules:load(not_existed_module)),
  39. ?assertEqual({error, not_started}, emqx_modules:unload(emqx_mod_rewrite)),
  40. ?assertEqual(ignore, emqx_modules:reload(emqx_mod_rewrite)),
  41. ?assertEqual(ok, emqx_modules:reload(emqx_mod_acl_internal)).
  42. t_list(_) ->
  43. ?assertMatch([{_, _} | _ ], emqx_modules:list()).
  44. t_modules_api(_) ->
  45. emqx_modules:load_module(emqx_mod_presence, false),
  46. timer:sleep(50),
  47. {ok, Modules1} = request_api(get, api_path(["modules"]), auth_header_()),
  48. [Modules11] = filter(get(<<"data">>, Modules1), <<"node">>, atom_to_binary(node(), utf8)),
  49. [Module1] = filter(maps:get(<<"modules">>, Modules11), <<"name">>, <<"emqx_mod_presence">>),
  50. ?assertEqual(<<"emqx_mod_presence">>, maps:get(<<"name">>, Module1)),
  51. ?assertEqual(true, maps:get(<<"active">>, Module1)),
  52. {ok, _} = request_api(put,
  53. api_path(["modules",
  54. atom_to_list(emqx_mod_presence),
  55. "unload"]),
  56. auth_header_()),
  57. {ok, Error1} = request_api(put,
  58. api_path(["modules",
  59. atom_to_list(emqx_mod_presence),
  60. "unload"]),
  61. auth_header_()),
  62. ?assertEqual(<<"not_started">>, get(<<"message">>, Error1)),
  63. {ok, Modules2} = request_api(get,
  64. api_path(["nodes", atom_to_list(node()), "modules"]),
  65. auth_header_()),
  66. [Module2] = filter(get(<<"data">>, Modules2), <<"name">>, <<"emqx_mod_presence">>),
  67. ?assertEqual(<<"emqx_mod_presence">>, maps:get(<<"name">>, Module2)),
  68. ?assertEqual(false, maps:get(<<"active">>, Module2)),
  69. {ok, _} = request_api(put,
  70. api_path(["nodes",
  71. atom_to_list(node()),
  72. "modules",
  73. atom_to_list(emqx_mod_presence),
  74. "load"]),
  75. auth_header_()),
  76. {ok, Modules3} = request_api(get,
  77. api_path(["nodes", atom_to_list(node()), "modules"]),
  78. auth_header_()),
  79. [Module3] = filter(get(<<"data">>, Modules3), <<"name">>, <<"emqx_mod_presence">>),
  80. ?assertEqual(<<"emqx_mod_presence">>, maps:get(<<"name">>, Module3)),
  81. ?assertEqual(true, maps:get(<<"active">>, Module3)),
  82. {ok, _} = request_api(put,
  83. api_path(["nodes",
  84. atom_to_list(node()),
  85. "modules",
  86. atom_to_list(emqx_mod_presence),
  87. "unload"]),
  88. auth_header_()),
  89. {ok, Error2} = request_api(put,
  90. api_path(["nodes",
  91. atom_to_list(node()),
  92. "modules",
  93. atom_to_list(emqx_mod_presence),
  94. "unload"]),
  95. auth_header_()),
  96. ?assertEqual(<<"not_started">>, get(<<"message">>, Error2)),
  97. emqx_modules:unload(emqx_mod_presence).
  98. t_modules_cmd(_) ->
  99. mock_print(),
  100. meck:new(emqx_modules, [non_strict, passthrough]),
  101. meck:expect(emqx_modules, load, fun(_) -> ok end),
  102. meck:expect(emqx_modules, unload, fun(_) -> ok end),
  103. meck:expect(emqx_modules, reload, fun(_) -> ok end),
  104. ?assertEqual(emqx_modules:cli(["list"]), ok),
  105. ?assertEqual(emqx_modules:cli(["load", "emqx_mod_presence"]),
  106. "Module emqx_mod_presence loaded successfully.\n"),
  107. ?assertEqual(emqx_modules:cli(["unload", "emqx_mod_presence"]),
  108. "Module emqx_mod_presence unloaded successfully.\n"),
  109. unmock_print().
  110. %% For: https://github.com/emqx/emqx/issues/4511
  111. t_join_cluster(_) ->
  112. %% Started by emqx application
  113. {error, {already_started, emqx_modules}} = application:start(emqx_modules),
  114. %% After clustered
  115. emqx:shutdown(),
  116. emqx:reboot(),
  117. {error,{already_started,emqx_modules}} = application:start(emqx_modules),
  118. %% After emqx reboot, we should not interfere with other tests
  119. _ = end_per_suite([]),
  120. _ = init_per_suite([]),
  121. ok.
  122. mock_print() ->
  123. catch meck:unload(emqx_ctl),
  124. meck:new(emqx_ctl, [non_strict, passthrough]),
  125. meck:expect(emqx_ctl, print, fun(Arg) -> emqx_ctl:format(Arg) end),
  126. meck:expect(emqx_ctl, print, fun(Msg, Arg) -> emqx_ctl:format(Msg, Arg) end),
  127. meck:expect(emqx_ctl, usage, fun(Usages) -> emqx_ctl:format_usage(Usages) end),
  128. meck:expect(emqx_ctl, usage, fun(Cmd, Descr) -> emqx_ctl:format_usage(Cmd, Descr) end).
  129. unmock_print() ->
  130. meck:unload(emqx_ctl).
  131. get(Key, ResponseBody) ->
  132. maps:get(Key, jiffy:decode(list_to_binary(ResponseBody), [return_maps])).
  133. request_api(Method, Url, Auth) ->
  134. request_api(Method, Url, [], Auth, []).
  135. request_api(Method, Url, QueryParams, Auth) ->
  136. request_api(Method, Url, QueryParams, Auth, []).
  137. request_api(Method, Url, QueryParams, Auth, []) ->
  138. NewUrl = case QueryParams of
  139. "" -> Url;
  140. _ -> Url ++ "?" ++ QueryParams
  141. end,
  142. do_request_api(Method, {NewUrl, [Auth]});
  143. request_api(Method, Url, QueryParams, Auth, Body) ->
  144. NewUrl = case QueryParams of
  145. "" -> Url;
  146. _ -> Url ++ "?" ++ QueryParams
  147. end,
  148. do_request_api(Method, {NewUrl, [Auth], "application/json", emqx_json:encode(Body)}).
  149. do_request_api(Method, Request)->
  150. ct:pal("Method: ~p, Request: ~p", [Method, Request]),
  151. case httpc:request(Method, Request, [], []) of
  152. {error, socket_closed_remotely} ->
  153. {error, socket_closed_remotely};
  154. {ok, {{"HTTP/1.1", Code, _}, _, Return} }
  155. when Code =:= 200 orelse Code =:= 201 ->
  156. {ok, Return};
  157. {ok, {Reason, _, _}} ->
  158. {error, Reason}
  159. end.
  160. auth_header_() ->
  161. AppId = <<"admin">>,
  162. AppSecret = <<"public">>,
  163. auth_header_(binary_to_list(AppId), binary_to_list(AppSecret)).
  164. auth_header_(User, Pass) ->
  165. Encoded = base64:encode_to_string(lists:append([User,":",Pass])),
  166. {"Authorization","Basic " ++ Encoded}.
  167. api_path(Parts)->
  168. ?HOST ++ filename:join([?BASE_PATH, ?API_VERSION] ++ Parts).
  169. filter(List, Key, Value) ->
  170. lists:filter(fun(Item) ->
  171. maps:get(Key, Item) == Value
  172. end, List).