chore(emqx_management): update test case
This commit is contained in:
parent
033f8619eb
commit
24d954282d
|
@ -3,7 +3,7 @@
|
||||||
{vsn, "4.3.0"}, % strict semver, bump manually!
|
{vsn, "4.3.0"}, % strict semver, bump manually!
|
||||||
{modules, []},
|
{modules, []},
|
||||||
{registered, [emqx_management_sup]},
|
{registered, [emqx_management_sup]},
|
||||||
{applications, [kernel,stdlib,minirest,emqx_modules]},
|
{applications, [kernel,stdlib,minirest]},
|
||||||
{mod, {emqx_mgmt_app,[]}},
|
{mod, {emqx_mgmt_app,[]}},
|
||||||
{env, []},
|
{env, []},
|
||||||
{licenses, ["Apache-2.0"]},
|
{licenses, ["Apache-2.0"]},
|
||||||
|
|
|
@ -483,16 +483,6 @@ delete_banned(Who) ->
|
||||||
emqx_banned:delete(Who).
|
emqx_banned:delete(Who).
|
||||||
|
|
||||||
|
|
||||||
any_to_atom(L) when is_list(L) -> list_to_atom(L);
|
|
||||||
any_to_atom(B) when is_binary(B) -> binary_to_atom(B, utf8);
|
|
||||||
any_to_atom(A) when is_atom(A) -> A.
|
|
||||||
|
|
||||||
to_version(Version) when is_integer(Version) ->
|
|
||||||
integer_to_list(Version);
|
|
||||||
to_version(Version) when is_binary(Version) ->
|
|
||||||
binary_to_list(Version);
|
|
||||||
to_version(Version) when is_list(Version) ->
|
|
||||||
Version.
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Telemtry API
|
%% Telemtry API
|
||||||
|
@ -561,20 +551,4 @@ max_row_limit() ->
|
||||||
|
|
||||||
table_size(Tab) -> ets:info(Tab, size).
|
table_size(Tab) -> ets:info(Tab, size).
|
||||||
|
|
||||||
map_to_actions(Maps) ->
|
|
||||||
[map_to_action(M) || M <- Maps].
|
|
||||||
|
|
||||||
map_to_action(Map = #{<<"id">> := ActionInstId, <<"name">> := Name, <<"args">> := Args}) ->
|
|
||||||
#{id => ActionInstId,
|
|
||||||
name => any_to_atom(Name),
|
|
||||||
args => Args,
|
|
||||||
fallbacks => map_to_actions(maps:get(<<"fallbacks">>, Map, []))}.
|
|
||||||
|
|
||||||
actions_to_prop_list(Actions) ->
|
|
||||||
[action_to_prop_list(Act) || Act <- Actions].
|
|
||||||
|
|
||||||
action_to_prop_list({action_instance, ActionInstId, Name, FallbackActions, Args}) ->
|
|
||||||
[{id, ActionInstId},
|
|
||||||
{name, Name},
|
|
||||||
{fallbacks, actions_to_prop_list(FallbackActions)},
|
|
||||||
{args, Args}].
|
|
||||||
|
|
|
@ -75,7 +75,11 @@
|
||||||
]).
|
]).
|
||||||
|
|
||||||
export(_Bindings, _Params) ->
|
export(_Bindings, _Params) ->
|
||||||
return(emqx_mgmt_data_backup:export()).
|
case emqx_mgmt_data_backup:export() of
|
||||||
|
{ok, File = #{filename := Filename}} ->
|
||||||
|
return({ok, File#{filename => filename:basename(Filename)}});
|
||||||
|
Return -> return(Return)
|
||||||
|
end.
|
||||||
|
|
||||||
list_exported(_Bindings, _Params) ->
|
list_exported(_Bindings, _Params) ->
|
||||||
List = [ rpc:call(Node, ?MODULE, get_list_exported, []) || Node <- ekka_mnesia:running_nodes() ],
|
List = [ rpc:call(Node, ?MODULE, get_list_exported, []) || Node <- ekka_mnesia:running_nodes() ],
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
-spec(load() -> ok).
|
-spec(load() -> ok).
|
||||||
load() ->
|
load() ->
|
||||||
Cmds = [Fun || {Fun, _} <- ?MODULE:module_info(exports), is_cmd(Fun)],
|
Cmds = [Fun || {Fun, _} <- ?MODULE:module_info(exports), is_cmd(Fun)],
|
||||||
lists:foreach(fun(Cmd) -> emqx_ctl:register_command(Cmd, {?MODULE, Cmd}, []) end, Cmds).
|
foreach(fun(Cmd) -> emqx_ctl:register_command(Cmd, {?MODULE, Cmd}, []) end, Cmds).
|
||||||
|
|
||||||
is_cmd(Fun) ->
|
is_cmd(Fun) ->
|
||||||
not lists:member(Fun, [init, load, module_info]).
|
not lists:member(Fun, [init, load, module_info]).
|
||||||
|
@ -100,7 +100,7 @@ mgmt(["delete", AppId]) ->
|
||||||
end;
|
end;
|
||||||
|
|
||||||
mgmt(["list"]) ->
|
mgmt(["list"]) ->
|
||||||
lists:foreach(fun({AppId, AppSecret, Name, Desc, Status, Expired}) ->
|
foreach(fun({AppId, AppSecret, Name, Desc, Status, Expired}) ->
|
||||||
emqx_ctl:print("app_id: ~s, secret: ~s, name: ~s, desc: ~s, status: ~s, expired: ~p~n",
|
emqx_ctl:print("app_id: ~s, secret: ~s, name: ~s, desc: ~s, status: ~s, expired: ~p~n",
|
||||||
[AppId, AppSecret, Name, Desc, Status, Expired])
|
[AppId, AppSecret, Name, Desc, Status, Expired])
|
||||||
end, emqx_mgmt_auth:list_apps());
|
end, emqx_mgmt_auth:list_apps());
|
||||||
|
@ -229,7 +229,7 @@ routes(_) ->
|
||||||
{"routes show <Topic>", "Show a route"}]).
|
{"routes show <Topic>", "Show a route"}]).
|
||||||
|
|
||||||
subscriptions(["list"]) ->
|
subscriptions(["list"]) ->
|
||||||
lists:foreach(fun(Suboption) ->
|
foreach(fun(Suboption) ->
|
||||||
print({emqx_suboption, Suboption})
|
print({emqx_suboption, Suboption})
|
||||||
end, ets:tab2list(emqx_suboption));
|
end, ets:tab2list(emqx_suboption));
|
||||||
|
|
||||||
|
@ -544,8 +544,8 @@ stop_listener(#{listen_on := ListenOn} = Listener, _Input) ->
|
||||||
|
|
||||||
data(["export"]) ->
|
data(["export"]) ->
|
||||||
case emqx_mgmt_data_backup:export() of
|
case emqx_mgmt_data_backup:export() of
|
||||||
{ok, _} ->
|
{ok, #{filename := Filename}} ->
|
||||||
emqx_ctl:print("The emqx data has been successfully exported to ~s.~n", [NFilename]);
|
emqx_ctl:print("The emqx data has been successfully exported to ~s.~n", [Filename]);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
emqx_ctl:print("The emqx data export failed due to ~p.~n", [Reason])
|
emqx_ctl:print("The emqx data export failed due to ~p.~n", [Reason])
|
||||||
end;
|
end;
|
||||||
|
@ -555,9 +555,9 @@ data(["import", Filename]) ->
|
||||||
ok ->
|
ok ->
|
||||||
emqx_ctl:print("The emqx data has been imported successfully.~n");
|
emqx_ctl:print("The emqx data has been imported successfully.~n");
|
||||||
{error, import_failed} ->
|
{error, import_failed} ->
|
||||||
emqx_ctl:print("The emqx data import failed due: ~0p~n", [{Class,Reason,Stack}]);
|
emqx_ctl:print("The emqx data import failed. ~n");
|
||||||
{error, unsupported_version} ->
|
{error, unsupported_version} ->
|
||||||
emqx_ctl:print("Unsupported version: ~p~n", [Version]);
|
emqx_ctl:print("The emqx data import failed: Unsupported version. ~n");
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
emqx_ctl:print("The emqx data import failed: ~0p while reading ~s.~n", [Reason, Filename])
|
emqx_ctl:print("The emqx data import failed: ~0p while reading ~s.~n", [Reason, Filename])
|
||||||
end;
|
end;
|
||||||
|
@ -636,10 +636,6 @@ print(#plugin{name = Name, descr = Descr, active = Active}) ->
|
||||||
emqx_ctl:print("Plugin(~s, description=~s, active=~s)~n",
|
emqx_ctl:print("Plugin(~s, description=~s, active=~s)~n",
|
||||||
[Name, Descr, Active]);
|
[Name, Descr, Active]);
|
||||||
|
|
||||||
print({module, {Name, Active}}) ->
|
|
||||||
emqx_ctl:print("Module(~s, description=~s, active=~s)~n",
|
|
||||||
[Name, Name:description(), Active]);
|
|
||||||
|
|
||||||
print({emqx_suboption, {{Pid, Topic}, Options}}) when is_pid(Pid) ->
|
print({emqx_suboption, {{Pid, Topic}, Options}}) when is_pid(Pid) ->
|
||||||
emqx_ctl:print("~s -> ~s~n", [maps:get(subid, Options), Topic]).
|
emqx_ctl:print("~s -> ~s~n", [maps:get(subid, Options), Topic]).
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
|
|
||||||
-module(emqx_mgmt_data_backup).
|
-module(emqx_mgmt_data_backup).
|
||||||
|
|
||||||
|
-include("emqx_mgmt.hrl").
|
||||||
|
-include_lib("emqx/include/emqx.hrl").
|
||||||
|
-include_lib("kernel/include/file.hrl").
|
||||||
|
|
||||||
-ifdef(EMQX_ENTERPISE).
|
-ifdef(EMQX_ENTERPISE).
|
||||||
-export([ export_modules/0
|
-export([ export_modules/0
|
||||||
, export_schemas/0
|
, export_schemas/0
|
||||||
|
@ -266,6 +270,14 @@ apply_new_config([Action = #{<<"name">> := <<"data_to_webserver">>,
|
||||||
apply_new_config(More, Configs, [Action#{<<"args">> := Args} | Acc])
|
apply_new_config(More, Configs, [Action#{<<"args">> := Args} | Acc])
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
actions_to_prop_list(Actions) ->
|
||||||
|
[action_to_prop_list(Act) || Act <- Actions].
|
||||||
|
|
||||||
|
action_to_prop_list({action_instance, ActionInstId, Name, FallbackActions, Args}) ->
|
||||||
|
[{id, ActionInstId},
|
||||||
|
{name, Name},
|
||||||
|
{fallbacks, actions_to_prop_list(FallbackActions)},
|
||||||
|
{args, Args}].
|
||||||
|
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
|
@ -415,6 +427,26 @@ import_confs(Configs, ListenersState) ->
|
||||||
|
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
|
any_to_atom(L) when is_list(L) -> list_to_atom(L);
|
||||||
|
any_to_atom(B) when is_binary(B) -> binary_to_atom(B, utf8);
|
||||||
|
any_to_atom(A) when is_atom(A) -> A.
|
||||||
|
|
||||||
|
map_to_actions(Maps) ->
|
||||||
|
[map_to_action(M) || M <- Maps].
|
||||||
|
|
||||||
|
map_to_action(Map = #{<<"id">> := ActionInstId, <<"name">> := Name, <<"args">> := Args}) ->
|
||||||
|
#{id => ActionInstId,
|
||||||
|
name => any_to_atom(Name),
|
||||||
|
args => Args,
|
||||||
|
fallbacks => map_to_actions(maps:get(<<"fallbacks">>, Map, []))}.
|
||||||
|
|
||||||
|
to_version(Version) when is_integer(Version) ->
|
||||||
|
integer_to_list(Version);
|
||||||
|
to_version(Version) when is_binary(Version) ->
|
||||||
|
binary_to_list(Version);
|
||||||
|
to_version(Version) when is_list(Version) ->
|
||||||
|
Version.
|
||||||
|
|
||||||
-ifdef(EMQX_ENTERPRISE).
|
-ifdef(EMQX_ENTERPRISE).
|
||||||
export() ->
|
export() ->
|
||||||
Modules = export_modules(),
|
Modules = export_modules(),
|
||||||
|
@ -507,7 +539,7 @@ export() ->
|
||||||
write_file(NFilename, Data).
|
write_file(NFilename, Data).
|
||||||
|
|
||||||
import(Filename) ->
|
import(Filename) ->
|
||||||
case file:read_file(FullFilename) of
|
case file:read_file(Filename) of
|
||||||
{ok, Json} ->
|
{ok, Json} ->
|
||||||
Data = emqx_json:decode(Json, [return_maps]),
|
Data = emqx_json:decode(Json, [return_maps]),
|
||||||
Version = to_version(maps:get(<<"version">>, Data)),
|
Version = to_version(maps:get(<<"version">>, Data)),
|
||||||
|
@ -532,8 +564,7 @@ import(Filename) ->
|
||||||
logger:error("Unsupported version: ~p", [Version]),
|
logger:error("Unsupported version: ~p", [Version]),
|
||||||
{error, unsupported_version}
|
{error, unsupported_version}
|
||||||
end;
|
end;
|
||||||
{error, Reason} ->
|
Error -> Error
|
||||||
{error, Reason}
|
|
||||||
end.
|
end.
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
|
@ -544,14 +575,12 @@ write_file(Filename, Data) ->
|
||||||
case file:read_file_info(Filename) of
|
case file:read_file_info(Filename) of
|
||||||
{ok, #file_info{size = Size, ctime = {{Y, M, D}, {H, MM, S}}}} ->
|
{ok, #file_info{size = Size, ctime = {{Y, M, D}, {H, MM, S}}}} ->
|
||||||
CreatedAt = io_lib:format("~p-~p-~p ~p:~p:~p", [Y, M, D, H, MM, S]),
|
CreatedAt = io_lib:format("~p-~p-~p ~p:~p:~p", [Y, M, D, H, MM, S]),
|
||||||
{ok, [{filename, list_to_binary(Filename)},
|
{ok, #{filename => list_to_binary(Filename),
|
||||||
{size, Size},
|
size => Size,
|
||||||
{created_at, list_to_binary(CreatedAt)},
|
created_at => list_to_binary(CreatedAt),
|
||||||
{node, node()}
|
node => node()
|
||||||
]};
|
}};
|
||||||
{error, Reason} ->
|
Error -> Error
|
||||||
{error, Reason}
|
|
||||||
end;
|
end;
|
||||||
{error, Reason} ->
|
Error -> Error
|
||||||
{error, Reason}
|
|
||||||
end.
|
end.
|
||||||
|
|
|
@ -44,7 +44,6 @@ groups() ->
|
||||||
t_clients_cmd,
|
t_clients_cmd,
|
||||||
t_vm_cmd,
|
t_vm_cmd,
|
||||||
t_plugins_cmd,
|
t_plugins_cmd,
|
||||||
t_modules_cmd,
|
|
||||||
t_trace_cmd,
|
t_trace_cmd,
|
||||||
t_broker_cmd,
|
t_broker_cmd,
|
||||||
t_router_cmd,
|
t_router_cmd,
|
||||||
|
@ -59,11 +58,11 @@ apps() ->
|
||||||
init_per_suite(Config) ->
|
init_per_suite(Config) ->
|
||||||
ekka_mnesia:start(),
|
ekka_mnesia:start(),
|
||||||
emqx_mgmt_auth:mnesia(boot),
|
emqx_mgmt_auth:mnesia(boot),
|
||||||
emqx_ct_helpers:start_apps([emqx_modules, emqx_management, emqx_auth_mnesia]),
|
emqx_ct_helpers:start_apps([emqx_management, emqx_auth_mnesia]),
|
||||||
Config.
|
Config.
|
||||||
|
|
||||||
end_per_suite(_Config) ->
|
end_per_suite(_Config) ->
|
||||||
emqx_ct_helpers:stop_apps([emqx_management, emqx_auth_mnesia, emqx_modules]).
|
emqx_ct_helpers:stop_apps([emqx_management, emqx_auth_mnesia]).
|
||||||
|
|
||||||
t_app(_Config) ->
|
t_app(_Config) ->
|
||||||
{ok, AppSecret} = emqx_mgmt_auth:add_app(<<"app_id">>, <<"app_name">>),
|
{ok, AppSecret} = emqx_mgmt_auth:add_app(<<"app_id">>, <<"app_name">>),
|
||||||
|
@ -329,19 +328,6 @@ t_plugins_cmd(_) ->
|
||||||
),
|
),
|
||||||
unmock_print().
|
unmock_print().
|
||||||
|
|
||||||
t_modules_cmd(_) ->
|
|
||||||
mock_print(),
|
|
||||||
meck:new(emqx_modules, [non_strict, passthrough]),
|
|
||||||
meck:expect(emqx_modules, load, fun(_) -> ok end),
|
|
||||||
meck:expect(emqx_modules, unload, fun(_) -> ok end),
|
|
||||||
meck:expect(emqx_modules, reload, fun(_) -> ok end),
|
|
||||||
?assertEqual(emqx_mgmt_cli:modules(["list"]), ok),
|
|
||||||
?assertEqual(emqx_mgmt_cli:modules(["load", "emqx_mod_presence"]),
|
|
||||||
"Module emqx_mod_presence loaded successfully.\n"),
|
|
||||||
?assertEqual(emqx_mgmt_cli:modules(["unload", "emqx_mod_presence"]),
|
|
||||||
"Module emqx_mod_presence unloaded successfully.\n"),
|
|
||||||
unmock_print().
|
|
||||||
|
|
||||||
t_cli(_) ->
|
t_cli(_) ->
|
||||||
mock_print(),
|
mock_print(),
|
||||||
?assertMatch({match, _}, re:run(emqx_mgmt_cli:status([""]), "status")),
|
?assertMatch({match, _}, re:run(emqx_mgmt_cli:status([""]), "status")),
|
||||||
|
|
|
@ -48,7 +48,6 @@ groups() ->
|
||||||
, metrics
|
, metrics
|
||||||
, nodes
|
, nodes
|
||||||
, plugins
|
, plugins
|
||||||
, modules
|
|
||||||
, acl_cache
|
, acl_cache
|
||||||
, pubsub
|
, pubsub
|
||||||
, routes_and_subscriptions
|
, routes_and_subscriptions
|
||||||
|
@ -58,13 +57,13 @@ groups() ->
|
||||||
}].
|
}].
|
||||||
|
|
||||||
init_per_suite(Config) ->
|
init_per_suite(Config) ->
|
||||||
emqx_ct_helpers:start_apps([emqx_modules, emqx_management, emqx_auth_mnesia]),
|
emqx_ct_helpers:start_apps([emqx_management, emqx_auth_mnesia]),
|
||||||
ekka_mnesia:start(),
|
ekka_mnesia:start(),
|
||||||
emqx_mgmt_auth:mnesia(boot),
|
emqx_mgmt_auth:mnesia(boot),
|
||||||
Config.
|
Config.
|
||||||
|
|
||||||
end_per_suite(_Config) ->
|
end_per_suite(_Config) ->
|
||||||
emqx_ct_helpers:stop_apps([emqx_auth_mnesia, emqx_management, emqx_modules]),
|
emqx_ct_helpers:stop_apps([emqx_auth_mnesia, emqx_management]),
|
||||||
ekka_mnesia:ensure_stopped().
|
ekka_mnesia:ensure_stopped().
|
||||||
|
|
||||||
init_per_testcase(data, Config) ->
|
init_per_testcase(data, Config) ->
|
||||||
|
@ -382,64 +381,6 @@ plugins(_) ->
|
||||||
auth_header_()),
|
auth_header_()),
|
||||||
?assertEqual(<<"not_started">>, get(<<"message">>, Error2)).
|
?assertEqual(<<"not_started">>, get(<<"message">>, Error2)).
|
||||||
|
|
||||||
modules(_) ->
|
|
||||||
emqx_modules:load_module(emqx_mod_presence, false),
|
|
||||||
timer:sleep(50),
|
|
||||||
{ok, Modules1} = request_api(get, api_path(["modules"]), auth_header_()),
|
|
||||||
[Modules11] = filter(get(<<"data">>, Modules1), <<"node">>, atom_to_binary(node(), utf8)),
|
|
||||||
[Module1] = filter(maps:get(<<"modules">>, Modules11), <<"name">>, <<"emqx_mod_presence">>),
|
|
||||||
?assertEqual(<<"emqx_mod_presence">>, maps:get(<<"name">>, Module1)),
|
|
||||||
?assertEqual(true, maps:get(<<"active">>, Module1)),
|
|
||||||
|
|
||||||
{ok, _} = request_api(put,
|
|
||||||
api_path(["modules",
|
|
||||||
atom_to_list(emqx_mod_presence),
|
|
||||||
"unload"]),
|
|
||||||
auth_header_()),
|
|
||||||
{ok, Error1} = request_api(put,
|
|
||||||
api_path(["modules",
|
|
||||||
atom_to_list(emqx_mod_presence),
|
|
||||||
"unload"]),
|
|
||||||
auth_header_()),
|
|
||||||
?assertEqual(<<"not_started">>, get(<<"message">>, Error1)),
|
|
||||||
{ok, Modules2} = request_api(get,
|
|
||||||
api_path(["nodes", atom_to_list(node()), "modules"]),
|
|
||||||
auth_header_()),
|
|
||||||
[Module2] = filter(get(<<"data">>, Modules2), <<"name">>, <<"emqx_mod_presence">>),
|
|
||||||
?assertEqual(<<"emqx_mod_presence">>, maps:get(<<"name">>, Module2)),
|
|
||||||
?assertEqual(false, maps:get(<<"active">>, Module2)),
|
|
||||||
|
|
||||||
{ok, _} = request_api(put,
|
|
||||||
api_path(["nodes",
|
|
||||||
atom_to_list(node()),
|
|
||||||
"modules",
|
|
||||||
atom_to_list(emqx_mod_presence),
|
|
||||||
"load"]),
|
|
||||||
auth_header_()),
|
|
||||||
{ok, Modules3} = request_api(get,
|
|
||||||
api_path(["nodes", atom_to_list(node()), "modules"]),
|
|
||||||
auth_header_()),
|
|
||||||
[Module3] = filter(get(<<"data">>, Modules3), <<"name">>, <<"emqx_mod_presence">>),
|
|
||||||
?assertEqual(<<"emqx_mod_presence">>, maps:get(<<"name">>, Module3)),
|
|
||||||
?assertEqual(true, maps:get(<<"active">>, Module3)),
|
|
||||||
|
|
||||||
{ok, _} = request_api(put,
|
|
||||||
api_path(["nodes",
|
|
||||||
atom_to_list(node()),
|
|
||||||
"modules",
|
|
||||||
atom_to_list(emqx_mod_presence),
|
|
||||||
"unload"]),
|
|
||||||
auth_header_()),
|
|
||||||
{ok, Error2} = request_api(put,
|
|
||||||
api_path(["nodes",
|
|
||||||
atom_to_list(node()),
|
|
||||||
"modules",
|
|
||||||
atom_to_list(emqx_mod_presence),
|
|
||||||
"unload"]),
|
|
||||||
auth_header_()),
|
|
||||||
?assertEqual(<<"not_started">>, get(<<"message">>, Error2)),
|
|
||||||
emqx_modules:unload(emqx_mod_presence).
|
|
||||||
|
|
||||||
acl_cache(_) ->
|
acl_cache(_) ->
|
||||||
ClientId = <<"client1">>,
|
ClientId = <<"client1">>,
|
||||||
Topic = <<"mytopic">>,
|
Topic = <<"mytopic">>,
|
||||||
|
|
|
@ -176,7 +176,10 @@ write_loaded(false) -> ok.
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @doc Modules Command
|
%% @doc Modules Command
|
||||||
cli(["list"]) ->
|
cli(["list"]) ->
|
||||||
foreach(fun(Module) -> print({module, Module}) end, emqx_modules:list());
|
lists:foreach(fun({Name, Active}) ->
|
||||||
|
emqx_ctl:print("Module(~s, description=~s, active=~s)~n",
|
||||||
|
[Name, Name:description(), Active])
|
||||||
|
end, emqx_modules:list());
|
||||||
|
|
||||||
cli(["load", Name]) ->
|
cli(["load", Name]) ->
|
||||||
case emqx_modules:load(list_to_atom(Name)) of
|
case emqx_modules:load(list_to_atom(Name)) of
|
||||||
|
|
|
@ -72,6 +72,10 @@
|
||||||
, reload/2
|
, reload/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
-export([ do_load_module/2
|
||||||
|
, do_unload_module/2
|
||||||
|
]).
|
||||||
|
|
||||||
list(#{node := Node}, _Params) ->
|
list(#{node := Node}, _Params) ->
|
||||||
return({ok, [format(Module) || Module <- list_modules(Node)]});
|
return({ok, [format(Module) || Module <- list_modules(Node)]});
|
||||||
|
|
||||||
|
@ -79,10 +83,10 @@ list(_Bindings, _Params) ->
|
||||||
return({ok, [format(Node, Modules) || {Node, Modules} <- list_modules()]}).
|
return({ok, [format(Node, Modules) || {Node, Modules} <- list_modules()]}).
|
||||||
|
|
||||||
load(#{node := Node, module := Module}, _Params) ->
|
load(#{node := Node, module := Module}, _Params) ->
|
||||||
return(load_module(Node, Module));
|
return(do_load_module(Node, Module));
|
||||||
|
|
||||||
load(#{module := Module}, _Params) ->
|
load(#{module := Module}, _Params) ->
|
||||||
Results = [load_module(Node, Module) || {Node, _Info} <- list_nodes()],
|
Results = [do_load_module(Node, Module) || {Node, _Info} <- emqx_mgmt:list_nodes()],
|
||||||
case lists:filter(fun(Item) -> Item =/= ok end, Results) of
|
case lists:filter(fun(Item) -> Item =/= ok end, Results) of
|
||||||
[] ->
|
[] ->
|
||||||
return(ok);
|
return(ok);
|
||||||
|
@ -91,10 +95,10 @@ load(#{module := Module}, _Params) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
unload(#{node := Node, module := Module}, _Params) ->
|
unload(#{node := Node, module := Module}, _Params) ->
|
||||||
return(unload_module(Node, Module));
|
return(do_unload_module(Node, Module));
|
||||||
|
|
||||||
unload(#{module := Module}, _Params) ->
|
unload(#{module := Module}, _Params) ->
|
||||||
Results = [unload_module(Node, Module) || {Node, _Info} <- list_nodes()],
|
Results = [do_unload_module(Node, Module) || {Node, _Info} <- emqx_mgmt:list_nodes()],
|
||||||
case lists:filter(fun(Item) -> Item =/= ok end, Results) of
|
case lists:filter(fun(Item) -> Item =/= ok end, Results) of
|
||||||
[] ->
|
[] ->
|
||||||
return(ok);
|
return(ok);
|
||||||
|
@ -109,7 +113,7 @@ reload(#{node := Node, module := Module}, _Params) ->
|
||||||
end;
|
end;
|
||||||
|
|
||||||
reload(#{module := Module}, _Params) ->
|
reload(#{module := Module}, _Params) ->
|
||||||
Results = [reload_module(Node, Module) || {Node, _Info} <- list_nodes()],
|
Results = [reload_module(Node, Module) || {Node, _Info} <- emqx_mgmt:list_nodes()],
|
||||||
case lists:filter(fun(Item) -> Item =/= ok end, Results) of
|
case lists:filter(fun(Item) -> Item =/= ok end, Results) of
|
||||||
[] ->
|
[] ->
|
||||||
return(ok);
|
return(ok);
|
||||||
|
@ -137,15 +141,15 @@ list_modules(Node) when Node =:= node() ->
|
||||||
list_modules(Node) ->
|
list_modules(Node) ->
|
||||||
rpc_call(Node, list_modules, [Node]).
|
rpc_call(Node, list_modules, [Node]).
|
||||||
|
|
||||||
load_module(Node, Module) when Node =:= node() ->
|
do_load_module(Node, Module) when Node =:= node() ->
|
||||||
emqx_modules:load(Module);
|
emqx_modules:load(Module);
|
||||||
load_module(Node, Module) ->
|
do_load_module(Node, Module) ->
|
||||||
rpc_call(Node, load_module, [Node, Module]).
|
rpc_call(Node, do_load_module, [Node, Module]).
|
||||||
|
|
||||||
unload_module(Node, Module) when Node =:= node() ->
|
do_unload_module(Node, Module) when Node =:= node() ->
|
||||||
emqx_modules:unload(Module);
|
emqx_modules:unload(Module);
|
||||||
unload_module(Node, Module) ->
|
do_unload_module(Node, Module) ->
|
||||||
rpc_call(Node, unload_module, [Node, Module]).
|
rpc_call(Node, do_unload_module, [Node, Module]).
|
||||||
|
|
||||||
reload_module(Node, Module) when Node =:= node() ->
|
reload_module(Node, Module) when Node =:= node() ->
|
||||||
emqx_modules:reload(Module);
|
emqx_modules:reload(Module);
|
||||||
|
|
|
@ -21,10 +21,19 @@
|
||||||
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
-define(CONTENT_TYPE, "application/x-www-form-urlencoded").
|
||||||
|
|
||||||
|
-define(HOST, "http://127.0.0.1:8081/").
|
||||||
|
|
||||||
|
-define(API_VERSION, "v4").
|
||||||
|
|
||||||
|
-define(BASE_PATH, "api").
|
||||||
|
|
||||||
all() -> emqx_ct:all(?MODULE).
|
all() -> emqx_ct:all(?MODULE).
|
||||||
|
|
||||||
init_per_suite(Config) ->
|
init_per_suite(Config) ->
|
||||||
emqx_ct_helpers:start_apps([emqx_modules], fun set_sepecial_cfg/1),
|
emqx_ct_helpers:start_apps([emqx_management, emqx_modules], fun set_sepecial_cfg/1),
|
||||||
|
emqx_ct_http:create_default_app(),
|
||||||
Config.
|
Config.
|
||||||
|
|
||||||
set_sepecial_cfg(_) ->
|
set_sepecial_cfg(_) ->
|
||||||
|
@ -32,7 +41,8 @@ set_sepecial_cfg(_) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
end_per_suite(_Config) ->
|
end_per_suite(_Config) ->
|
||||||
emqx_ct_helpers:stop_apps([emqx_modules]).
|
emqx_ct_http:delete_default_app(),
|
||||||
|
emqx_ct_helpers:stop_apps([emqx_modules, emqx_management]).
|
||||||
|
|
||||||
t_load(_) ->
|
t_load(_) ->
|
||||||
?assertEqual(ok, emqx_modules:unload()),
|
?assertEqual(ok, emqx_modules:unload()),
|
||||||
|
@ -45,3 +55,136 @@ t_load(_) ->
|
||||||
t_list(_) ->
|
t_list(_) ->
|
||||||
?assertMatch([{_, _} | _ ], emqx_modules:list()).
|
?assertMatch([{_, _} | _ ], emqx_modules:list()).
|
||||||
|
|
||||||
|
t_modules_api(_) ->
|
||||||
|
emqx_modules:load_module(emqx_mod_presence, false),
|
||||||
|
timer:sleep(50),
|
||||||
|
{ok, Modules1} = request_api(get, api_path(["modules"]), auth_header_()),
|
||||||
|
[Modules11] = filter(get(<<"data">>, Modules1), <<"node">>, atom_to_binary(node(), utf8)),
|
||||||
|
[Module1] = filter(maps:get(<<"modules">>, Modules11), <<"name">>, <<"emqx_mod_presence">>),
|
||||||
|
?assertEqual(<<"emqx_mod_presence">>, maps:get(<<"name">>, Module1)),
|
||||||
|
?assertEqual(true, maps:get(<<"active">>, Module1)),
|
||||||
|
|
||||||
|
{ok, _} = request_api(put,
|
||||||
|
api_path(["modules",
|
||||||
|
atom_to_list(emqx_mod_presence),
|
||||||
|
"unload"]),
|
||||||
|
auth_header_()),
|
||||||
|
{ok, Error1} = request_api(put,
|
||||||
|
api_path(["modules",
|
||||||
|
atom_to_list(emqx_mod_presence),
|
||||||
|
"unload"]),
|
||||||
|
auth_header_()),
|
||||||
|
?assertEqual(<<"not_started">>, get(<<"message">>, Error1)),
|
||||||
|
{ok, Modules2} = request_api(get,
|
||||||
|
api_path(["nodes", atom_to_list(node()), "modules"]),
|
||||||
|
auth_header_()),
|
||||||
|
[Module2] = filter(get(<<"data">>, Modules2), <<"name">>, <<"emqx_mod_presence">>),
|
||||||
|
?assertEqual(<<"emqx_mod_presence">>, maps:get(<<"name">>, Module2)),
|
||||||
|
?assertEqual(false, maps:get(<<"active">>, Module2)),
|
||||||
|
|
||||||
|
{ok, _} = request_api(put,
|
||||||
|
api_path(["nodes",
|
||||||
|
atom_to_list(node()),
|
||||||
|
"modules",
|
||||||
|
atom_to_list(emqx_mod_presence),
|
||||||
|
"load"]),
|
||||||
|
auth_header_()),
|
||||||
|
{ok, Modules3} = request_api(get,
|
||||||
|
api_path(["nodes", atom_to_list(node()), "modules"]),
|
||||||
|
auth_header_()),
|
||||||
|
[Module3] = filter(get(<<"data">>, Modules3), <<"name">>, <<"emqx_mod_presence">>),
|
||||||
|
?assertEqual(<<"emqx_mod_presence">>, maps:get(<<"name">>, Module3)),
|
||||||
|
?assertEqual(true, maps:get(<<"active">>, Module3)),
|
||||||
|
|
||||||
|
{ok, _} = request_api(put,
|
||||||
|
api_path(["nodes",
|
||||||
|
atom_to_list(node()),
|
||||||
|
"modules",
|
||||||
|
atom_to_list(emqx_mod_presence),
|
||||||
|
"unload"]),
|
||||||
|
auth_header_()),
|
||||||
|
{ok, Error2} = request_api(put,
|
||||||
|
api_path(["nodes",
|
||||||
|
atom_to_list(node()),
|
||||||
|
"modules",
|
||||||
|
atom_to_list(emqx_mod_presence),
|
||||||
|
"unload"]),
|
||||||
|
auth_header_()),
|
||||||
|
?assertEqual(<<"not_started">>, get(<<"message">>, Error2)),
|
||||||
|
emqx_modules:unload(emqx_mod_presence).
|
||||||
|
|
||||||
|
|
||||||
|
t_modules_cmd(_) ->
|
||||||
|
mock_print(),
|
||||||
|
meck:new(emqx_modules, [non_strict, passthrough]),
|
||||||
|
meck:expect(emqx_modules, load, fun(_) -> ok end),
|
||||||
|
meck:expect(emqx_modules, unload, fun(_) -> ok end),
|
||||||
|
meck:expect(emqx_modules, reload, fun(_) -> ok end),
|
||||||
|
?assertEqual(emqx_modules:cli(["list"]), ok),
|
||||||
|
?assertEqual(emqx_modules:cli(["load", "emqx_mod_presence"]),
|
||||||
|
"Module emqx_mod_presence loaded successfully.\n"),
|
||||||
|
?assertEqual(emqx_modules:cli(["unload", "emqx_mod_presence"]),
|
||||||
|
"Module emqx_mod_presence unloaded successfully.\n"),
|
||||||
|
unmock_print().
|
||||||
|
|
||||||
|
mock_print() ->
|
||||||
|
catch meck:unload(emqx_ctl),
|
||||||
|
meck:new(emqx_ctl, [non_strict, passthrough]),
|
||||||
|
meck:expect(emqx_ctl, print, fun(Arg) -> emqx_ctl:format(Arg) end),
|
||||||
|
meck:expect(emqx_ctl, print, fun(Msg, Arg) -> emqx_ctl:format(Msg, Arg) end),
|
||||||
|
meck:expect(emqx_ctl, usage, fun(Usages) -> emqx_ctl:format_usage(Usages) end),
|
||||||
|
meck:expect(emqx_ctl, usage, fun(Cmd, Descr) -> emqx_ctl:format_usage(Cmd, Descr) end).
|
||||||
|
|
||||||
|
unmock_print() ->
|
||||||
|
meck:unload(emqx_ctl).
|
||||||
|
|
||||||
|
get(Key, ResponseBody) ->
|
||||||
|
maps:get(Key, jiffy:decode(list_to_binary(ResponseBody), [return_maps])).
|
||||||
|
|
||||||
|
request_api(Method, Url, Auth) ->
|
||||||
|
request_api(Method, Url, [], Auth, []).
|
||||||
|
|
||||||
|
request_api(Method, Url, QueryParams, Auth) ->
|
||||||
|
request_api(Method, Url, QueryParams, Auth, []).
|
||||||
|
|
||||||
|
request_api(Method, Url, QueryParams, Auth, []) ->
|
||||||
|
NewUrl = case QueryParams of
|
||||||
|
"" -> Url;
|
||||||
|
_ -> Url ++ "?" ++ QueryParams
|
||||||
|
end,
|
||||||
|
do_request_api(Method, {NewUrl, [Auth]});
|
||||||
|
request_api(Method, Url, QueryParams, Auth, Body) ->
|
||||||
|
NewUrl = case QueryParams of
|
||||||
|
"" -> Url;
|
||||||
|
_ -> Url ++ "?" ++ QueryParams
|
||||||
|
end,
|
||||||
|
do_request_api(Method, {NewUrl, [Auth], "application/json", emqx_json:encode(Body)}).
|
||||||
|
|
||||||
|
do_request_api(Method, Request)->
|
||||||
|
ct:pal("Method: ~p, Request: ~p", [Method, Request]),
|
||||||
|
case httpc:request(Method, Request, [], []) of
|
||||||
|
{error, socket_closed_remotely} ->
|
||||||
|
{error, socket_closed_remotely};
|
||||||
|
{ok, {{"HTTP/1.1", Code, _}, _, Return} }
|
||||||
|
when Code =:= 200 orelse Code =:= 201 ->
|
||||||
|
{ok, Return};
|
||||||
|
{ok, {Reason, _, _}} ->
|
||||||
|
{error, Reason}
|
||||||
|
end.
|
||||||
|
|
||||||
|
auth_header_() ->
|
||||||
|
AppId = <<"admin">>,
|
||||||
|
AppSecret = <<"public">>,
|
||||||
|
auth_header_(binary_to_list(AppId), binary_to_list(AppSecret)).
|
||||||
|
|
||||||
|
auth_header_(User, Pass) ->
|
||||||
|
Encoded = base64:encode_to_string(lists:append([User,":",Pass])),
|
||||||
|
{"Authorization","Basic " ++ Encoded}.
|
||||||
|
|
||||||
|
api_path(Parts)->
|
||||||
|
?HOST ++ filename:join([?BASE_PATH, ?API_VERSION] ++ Parts).
|
||||||
|
|
||||||
|
filter(List, Key, Value) ->
|
||||||
|
lists:filter(fun(Item) ->
|
||||||
|
maps:get(Key, Item) == Value
|
||||||
|
end, List).
|
||||||
|
|
Loading…
Reference in New Issue