emqx_dashboard_api_test_helpers.erl 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2022-2024 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_dashboard_api_test_helpers).
  17. -export([
  18. set_default_config/0,
  19. set_default_config/1,
  20. set_default_config/2,
  21. set_default_config/3,
  22. request/2,
  23. request/3,
  24. request/4,
  25. request/5,
  26. request/6,
  27. multipart_formdata_request/3,
  28. multipart_formdata_request/4,
  29. host/0,
  30. uri/0,
  31. uri/1,
  32. uri/2
  33. ]).
  34. -define(HOST, "http://127.0.0.1:18083").
  35. -define(API_VERSION, "v5").
  36. -define(BASE_PATH, "api").
  37. set_default_config() ->
  38. set_default_config(<<"admin">>).
  39. set_default_config(DefaultUsername) ->
  40. set_default_config(DefaultUsername, false).
  41. set_default_config(DefaultUsername, HAProxyEnabled) ->
  42. set_default_config(DefaultUsername, HAProxyEnabled, #{}).
  43. set_default_config(DefaultUsername, HAProxyEnabled, Opts) ->
  44. Config = #{
  45. listeners => #{
  46. http => #{
  47. bind => maps:get(bind, Opts, 18083),
  48. inet6 => false,
  49. ipv6_v6only => false,
  50. max_connections => 512,
  51. num_acceptors => 4,
  52. send_timeout => 5000,
  53. backlog => 512,
  54. proxy_header => HAProxyEnabled
  55. }
  56. },
  57. default_username => DefaultUsername,
  58. default_password => <<"public">>,
  59. i18n_lang => en
  60. },
  61. emqx_config:put([dashboard], Config),
  62. ok.
  63. request(Method, Url) ->
  64. request(Method, Url, []).
  65. request(Method, Url, Body) ->
  66. request(<<"admin">>, Method, Url, Body).
  67. request(Username, Method, Url, Body) ->
  68. request(Username, <<"public">>, Method, Url, Body).
  69. request(Username, Password, Method, Url, Body) ->
  70. request(Username, Password, Method, Url, Body, #{}).
  71. request(Username, Password, Method, Url, Body0, Headers) ->
  72. Request =
  73. case Body0 of
  74. [] when
  75. Method =:= get orelse Method =:= put orelse
  76. Method =:= head orelse Method =:= delete orelse
  77. Method =:= trace
  78. ->
  79. {Url, [auth_header(Username, Password)]};
  80. _ ->
  81. ContentType = maps:get("content-type", Headers, "application/json"),
  82. HeadersList = maps:to_list(maps:without(["content-type"], Headers)),
  83. Body = maybe_encode(Body0),
  84. {Url, [auth_header(Username, Password) | HeadersList], ContentType, Body}
  85. end,
  86. ct:pal("Method: ~p, Request: ~p", [Method, Request]),
  87. case httpc:request(Method, Request, [], [{body_format, binary}]) of
  88. {error, socket_closed_remotely} ->
  89. {error, socket_closed_remotely};
  90. {ok, {{"HTTP/1.1", Code, _}, _Headers, Return}} ->
  91. {ok, Code, Return};
  92. {ok, {Reason, _, _}} ->
  93. {error, Reason}
  94. end.
  95. maybe_encode(Body) when is_binary(Body) -> Body;
  96. maybe_encode(Body) -> emqx_utils_json:encode(Body).
  97. host() ->
  98. ?HOST.
  99. uri() ->
  100. uri([]).
  101. uri(Parts) when is_list(Parts) ->
  102. uri(host(), Parts).
  103. uri(Host, Parts) when is_list(Host), is_list(Parts) ->
  104. NParts = [E || E <- Parts],
  105. Host ++ "/" ++ to_list(filename:join([?BASE_PATH, ?API_VERSION | NParts])).
  106. auth_header(Username) ->
  107. auth_header(Username, <<"public">>).
  108. auth_header(Username, Password) ->
  109. {ok, _Role, Token} = emqx_dashboard_admin:sign_token(Username, Password),
  110. {"Authorization", "Bearer " ++ binary_to_list(Token)}.
  111. multipart_formdata_request(Url, Fields, Files) ->
  112. multipart_formdata_request(Url, <<"admin">>, Fields, Files).
  113. multipart_formdata_request(Url, Username, Fields, Files) ->
  114. Boundary =
  115. "------------" ++ integer_to_list(rand:uniform(99999999999999999)) ++
  116. integer_to_list(erlang:system_time(millisecond)),
  117. Body = format_multipart_formdata(Boundary, Fields, Files),
  118. ContentType = lists:concat(["multipart/form-data; boundary=", Boundary]),
  119. Headers =
  120. [
  121. auth_header(Username),
  122. {"Content-Length", integer_to_list(length(Body))}
  123. ],
  124. case httpc:request(post, {Url, Headers, ContentType, Body}, [], []) of
  125. {error, socket_closed_remotely} ->
  126. {error, socket_closed_remotely};
  127. {ok, {{"HTTP/1.1", Code, _}, _Headers, Return}} ->
  128. {ok, Code, Return};
  129. {ok, {Reason, _, _}} ->
  130. {error, Reason}
  131. end.
  132. format_multipart_formdata(Boundary, Fields, Files) ->
  133. FieldParts = lists:map(
  134. fun({FieldName, FieldContent}) ->
  135. [
  136. lists:concat(["--", Boundary]),
  137. lists:concat([
  138. "Content-Disposition: form-data; name=\"", atom_to_list(FieldName), "\""
  139. ]),
  140. "",
  141. to_list(FieldContent)
  142. ]
  143. end,
  144. Fields
  145. ),
  146. FieldParts2 = lists:append(FieldParts),
  147. FileParts = lists:map(
  148. fun({FieldName, FileName, FileContent}) ->
  149. [
  150. lists:concat(["--", Boundary]),
  151. lists:concat([
  152. "Content-Disposition: form-data; name=\"",
  153. atom_to_list(FieldName),
  154. "\"; filename=\"",
  155. FileName,
  156. "\""
  157. ]),
  158. lists:concat(["Content-Type: ", "application/octet-stream"]),
  159. "",
  160. to_list(FileContent)
  161. ]
  162. end,
  163. Files
  164. ),
  165. FileParts2 = lists:append(FileParts),
  166. EndingParts = [lists:concat(["--", Boundary, "--"]), ""],
  167. Parts = lists:append([FieldParts2, FileParts2, EndingParts]),
  168. string:join(Parts, "\r\n").
  169. to_list(Bin) when is_binary(Bin) -> binary_to_list(Bin);
  170. to_list(Str) when is_list(Str) -> Str.