rabbitmq-server/test/metrics_SUITE.erl

377 lines
16 KiB
Erlang

%% The contents of this file are subject to the Mozilla Public License
%% Version 1.1 (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.mozilla.org/MPL/
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and
%% limitations under the License.
%%
%% The Original Code is RabbitMQ.
%%
%% The Initial Developer of the Original Code is GoPivotal, Inc.
%% Copyright (c) 2016 Pivotal Software, Inc. All rights reserved.
%%
-module(metrics_SUITE).
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
-include_lib("proper/include/proper.hrl").
-include_lib("eunit/include/eunit.hrl").
-include_lib("amqp_client/include/amqp_client.hrl").
all() ->
[
{group, non_parallel_tests}
].
groups() ->
[
{non_parallel_tests, [], [
connection,
channel,
channel_connection_close,
channel_queue_exchange_consumer_close_connection,
channel_queue_delete_queue,
connection_metric_count_test,
channel_metric_count_test,
queue_metric_count_test,
queue_metric_count_channel_per_queue_test,
connection_metric_idemp_test,
channel_metric_idemp_test,
queue_metric_idemp_test
]}
].
%% -------------------------------------------------------------------
%% Testsuite setup/teardown.
%% -------------------------------------------------------------------
merge_app_env(Config) ->
rabbit_ct_helpers:merge_app_env(Config,
{rabbit, [
{collect_statistics, fine},
{collect_statistics_interval, 500}
]}).
init_per_suite(Config) ->
rabbit_ct_helpers:log_environment(),
Config1 = rabbit_ct_helpers:set_config(Config, [
{rmq_nodename_suffix, ?MODULE}
]),
rabbit_ct_helpers:run_setup_steps(Config1,
[ fun merge_app_env/1 ] ++
rabbit_ct_broker_helpers:setup_steps()).
end_per_suite(Config) ->
rabbit_ct_helpers:run_teardown_steps(Config,
rabbit_ct_broker_helpers:teardown_steps()).
init_per_group(_, Config) ->
Config.
end_per_group(_, Config) ->
Config.
init_per_testcase(Testcase, Config) ->
rabbit_ct_helpers:testcase_started(Config, Testcase).
end_per_testcase(Testcase, Config) ->
rabbit_ct_helpers:testcase_finished(Config, Testcase).
%% -------------------------------------------------------------------
%% Testcases.
%% -------------------------------------------------------------------
% NB: node_stats tests are in the management_agent repo
connection_metric_count_test(Config) ->
rabbit_ct_proper_helpers:run_proper(fun prop_connection_metric_count/1, [Config], 25).
channel_metric_count_test(Config) ->
rabbit_ct_proper_helpers:run_proper(fun prop_channel_metric_count/1, [Config], 25).
queue_metric_count_test(Config) ->
rabbit_ct_proper_helpers:run_proper(fun prop_queue_metric_count/1, [Config], 5).
queue_metric_count_channel_per_queue_test(Config) ->
rabbit_ct_proper_helpers:run_proper(fun prop_queue_metric_count_channel_per_queue/1,
[Config], 5).
connection_metric_idemp_test(Config) ->
rabbit_ct_proper_helpers:run_proper(fun prop_connection_metric_idemp/1, [Config], 25).
channel_metric_idemp_test(Config) ->
rabbit_ct_proper_helpers:run_proper(fun prop_channel_metric_idemp/1, [Config], 25).
queue_metric_idemp_test(Config) ->
rabbit_ct_proper_helpers:run_proper(fun prop_queue_metric_idemp/1, [Config], 25).
prop_connection_metric_idemp(Config) ->
?FORALL(N, {integer(1, 25), integer(1, 25)},
connection_metric_idemp(Config, N)).
prop_channel_metric_idemp(Config) ->
?FORALL(N, {integer(1, 25), integer(1, 25)},
channel_metric_idemp(Config, N)).
prop_queue_metric_idemp(Config) ->
?FORALL(N, {integer(1, 25), integer(1, 25)},
queue_metric_idemp(Config, N)).
prop_connection_metric_count(Config) ->
?FORALL(N, {integer(1, 25), resize(100, list(oneof([add, remove])))},
connection_metric_count(Config, N)).
prop_channel_metric_count(Config) ->
?FORALL(N, {integer(1, 25), resize(100, list(oneof([add, remove])))},
channel_metric_count(Config, N)).
prop_queue_metric_count(Config) ->
?FORALL(N, {integer(1, 10), resize(10, list(oneof([add, remove])))},
queue_metric_count(Config, N)).
prop_queue_metric_count_channel_per_queue(Config) ->
?FORALL(N, {integer(1, 10), resize(10, list(oneof([add, remove])))},
queue_metric_count_channel_per_queue(Config, N)).
connection_metric_idemp(Config, {N, R}) ->
Conns = [rabbit_ct_client_helpers:open_unmanaged_connection(Config)
|| _ <- lists:seq(1, N)],
Table = [ Pid || {Pid, _} <- read_table_rpc(Config, connection_metrics)],
Table2 = [ Pid || {Pid, _} <- read_table_rpc(Config, connection_coarse_metrics)],
% referesh stats 'R' times
[[Pid ! emit_stats || Pid <- Table] || _ <- lists:seq(1, R)],
timer:sleep(100),
TableAfter = [ Pid || {Pid, _} <- read_table_rpc(Config, connection_metrics)],
TableAfter2 = [ Pid || {Pid, _} <- read_table_rpc(Config, connection_coarse_metrics)],
[rabbit_ct_client_helpers:close_connection(Conn) || Conn <- Conns],
(Table2 == TableAfter2) and (Table == TableAfter) and
(N == length(Table)) and (N == length(TableAfter)).
channel_metric_idemp(Config, {N, R}) ->
Conn = rabbit_ct_client_helpers:open_unmanaged_connection(Config),
[amqp_connection:open_channel(Conn) || _ <- lists:seq(1, N)],
Table = [ Pid || {Pid, _} <- read_table_rpc(Config, channel_metrics)],
Table2 = [ Pid || {Pid, _} <- read_table_rpc(Config, channel_process_metrics)],
% referesh stats 'R' times
[[Pid ! emit_stats || Pid <- Table] || _ <- lists:seq(1, R)],
timer:sleep(100),
TableAfter = [ Pid || {Pid, _} <- read_table_rpc(Config, channel_metrics)],
TableAfter2 = [ Pid || {Pid, _} <- read_table_rpc(Config, channel_process_metrics)],
rabbit_ct_client_helpers:close_connection(Conn),
(Table2 == TableAfter2) and (Table == TableAfter) and
(N == length(Table)) and (N == length(TableAfter)).
queue_metric_idemp(Config, {N, R}) ->
Conn = rabbit_ct_client_helpers:open_unmanaged_connection(Config),
{ok, Chan} = amqp_connection:open_channel(Conn),
Queues =
[begin
Queue = declare_queue(Chan),
ensure_exchange_metrics_populated(Chan, Queue),
ensure_channel_queue_metrics_populated(Chan, Queue),
Queue
end || _ <- lists:seq(1, N)],
Table = [ Pid || {Pid, _} <- read_table_rpc(Config, queue_metrics)],
Table2 = [ Pid || {Pid, _} <- read_table_rpc(Config, queue_coarse_metrics)],
% referesh stats 'R' times
ChanTable = read_table_rpc(Config, channel_created),
[[Pid ! emit_stats || {Pid, _} <- ChanTable ] || _ <- lists:seq(1, R)],
timer:sleep(100),
TableAfter = [ Pid || {Pid, _} <- read_table_rpc(Config, queue_metrics)],
TableAfter2 = [ Pid || {Pid, _} <- read_table_rpc(Config, queue_coarse_metrics)],
[ delete_queue(Chan, Q) || Q <- Queues],
rabbit_ct_client_helpers:close_connection(Conn),
(Table2 == TableAfter2) and (Table == TableAfter) and
(N == length(Table)) and (N == length(TableAfter)).
connection_metric_count(Config, Ops) ->
add_rem_counter(Config, Ops,
{fun rabbit_ct_client_helpers:open_unmanaged_connection/1,
fun rabbit_ct_client_helpers:close_connection/1},
[ connection_created,
connection_metrics,
connection_coarse_metrics ]).
channel_metric_count(Config, Ops) ->
Conn = rabbit_ct_client_helpers:open_unmanaged_connection(Config),
Result = add_rem_counter(Config, Ops,
{fun (_Config) ->
{ok, Chan} = amqp_connection:open_channel(Conn),
Chan
end,
fun amqp_channel:close/1},
[ channel_created,
channel_metrics,
channel_process_metrics ]),
ok = rabbit_ct_client_helpers:close_connection(Conn),
Result.
queue_metric_count(Config, Ops) ->
Conn = rabbit_ct_client_helpers:open_unmanaged_connection(Config),
{ok, Chan} = amqp_connection:open_channel(Conn),
AddFun = fun (_) ->
Queue = declare_queue(Chan),
ensure_exchange_metrics_populated(Chan, Queue),
ensure_channel_queue_metrics_populated(Chan, Queue),
force_channel_stats(Config),
Queue
end,
Result = add_rem_counter(Config, Ops,
{AddFun,
fun (Q) -> delete_queue(Chan, Q) end},
[ channel_queue_metrics,
channel_queue_exchange_metrics ]),
ok = rabbit_ct_client_helpers:close_connection(Conn),
Result.
queue_metric_count_channel_per_queue(Config, Ops) ->
Conn = rabbit_ct_client_helpers:open_unmanaged_connection(Config),
AddFun = fun (_) ->
{ok, Chan} = amqp_connection:open_channel(Conn),
Queue = declare_queue(Chan),
ensure_exchange_metrics_populated(Chan, Queue),
ensure_channel_queue_metrics_populated(Chan, Queue),
force_channel_stats(Config),
{Chan, Queue}
end,
Result = add_rem_counter(Config, Ops,
{AddFun,
fun ({Chan, Q}) -> delete_queue(Chan, Q) end},
[ channel_queue_metrics,
channel_queue_exchange_metrics ]),
ok = rabbit_ct_client_helpers:close_connection(Conn),
Result.
add_rem_counter(Config, {Initial, Ops}, {AddFun, RemFun}, Tables) ->
Things = [ AddFun(Config) || _ <- lists:seq(1, Initial) ],
% either add or remove some things
{FinalLen, Things1} =
lists:foldl(fun(add, {L, Items}) ->
{L+1, [AddFun(Config) | Items]};
(remove, {L, [H|Tail]}) ->
RemFun(H),
{L-1, Tail};
(_, S) -> S end,
{Initial, Things},
Ops),
TabLens = lists:map(fun(T) ->
length(read_table_rpc(Config, T)) end, Tables),
[RemFun(Thing) || Thing <- Things1],
[FinalLen] == lists:usort(TabLens).
connection(Config) ->
Conn = rabbit_ct_client_helpers:open_unmanaged_connection(Config),
[_] = read_table_rpc(Config, connection_created),
[_] = read_table_rpc(Config, connection_metrics),
[_] = read_table_rpc(Config, connection_coarse_metrics),
ok = rabbit_ct_client_helpers:close_connection(Conn),
[] = read_table_rpc(Config, connection_created),
[] = read_table_rpc(Config, connection_metrics),
[] = read_table_rpc(Config, connection_coarse_metrics).
channel(Config) ->
Conn = rabbit_ct_client_helpers:open_unmanaged_connection(Config),
{ok, Chan} = amqp_connection:open_channel(Conn),
[_] = read_table_rpc(Config, channel_created),
[_] = read_table_rpc(Config, channel_metrics),
[_] = read_table_rpc(Config, channel_process_metrics),
ok = amqp_channel:close(Chan),
[] = read_table_rpc(Config, channel_created),
[] = read_table_rpc(Config, channel_metrics),
[] = read_table_rpc(Config, channel_process_metrics),
ok = rabbit_ct_client_helpers:close_connection(Conn).
channel_connection_close(Config) ->
Conn = rabbit_ct_client_helpers:open_unmanaged_connection(Config),
{ok, _} = amqp_connection:open_channel(Conn),
[_] = read_table_rpc(Config, channel_created),
[_] = read_table_rpc(Config, channel_metrics),
[_] = read_table_rpc(Config, channel_process_metrics),
ok = rabbit_ct_client_helpers:close_connection(Conn),
[] = read_table_rpc(Config, channel_created),
[] = read_table_rpc(Config, channel_metrics),
[] = read_table_rpc(Config, channel_process_metrics).
channel_queue_delete_queue(Config) ->
Conn = rabbit_ct_client_helpers:open_unmanaged_connection(Config),
{ok, Chan} = amqp_connection:open_channel(Conn),
Queue = declare_queue(Chan),
ensure_exchange_metrics_populated(Chan, Queue),
ensure_channel_queue_metrics_populated(Chan, Queue),
force_channel_stats(Config),
[_] = read_table_rpc(Config, channel_queue_metrics),
[_] = read_table_rpc(Config, channel_queue_exchange_metrics),
delete_queue(Chan, Queue),
% ensure removal of queue cleans up channel_queue metrics
[] = read_table_rpc(Config, channel_queue_exchange_metrics),
[] = read_table_rpc(Config, channel_queue_metrics),
ok = rabbit_ct_client_helpers:close_connection(Conn).
channel_queue_exchange_consumer_close_connection(Config) ->
Conn = rabbit_ct_client_helpers:open_unmanaged_connection(Config),
{ok, Chan} = amqp_connection:open_channel(Conn),
Queue = declare_queue(Chan),
ensure_exchange_metrics_populated(Chan, Queue),
force_channel_stats(Config),
[_] = read_table_rpc(Config, channel_exchange_metrics),
[_] = read_table_rpc(Config, channel_queue_exchange_metrics),
ensure_channel_queue_metrics_populated(Chan, Queue),
force_channel_stats(Config),
[_] = read_table_rpc(Config, channel_queue_metrics),
Sub = #'basic.consume'{queue = Queue},
#'basic.consume_ok'{consumer_tag = _} =
amqp_channel:call(Chan, Sub),
[_] = read_table_rpc(Config, consumer_created),
ok = rabbit_ct_client_helpers:close_connection(Conn),
% ensure cleanup happened
[] = read_table_rpc(Config, channel_exchange_metrics),
[] = read_table_rpc(Config, channel_queue_exchange_metrics),
[] = read_table_rpc(Config, channel_queue_metrics),
[] = read_table_rpc(Config, consumer_created).
%% -------------------------------------------------------------------
%% Utilities
%% -------------------------------------------------------------------
declare_queue(Chan) ->
Declare = #'queue.declare'{durable = false, auto_delete = true},
#'queue.declare_ok'{queue = Name} = amqp_channel:call(Chan, Declare),
Name.
delete_queue(Chan, Name) ->
Delete = #'queue.delete'{queue = Name},
#'queue.delete_ok'{} = amqp_channel:call(Chan, Delete).
ensure_exchange_metrics_populated(Chan, RoutingKey) ->
% need to publish for exchange metrics to be populated
Publish = #'basic.publish'{routing_key = RoutingKey},
amqp_channel:call(Chan, Publish, #amqp_msg{payload = <<"hello">>}).
ensure_channel_queue_metrics_populated(Chan, Queue) ->
% need to get and wait for timer for channel queue metrics to be populated
Get = #'basic.get'{queue = Queue, no_ack=true},
{#'basic.get_ok'{}, #amqp_msg{}} = amqp_channel:call(Chan, Get).
force_channel_stats(Config) ->
[ Pid ! emit_stats || {Pid, _} <- read_table_rpc(Config, channel_created) ],
timer:sleep(10).
read_table_rpc(Config, Table) ->
rabbit_ct_broker_helpers:rpc(Config, 0, ?MODULE, read_table, [Table]).
read_table(Table) ->
ets:tab2list(Table).