fix(test): add monitor SUITE, TODO: API Test SUITE
This commit is contained in:
parent
fedfa6c653
commit
8c1c87a8d6
|
@ -39,8 +39,13 @@
|
|||
|
||||
-define(DASHBOARD_SHARD, emqx_dashboard_shard).
|
||||
|
||||
%% 10 seconds
|
||||
-ifdef(TEST).
|
||||
%% for test, 2s
|
||||
-define(DEFAULT_SAMPLE_INTERVAL, 1).
|
||||
-else.
|
||||
%% dashboard monitor do sample interval, default 10s
|
||||
-define(DEFAULT_SAMPLE_INTERVAL, 10).
|
||||
-endif.
|
||||
|
||||
-define(DELTA_SAMPLER_LIST,
|
||||
[ received
|
||||
|
|
|
@ -40,26 +40,14 @@
|
|||
]).
|
||||
|
||||
%% for rpc
|
||||
-export([ do_samples/1]).
|
||||
-export([ do_sample/1]).
|
||||
|
||||
-define(TAB, ?MODULE).
|
||||
|
||||
-ifdef(TEST).
|
||||
%% for test
|
||||
-define(CLEAN_EXPIRED_INTERVAL, 2 * 1000).
|
||||
-define(RETENTION_TIME, 3 * 1000).
|
||||
-define(DEFAULT_GET_DATA_TIME, 5* 1000).
|
||||
|
||||
-else.
|
||||
|
||||
%% 1 hour = 60 * 60 * 1000 milliseconds
|
||||
-define(CLEAN_EXPIRED_INTERVAL, 60 * 60 * 1000).
|
||||
%% 7 days = 7 * 24 * 60 * 60 * 1000 milliseconds
|
||||
-define(RETENTION_TIME, 7 * 24 * 60 * 60 * 1000).
|
||||
%% 1 day = 60 * 60 * 1000 milliseconds
|
||||
-define(DEFAULT_GET_DATA_TIME, 60 * 60 * 1000).
|
||||
|
||||
-endif.
|
||||
|
||||
-record(state, {
|
||||
last
|
||||
|
@ -82,7 +70,7 @@ samplers() ->
|
|||
samplers(all).
|
||||
|
||||
samplers(NodeOrCluster) ->
|
||||
format(do_samples(NodeOrCluster)).
|
||||
format(do_sample(NodeOrCluster)).
|
||||
|
||||
samplers(NodeOrCluster, 0) ->
|
||||
samplers(NodeOrCluster);
|
||||
|
@ -141,10 +129,10 @@ code_change(_OldVsn, State = #state{}, _Extra) ->
|
|||
%%% Internal functions
|
||||
%%%===================================================================
|
||||
|
||||
do_samples(all) ->
|
||||
do_sample(all) ->
|
||||
Fun =
|
||||
fun(Node, All) ->
|
||||
case do_samples(Node) of
|
||||
case do_sample(Node) of
|
||||
{badrpc, Reason} ->
|
||||
{badrpc, {Node, Reason}};
|
||||
NodeSamplers ->
|
||||
|
@ -152,9 +140,10 @@ do_samples(all) ->
|
|||
end
|
||||
end,
|
||||
lists:foldl(Fun, #{}, mria_mnesia:cluster_nodes(running));
|
||||
do_samples(Node) when Node == node() ->
|
||||
get_data(?DEFAULT_GET_DATA_TIME);
|
||||
do_samples(Node) ->
|
||||
do_sample(Node) when Node == node() ->
|
||||
ExpiredMS = [{'$1',[],['$1']}],
|
||||
internal_format(ets:select(?TAB, ExpiredMS));
|
||||
do_sample(Node) ->
|
||||
rpc:call(Node, ?MODULE, ?FUNCTION_NAME, [Node], 5000).
|
||||
|
||||
merge_cluster_samplers(Node, Cluster) ->
|
||||
|
@ -191,7 +180,7 @@ clean_timer() ->
|
|||
%% The monitor will start working at full seconds, as like 00:00:00, 00:00:10, 00:00:20 ...
|
||||
%% Ensure that the monitor data of all nodes in the cluster are aligned in time
|
||||
next_interval() ->
|
||||
Interval = emqx_conf:get([dashboard, monitor, interval], ?DEFAULT_SAMPLE_INTERVAL) * 1000,
|
||||
Interval = emqx_conf:get([dashboard, sample_interval], ?DEFAULT_SAMPLE_INTERVAL) * 1000,
|
||||
Now = erlang:system_time(millisecond),
|
||||
NextTime = ((Now div Interval) + 1) * Interval,
|
||||
Remaining = NextTime - Now,
|
||||
|
@ -232,11 +221,6 @@ clean() ->
|
|||
end, Expired),
|
||||
ok.
|
||||
|
||||
get_data(PastTime) ->
|
||||
Now = erlang:system_time(millisecond),
|
||||
ExpiredMS = [{{'_', '$1', '_'}, [{'<', {'-', Now, '$1'}, PastTime}], ['$_']}],
|
||||
internal_format(ets:select(?TAB, ExpiredMS)).
|
||||
|
||||
%% To make it easier to do data aggregation
|
||||
internal_format(List) when is_list(List) ->
|
||||
Fun =
|
||||
|
|
|
@ -18,15 +18,6 @@
|
|||
|
||||
-export([ monitor/2]).
|
||||
|
||||
-define(SAMPLERS,
|
||||
[ connection
|
||||
, route
|
||||
, subscriptions
|
||||
, received
|
||||
, sent
|
||||
, dropped
|
||||
]).
|
||||
|
||||
api_spec() ->
|
||||
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
|
||||
|
||||
|
@ -41,7 +32,7 @@ schema("/monitor") ->
|
|||
get => #{
|
||||
description => <<"List monitor data.">>,
|
||||
parameters => [
|
||||
{latest, hoconsc:mk(integer(), #{in => query, required => false, example => 1000})}
|
||||
{latest, hoconsc:mk(integer(), #{in => query, nullable => true, example => 1000})}
|
||||
],
|
||||
responses => #{
|
||||
200 => hoconsc:mk(hoconsc:array(hoconsc:ref(sampler)), #{}),
|
||||
|
@ -56,8 +47,8 @@ schema("/monitor/nodes/:node") ->
|
|||
get => #{
|
||||
description => <<"List the monitor data on the node.">>,
|
||||
parameters => [
|
||||
{node, hoconsc:mk(binary(), #{in => path, required => true, example => node()})},
|
||||
{latest, hoconsc:mk(integer(), #{in => query, required => false, example => 1000})}
|
||||
{node, hoconsc:mk(binary(), #{in => path, nullable => false, example => node()})},
|
||||
{latest, hoconsc:mk(integer(), #{in => query, nullable => true, example => 1000})}
|
||||
],
|
||||
responses => #{
|
||||
200 => hoconsc:mk(hoconsc:array(hoconsc:ref(sampler)), #{}),
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_dashboard_monitor_SUITE).
|
||||
|
||||
-compile(nowarn_export_all).
|
||||
-compile(export_all).
|
||||
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
-include_lib("common_test/include/ct.hrl").
|
||||
-include_lib("emqx/include/emqx.hrl").
|
||||
-include("emqx_dashboard.hrl").
|
||||
|
||||
-define(SERVER, "http://127.0.0.1:18083").
|
||||
-define(BASE_PATH, "/api/v5").
|
||||
|
||||
all() ->
|
||||
emqx_common_test_helpers:all(?MODULE).
|
||||
|
||||
init_per_suite(Config) ->
|
||||
mria:start(),
|
||||
emqx_common_test_helpers:start_apps([emqx_dashboard], fun set_special_configs/1),
|
||||
Config.
|
||||
|
||||
end_per_suite(Config) ->
|
||||
emqx_common_test_helpers:stop_apps([emqx_dashboard]),
|
||||
Config.
|
||||
|
||||
set_special_configs(emqx_dashboard) ->
|
||||
Config = #{
|
||||
default_username => <<"admin">>,
|
||||
default_password => <<"public">>,
|
||||
listeners => [#{
|
||||
protocol => http,
|
||||
port => 18083
|
||||
}]
|
||||
},
|
||||
emqx_config:put([dashboard], Config),
|
||||
ok;
|
||||
set_special_configs(_) ->
|
||||
ok.
|
||||
|
||||
t_monitor_samplers_all(_Config) ->
|
||||
timer:sleep(?DEFAULT_SAMPLE_INTERVAL * 2 * 1000 + 20),
|
||||
Size = mnesia:table_info(emqx_dashboard_monitor,size),
|
||||
All = emqx_dashboard_monitor:samplers(all),
|
||||
All2 = emqx_dashboard_monitor:samplers(),
|
||||
?assert(erlang:length(All) == Size),
|
||||
?assert(erlang:length(All2) == Size),
|
||||
ok.
|
||||
|
||||
t_monitor_samplers_latest(_Config) ->
|
||||
timer:sleep(?DEFAULT_SAMPLE_INTERVAL * 2 * 1000 + 20),
|
||||
Samplers = emqx_dashboard_monitor:samplers(node(), 2),
|
||||
Latest = emqx_dashboard_monitor:samplers(node(), 1),
|
||||
?assert(erlang:length(Samplers) == 2),
|
||||
?assert(erlang:length(Latest) == 1),
|
||||
?assert(hd(Latest) == lists:nth(2, Samplers)),
|
||||
ok.
|
||||
|
||||
t_monitor_sampler_format(_Config) ->
|
||||
timer:sleep(?DEFAULT_SAMPLE_INTERVAL * 2 * 1000 + 20),
|
||||
Latest = hd(emqx_dashboard_monitor:samplers(node(), 1)),
|
||||
SamplerKeys = maps:keys(Latest),
|
||||
[?assert(lists:member(SamplerName, SamplerKeys)) || SamplerName <- ?SAMPLER_LIST],
|
||||
ok.
|
||||
|
||||
%% TODO: api test
|
||||
% t_monitor_api(_) ->
|
||||
% timer:sleep(?DEFAULT_SAMPLE_INTERVAL * 2 * 1000 + 20),
|
||||
% {ok, Samplers} = request(["monitor"]),
|
||||
% ?assert(erlang:length(Samplers) >= 2),
|
||||
% Sample = hd(Samplers),
|
||||
% Fun =
|
||||
% fun(Sampler) ->
|
||||
% Keys = [binary_to_atom(Key, utf8) || Key <- maps:keys(Sampler)],
|
||||
% [?assert(lists:member(SamplerName, Keys)) || SamplerName<- ?SAMPLER_LIST]
|
||||
% end,
|
||||
% [Fun(Sampler) || Sampler <- Samplers],
|
||||
% ok.
|
||||
|
||||
% t_monitor_api_error(_) ->
|
||||
% {error, _Reason} = request(["monitor_a"]),
|
||||
% ok.
|
||||
|
||||
% request(Path) ->
|
||||
% request(Path, "").
|
||||
|
||||
% request(Path, QS) ->
|
||||
% Url = url(Path, QS),
|
||||
% case do_request_api(get, {Path, auth_header_()}) of
|
||||
% {ok, Apps} -> {ok, emqx_json:decode(Apps, [return_maps])};
|
||||
% Error -> Error
|
||||
% end.
|
||||
|
||||
% url(Parts, QS)->
|
||||
% case QS of
|
||||
% "" ->
|
||||
% ?SERVER ++ filename:join([?BASE_PATH | Parts]);
|
||||
% _ ->
|
||||
% ?SERVER ++ filename:join([?BASE_PATH | Parts]) ++ "?" ++ QS
|
||||
% end.
|
||||
|
||||
% do_request_api(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 andalso Code =< 299 ->
|
||||
% {ok, emqx_json:decode(Return)};
|
||||
% {ok, Resp} ->
|
||||
% {error, Resp}
|
||||
% end.
|
||||
|
||||
% auth_header_() ->
|
||||
% Basic = binary_to_list(base64:encode(<<"admin:public">>)),
|
||||
% {"Authorization", "Basic " ++ Basic}.
|
|
@ -1,40 +0,0 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-module(emqx_dashboard_monitor_api_SUITE).
|
||||
|
||||
-compile(nowarn_export_all).
|
||||
-compile(export_all).
|
||||
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
-include_lib("common_test/include/ct.hrl").
|
||||
-include_lib("emqx/include/emqx.hrl").
|
||||
-include("emqx_dashboard.hrl").
|
||||
|
||||
all() ->
|
||||
emqx_common_test_helpers:all(?MODULE).
|
||||
|
||||
init_per_testcase(_, Config) ->
|
||||
Config.
|
||||
|
||||
end_per_testcase(_, _Config) ->
|
||||
ok.
|
||||
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Internal functions
|
||||
%%------------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue