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).
|
-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).
|
-define(DEFAULT_SAMPLE_INTERVAL, 10).
|
||||||
|
-endif.
|
||||||
|
|
||||||
-define(DELTA_SAMPLER_LIST,
|
-define(DELTA_SAMPLER_LIST,
|
||||||
[ received
|
[ received
|
||||||
|
|
|
@ -40,26 +40,14 @@
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% for rpc
|
%% for rpc
|
||||||
-export([ do_samples/1]).
|
-export([ do_sample/1]).
|
||||||
|
|
||||||
-define(TAB, ?MODULE).
|
-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
|
%% 1 hour = 60 * 60 * 1000 milliseconds
|
||||||
-define(CLEAN_EXPIRED_INTERVAL, 60 * 60 * 1000).
|
-define(CLEAN_EXPIRED_INTERVAL, 60 * 60 * 1000).
|
||||||
%% 7 days = 7 * 24 * 60 * 60 * 1000 milliseconds
|
%% 7 days = 7 * 24 * 60 * 60 * 1000 milliseconds
|
||||||
-define(RETENTION_TIME, 7 * 24 * 60 * 60 * 1000).
|
-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, {
|
-record(state, {
|
||||||
last
|
last
|
||||||
|
@ -82,7 +70,7 @@ samplers() ->
|
||||||
samplers(all).
|
samplers(all).
|
||||||
|
|
||||||
samplers(NodeOrCluster) ->
|
samplers(NodeOrCluster) ->
|
||||||
format(do_samples(NodeOrCluster)).
|
format(do_sample(NodeOrCluster)).
|
||||||
|
|
||||||
samplers(NodeOrCluster, 0) ->
|
samplers(NodeOrCluster, 0) ->
|
||||||
samplers(NodeOrCluster);
|
samplers(NodeOrCluster);
|
||||||
|
@ -141,10 +129,10 @@ code_change(_OldVsn, State = #state{}, _Extra) ->
|
||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
|
||||||
do_samples(all) ->
|
do_sample(all) ->
|
||||||
Fun =
|
Fun =
|
||||||
fun(Node, All) ->
|
fun(Node, All) ->
|
||||||
case do_samples(Node) of
|
case do_sample(Node) of
|
||||||
{badrpc, Reason} ->
|
{badrpc, Reason} ->
|
||||||
{badrpc, {Node, Reason}};
|
{badrpc, {Node, Reason}};
|
||||||
NodeSamplers ->
|
NodeSamplers ->
|
||||||
|
@ -152,9 +140,10 @@ do_samples(all) ->
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
lists:foldl(Fun, #{}, mria_mnesia:cluster_nodes(running));
|
lists:foldl(Fun, #{}, mria_mnesia:cluster_nodes(running));
|
||||||
do_samples(Node) when Node == node() ->
|
do_sample(Node) when Node == node() ->
|
||||||
get_data(?DEFAULT_GET_DATA_TIME);
|
ExpiredMS = [{'$1',[],['$1']}],
|
||||||
do_samples(Node) ->
|
internal_format(ets:select(?TAB, ExpiredMS));
|
||||||
|
do_sample(Node) ->
|
||||||
rpc:call(Node, ?MODULE, ?FUNCTION_NAME, [Node], 5000).
|
rpc:call(Node, ?MODULE, ?FUNCTION_NAME, [Node], 5000).
|
||||||
|
|
||||||
merge_cluster_samplers(Node, Cluster) ->
|
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 ...
|
%% 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
|
%% Ensure that the monitor data of all nodes in the cluster are aligned in time
|
||||||
next_interval() ->
|
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),
|
Now = erlang:system_time(millisecond),
|
||||||
NextTime = ((Now div Interval) + 1) * Interval,
|
NextTime = ((Now div Interval) + 1) * Interval,
|
||||||
Remaining = NextTime - Now,
|
Remaining = NextTime - Now,
|
||||||
|
@ -232,11 +221,6 @@ clean() ->
|
||||||
end, Expired),
|
end, Expired),
|
||||||
ok.
|
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
|
%% To make it easier to do data aggregation
|
||||||
internal_format(List) when is_list(List) ->
|
internal_format(List) when is_list(List) ->
|
||||||
Fun =
|
Fun =
|
||||||
|
|
|
@ -18,15 +18,6 @@
|
||||||
|
|
||||||
-export([ monitor/2]).
|
-export([ monitor/2]).
|
||||||
|
|
||||||
-define(SAMPLERS,
|
|
||||||
[ connection
|
|
||||||
, route
|
|
||||||
, subscriptions
|
|
||||||
, received
|
|
||||||
, sent
|
|
||||||
, dropped
|
|
||||||
]).
|
|
||||||
|
|
||||||
api_spec() ->
|
api_spec() ->
|
||||||
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
|
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
|
||||||
|
|
||||||
|
@ -41,7 +32,7 @@ schema("/monitor") ->
|
||||||
get => #{
|
get => #{
|
||||||
description => <<"List monitor data.">>,
|
description => <<"List monitor data.">>,
|
||||||
parameters => [
|
parameters => [
|
||||||
{latest, hoconsc:mk(integer(), #{in => query, required => false, example => 1000})}
|
{latest, hoconsc:mk(integer(), #{in => query, nullable => true, example => 1000})}
|
||||||
],
|
],
|
||||||
responses => #{
|
responses => #{
|
||||||
200 => hoconsc:mk(hoconsc:array(hoconsc:ref(sampler)), #{}),
|
200 => hoconsc:mk(hoconsc:array(hoconsc:ref(sampler)), #{}),
|
||||||
|
@ -56,8 +47,8 @@ schema("/monitor/nodes/:node") ->
|
||||||
get => #{
|
get => #{
|
||||||
description => <<"List the monitor data on the node.">>,
|
description => <<"List the monitor data on the node.">>,
|
||||||
parameters => [
|
parameters => [
|
||||||
{node, hoconsc:mk(binary(), #{in => path, required => true, example => node()})},
|
{node, hoconsc:mk(binary(), #{in => path, nullable => false, example => node()})},
|
||||||
{latest, hoconsc:mk(integer(), #{in => query, required => false, example => 1000})}
|
{latest, hoconsc:mk(integer(), #{in => query, nullable => true, example => 1000})}
|
||||||
],
|
],
|
||||||
responses => #{
|
responses => #{
|
||||||
200 => hoconsc:mk(hoconsc:array(hoconsc:ref(sampler)), #{}),
|
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