diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | src/truncate.erl | 75 | ||||
| -rw-r--r-- | test/credit_flow_SUITE.erl | 77 | ||||
| -rw-r--r-- | test/gm_SUITE.erl | 205 | ||||
| -rw-r--r-- | test/mirrored_supervisor_SUITE.erl | 335 | ||||
| -rw-r--r-- | test/mirrored_supervisor_SUITE_gs.erl | 66 | ||||
| -rw-r--r-- | test/msg_store_SUITE.erl | 62 | ||||
| -rw-r--r-- | test/password_hashing_SUITE.erl | 121 | ||||
| -rw-r--r-- | test/rabbit_ctl_timeout_SUITE.erl | 173 | ||||
| -rw-r--r-- | test/resource_monitor_SUITE.erl | 64 | ||||
| -rw-r--r-- | test/supervisor2_SUITE.erl | 90 | ||||
| -rw-r--r-- | test/truncate_SUITE.erl | 99 | ||||
| -rw-r--r-- | test/vm_memory_monitor_SUITE.erl | 42 |
14 files changed, 1342 insertions, 71 deletions
diff --git a/.gitignore b/.gitignore index 3e0b548789..720f17d9b6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .sw? .*.sw? *.beam +*.coverdata .erlang.mk/ cover/ debug/ @@ -11,6 +12,7 @@ ebin/ etc/ logs/ plugins/ +test/ct.cover.spec PACKAGES/ @@ -25,6 +25,8 @@ DEP_PLUGINS = rabbit_common/mk/rabbitmq-run.mk \ rabbit_common/mk/rabbitmq-dist.mk \ rabbit_common/mk/rabbitmq-tools.mk +CT_OPTS += -ct_hooks cth_surefire + # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be # reviewed and merged. diff --git a/src/truncate.erl b/src/truncate.erl index 1c9b08ed27..a1586b0cb0 100644 --- a/src/truncate.erl +++ b/src/truncate.erl @@ -21,8 +21,10 @@ -record(params, {content, struct, content_dec, struct_dec}). -export([log_event/2, term/2]). -%% exported for testing --export([test/0]). + +-ifdef(TEST). +-export([term_size/3]). +-endif. log_event({Type, GL, {Pid, Format, Args}}, Params) when Type =:= error orelse @@ -123,72 +125,3 @@ tuple_term_size(_T, M, I, S, _W) when I > S -> M; tuple_term_size(T, M, I, S, W) -> tuple_term_size(T, lim(term_size(element(I, T), M, W), 2 * W), I + 1, S, W). - -%%---------------------------------------------------------------------------- - -test() -> - test_short_examples_exactly(), - test_term_limit(), - test_large_examples_for_size(), - ok. - -test_short_examples_exactly() -> - F = fun (Term, Exp) -> - Exp = term(Term, {1, {10, 10, 5, 5}}), - Term = term(Term, {100000, {10, 10, 5, 5}}) - end, - FSmall = fun (Term, Exp) -> - Exp = term(Term, {1, {2, 2, 2, 2}}), - Term = term(Term, {100000, {2, 2, 2, 2}}) - end, - F([], []), - F("h", "h"), - F("hello world", "hello w..."), - F([[h,e,l,l,o,' ',w,o,r,l,d]], [[h,e,l,l,o,'...']]), - F([a|b], [a|b]), - F(<<"hello">>, <<"hello">>), - F([<<"hello world">>], [<<"he...">>]), - F(<<1:1>>, <<1:1>>), - F(<<1:81>>, <<0:56, "...">>), - F({{{{a}}},{b},c,d,e,f,g,h,i,j,k}, {{{'...'}},{b},c,d,e,f,g,h,i,j,'...'}), - FSmall({a,30,40,40,40,40}, {a,30,'...'}), - FSmall([a,30,40,40,40,40], [a,30,'...']), - P = spawn(fun() -> receive die -> ok end end), - F([0, 0.0, <<1:1>>, F, P], [0, 0.0, <<1:1>>, F, P]), - P ! die, - R = make_ref(), - F([R], [R]), - ok. - -test_term_limit() -> - W = erlang:system_info(wordsize), - S = <<"abc">>, - 1 = term_size(S, 4, W), - limit_exceeded = term_size(S, 3, W), - case 100 - term_size([S, S], 100, W) of - 22 -> ok; %% 32 bit - 38 -> ok %% 64 bit - end, - case 100 - term_size([S, [S]], 100, W) of - 30 -> ok; %% ditto - 54 -> ok - end, - limit_exceeded = term_size([S, S], 6, W), - ok. - -test_large_examples_for_size() -> - %% Real world values - Shrink = fun(Term) -> term(Term, {1, {1000, 100, 50, 5}}) end, - TestSize = fun(Term) -> - true = 5000000 < size(term_to_binary(Term)), - true = 500000 > size(term_to_binary(Shrink(Term))) - end, - TestSize(lists:seq(1, 5000000)), - TestSize(recursive_list(1000, 10)), - TestSize(recursive_list(5000, 20)), - TestSize(gb_sets:from_list([I || I <- lists:seq(1, 1000000)])), - TestSize(gb_trees:from_orddict([{I, I} || I <- lists:seq(1, 1000000)])), - ok. - -recursive_list(S, 0) -> lists:seq(1, S); -recursive_list(S, N) -> [recursive_list(S div N, N-1) || _ <- lists:seq(1, S)]. diff --git a/test/credit_flow_SUITE.erl b/test/credit_flow_SUITE.erl new file mode 100644 index 0000000000..5747f8c8d8 --- /dev/null +++ b/test/credit_flow_SUITE.erl @@ -0,0 +1,77 @@ +%% 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) 2011-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(credit_flow_SUITE). + +-include_lib("common_test/include/ct.hrl"). + +-compile(export_all). + +all() -> + [ + credit_flow_settings + ]. + +%% ------------------------------------------------------------------- +%% Testsuite setup/teardown. +%% ------------------------------------------------------------------- + +init_per_suite(Config) -> + rabbit_ct_helpers:log_environment(), + rabbit_ct_helpers:run_setup_steps(?MODULE, Config). + +end_per_suite(Config) -> + rabbit_ct_helpers:run_teardown_steps(Config). + +%% --------------------------------------------------------------------------- +%% Test cases +%% --------------------------------------------------------------------------- + +credit_flow_settings(Config) -> + passed = rabbit_ct_broker_helpers:run_test_on_broker( + ?config(rmq_nodename, Config), + ?MODULE, credit_flow_settings1, [Config]). + +credit_flow_settings1(_Config) -> + %% default values + passed = test_proc(200, 50), + + application:set_env(rabbit, credit_flow_default_credit, {100, 20}), + passed = test_proc(100, 20), + + application:unset_env(rabbit, credit_flow_default_credit), + + % back to defaults + passed = test_proc(200, 50), + passed. + +test_proc(InitialCredit, MoreCreditAfter) -> + Pid = spawn(fun dummy/0), + Pid ! {credit, self()}, + {InitialCredit, MoreCreditAfter} = + receive + {credit, Val} -> Val + end, + passed. + +dummy() -> + credit_flow:send(self()), + receive + {credit, From} -> + From ! {credit, get(credit_flow_default_credit)}; + _ -> + dummy() + end. diff --git a/test/gm_SUITE.erl b/test/gm_SUITE.erl new file mode 100644 index 0000000000..f5ccf75b70 --- /dev/null +++ b/test/gm_SUITE.erl @@ -0,0 +1,205 @@ +%% 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) 2007-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(gm_SUITE). + +-behaviour(gm). + +-include_lib("common_test/include/ct.hrl"). + +-include("gm_specs.hrl"). + +-compile(export_all). + +-define(RECEIVE_OR_THROW(Body, Bool, Error), + receive Body -> + true = Bool, + passed + after 1000 -> + throw(Error) + end). + +all() -> + [ + join_leave, + broadcast, + confirmed_broadcast, + member_death, + receive_in_order + ]. + +init_per_suite(Config) -> + ok = application:set_env(mnesia, dir, ?config(priv_dir, Config)), + ok = application:start(mnesia), + {ok, FHC} = file_handle_cache:start_link(), + unlink(FHC), + {ok, WPS} = worker_pool_sup:start_link(), + unlink(WPS), + rabbit_ct_helpers:set_config(Config, [ + {file_handle_cache_pid, FHC}, + {worker_pool_sup_pid, WPS} + ]). + +end_per_suite(Config) -> + exit(?config(worker_pool_sup_pid, Config), shutdown), + exit(?config(file_handle_cache_pid, Config), shutdown), + ok = application:stop(mnesia), + Config. + +%% --------------------------------------------------------------------------- +%% Functional tests +%% --------------------------------------------------------------------------- + +join_leave(_Config) -> + passed = with_two_members(fun (_Pid, _Pid2) -> passed end). + +broadcast(_Config) -> + passed = do_broadcast(fun gm:broadcast/2). + +confirmed_broadcast(_Config) -> + passed = do_broadcast(fun gm:confirmed_broadcast/2). + +member_death(_Config) -> + passed = with_two_members( + fun (Pid, Pid2) -> + {ok, Pid3} = gm:start_link( + ?MODULE, ?MODULE, self(), + fun rabbit_misc:execute_mnesia_transaction/1), + passed = receive_joined(Pid3, [Pid, Pid2, Pid3], + timeout_joining_gm_group_3), + passed = receive_birth(Pid, Pid3, timeout_waiting_for_birth_3_1), + passed = receive_birth(Pid2, Pid3, timeout_waiting_for_birth_3_2), + + unlink(Pid3), + exit(Pid3, kill), + + %% Have to do some broadcasts to ensure that all members + %% find out about the death. + passed = (broadcast_fun(fun gm:confirmed_broadcast/2))( + Pid, Pid2), + + passed = receive_death(Pid, Pid3, timeout_waiting_for_death_3_1), + passed = receive_death(Pid2, Pid3, timeout_waiting_for_death_3_2), + + passed + end). + +receive_in_order(_Config) -> + passed = with_two_members( + fun (Pid, Pid2) -> + Numbers = lists:seq(1,1000), + [begin ok = gm:broadcast(Pid, N), ok = gm:broadcast(Pid2, N) end + || N <- Numbers], + passed = receive_numbers( + Pid, Pid, {timeout_for_msgs, Pid, Pid}, Numbers), + passed = receive_numbers( + Pid, Pid2, {timeout_for_msgs, Pid, Pid2}, Numbers), + passed = receive_numbers( + Pid2, Pid, {timeout_for_msgs, Pid2, Pid}, Numbers), + passed = receive_numbers( + Pid2, Pid2, {timeout_for_msgs, Pid2, Pid2}, Numbers), + passed + end). + +do_broadcast(Fun) -> + with_two_members(broadcast_fun(Fun)). + +broadcast_fun(Fun) -> + fun (Pid, Pid2) -> + ok = Fun(Pid, magic_message), + passed = receive_or_throw({msg, Pid, Pid, magic_message}, + timeout_waiting_for_msg), + passed = receive_or_throw({msg, Pid2, Pid, magic_message}, + timeout_waiting_for_msg) + end. + +with_two_members(Fun) -> + ok = gm:create_tables(), + + {ok, Pid} = gm:start_link(?MODULE, ?MODULE, self(), + fun rabbit_misc:execute_mnesia_transaction/1), + passed = receive_joined(Pid, [Pid], timeout_joining_gm_group_1), + + {ok, Pid2} = gm:start_link(?MODULE, ?MODULE, self(), + fun rabbit_misc:execute_mnesia_transaction/1), + passed = receive_joined(Pid2, [Pid, Pid2], timeout_joining_gm_group_2), + passed = receive_birth(Pid, Pid2, timeout_waiting_for_birth_2), + + passed = Fun(Pid, Pid2), + + ok = gm:leave(Pid), + passed = receive_death(Pid2, Pid, timeout_waiting_for_death_1), + passed = + receive_termination(Pid, normal, timeout_waiting_for_termination_1), + + ok = gm:leave(Pid2), + passed = + receive_termination(Pid2, normal, timeout_waiting_for_termination_2), + + receive X -> throw({unexpected_message, X}) + after 0 -> passed + end. + +receive_or_throw(Pattern, Error) -> + ?RECEIVE_OR_THROW(Pattern, true, Error). + +receive_birth(From, Born, Error) -> + ?RECEIVE_OR_THROW({members_changed, From, Birth, Death}, + ([Born] == Birth) andalso ([] == Death), + Error). + +receive_death(From, Died, Error) -> + ?RECEIVE_OR_THROW({members_changed, From, Birth, Death}, + ([] == Birth) andalso ([Died] == Death), + Error). + +receive_joined(From, Members, Error) -> + ?RECEIVE_OR_THROW({joined, From, Members1}, + lists:usort(Members) == lists:usort(Members1), + Error). + +receive_termination(From, Reason, Error) -> + ?RECEIVE_OR_THROW({termination, From, Reason1}, + Reason == Reason1, + Error). + +receive_numbers(_Pid, _Sender, _Error, []) -> + passed; +receive_numbers(Pid, Sender, Error, [N | Numbers]) -> + ?RECEIVE_OR_THROW({msg, Pid, Sender, M}, + M == N, + Error), + receive_numbers(Pid, Sender, Error, Numbers). + +%% ------------------------------------------------------------------- +%% gm behavior callbacks. +%% ------------------------------------------------------------------- + +joined(Pid, Members) -> + Pid ! {joined, self(), Members}, + ok. + +members_changed(Pid, Births, Deaths) -> + Pid ! {members_changed, self(), Births, Deaths}, + ok. + +handle_msg(Pid, From, Msg) -> + Pid ! {msg, self(), From, Msg}, + ok. + +handle_terminate(Pid, Reason) -> + Pid ! {termination, self(), Reason}, + ok. diff --git a/test/mirrored_supervisor_SUITE.erl b/test/mirrored_supervisor_SUITE.erl new file mode 100644 index 0000000000..5ed17c90bb --- /dev/null +++ b/test/mirrored_supervisor_SUITE.erl @@ -0,0 +1,335 @@ +%% 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) 2011-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(mirrored_supervisor_SUITE). + +-behaviour(mirrored_supervisor). + +-include_lib("common_test/include/ct.hrl"). + +-compile(export_all). + +-define(MS, mirrored_supervisor). +-define(SERVER, mirrored_supervisor_SUITE_gs). + +all() -> + [ + migrate, + migrate_twice, + already_there, + delete_restart, + which_children, + large_group, + childspecs_at_init, + anonymous_supervisors, + no_migration_on_shutdown, + start_idempotence, + unsupported, + ignore, + startup_failure + ]. + +init_per_suite(Config) -> + ok = application:set_env(mnesia, dir, ?config(priv_dir, Config)), + ok = application:start(mnesia), + lists:foreach( + fun ({Tab, TabDef}) -> + TabDef1 = proplists:delete(match, TabDef), + case mnesia:create_table(Tab, TabDef1) of + {atomic, ok} -> + ok; + {aborted, Reason} -> + throw({error, + {table_creation_failed, Tab, TabDef1, Reason}}) + end + end, mirrored_supervisor:table_definitions()), + Config. + +end_per_suite(Config) -> + ok = application:stop(mnesia), + Config. + +%% --------------------------------------------------------------------------- +%% Functional tests +%% --------------------------------------------------------------------------- + +%% Simplest test +migrate(_Config) -> + passed = with_sups( + fun([A, _]) -> + {ok, _} = ?MS:start_child(a, childspec(worker)), + Pid1 = pid_of(worker), + kill_registered(A, Pid1), + Pid2 = pid_of(worker), + false = (Pid1 =:= Pid2) + end, [a, b]). + +%% Is migration transitive? +migrate_twice(_Config) -> + passed = with_sups( + fun([A, B]) -> + {ok, _} = ?MS:start_child(a, childspec(worker)), + Pid1 = pid_of(worker), + kill_registered(A, Pid1), + {ok, C} = start_sup(c), + Pid2 = pid_of(worker), + kill_registered(B, Pid2), + Pid3 = pid_of(worker), + false = (Pid1 =:= Pid3), + kill(C) + end, [a, b]). + +%% Can't start the same child twice +already_there(_Config) -> + passed = with_sups( + fun([_, _]) -> + S = childspec(worker), + {ok, Pid} = ?MS:start_child(a, S), + {error, {already_started, Pid}} = ?MS:start_child(b, S) + end, [a, b]). + +%% Deleting and restarting should work as per a normal supervisor +delete_restart(_Config) -> + passed = with_sups( + fun([_, _]) -> + S = childspec(worker), + {ok, Pid1} = ?MS:start_child(a, S), + {error, running} = ?MS:delete_child(a, worker), + ok = ?MS:terminate_child(a, worker), + ok = ?MS:delete_child(a, worker), + {ok, Pid2} = ?MS:start_child(b, S), + false = (Pid1 =:= Pid2), + ok = ?MS:terminate_child(b, worker), + {ok, Pid3} = ?MS:restart_child(b, worker), + Pid3 = pid_of(worker), + false = (Pid2 =:= Pid3), + %% Not the same supervisor as the worker is on + ok = ?MS:terminate_child(a, worker), + ok = ?MS:delete_child(a, worker), + {ok, Pid4} = ?MS:start_child(a, S), + false = (Pid3 =:= Pid4) + end, [a, b]). + +which_children(_Config) -> + passed = with_sups( + fun([A, B] = Both) -> + ?MS:start_child(A, childspec(worker)), + assert_wc(Both, fun ([C]) -> true = is_pid(wc_pid(C)) end), + ok = ?MS:terminate_child(a, worker), + assert_wc(Both, fun ([C]) -> undefined = wc_pid(C) end), + {ok, _} = ?MS:restart_child(a, worker), + assert_wc(Both, fun ([C]) -> true = is_pid(wc_pid(C)) end), + ?MS:start_child(B, childspec(worker2)), + assert_wc(Both, fun (C) -> 2 = length(C) end) + end, [a, b]). + +assert_wc(Sups, Fun) -> + [Fun(?MS:which_children(Sup)) || Sup <- Sups]. + +wc_pid(Child) -> + {worker, Pid, worker, [?MODULE]} = Child, + Pid. + +%% Not all the members of the group should actually do the failover +large_group(_Config) -> + passed = with_sups( + fun([A, _, _, _]) -> + {ok, _} = ?MS:start_child(a, childspec(worker)), + Pid1 = pid_of(worker), + kill_registered(A, Pid1), + Pid2 = pid_of(worker), + false = (Pid1 =:= Pid2) + end, [a, b, c, d]). + +%% Do childspecs work when returned from init? +childspecs_at_init(_Config) -> + S = childspec(worker), + passed = with_sups( + fun([A, _]) -> + Pid1 = pid_of(worker), + kill_registered(A, Pid1), + Pid2 = pid_of(worker), + false = (Pid1 =:= Pid2) + end, [{a, [S]}, {b, [S]}]). + +anonymous_supervisors(_Config) -> + passed = with_sups( + fun([A, _B]) -> + {ok, _} = ?MS:start_child(A, childspec(worker)), + Pid1 = pid_of(worker), + kill_registered(A, Pid1), + Pid2 = pid_of(worker), + false = (Pid1 =:= Pid2) + end, [anon, anon]). + +%% When a mirrored_supervisor terminates, we should not migrate, but +%% the whole supervisor group should shut down. To test this we set up +%% a situation where the gen_server will only fail if it's running +%% under the supervisor called 'evil'. It should not migrate to +%% 'good' and survive, rather the whole group should go away. +no_migration_on_shutdown(_Config) -> + passed = with_sups( + fun([Evil, _]) -> + {ok, _} = ?MS:start_child(Evil, childspec(worker)), + try + call(worker, ping, 1000, 100), + exit(worker_should_not_have_migrated) + catch exit:{timeout_waiting_for_server, _, _} -> + ok + end + end, [evil, good]). + +start_idempotence(_Config) -> + passed = with_sups( + fun([_]) -> + CS = childspec(worker), + {ok, Pid} = ?MS:start_child(a, CS), + {error, {already_started, Pid}} = ?MS:start_child(a, CS), + ?MS:terminate_child(a, worker), + {error, already_present} = ?MS:start_child(a, CS) + end, [a]). + +unsupported(_Config) -> + try + ?MS:start_link({global, foo}, get_group(group), fun tx_fun/1, ?MODULE, + {one_for_one, []}), + exit(no_global) + catch error:badarg -> + ok + end, + try + {ok, _} = ?MS:start_link({local, foo}, get_group(group), + fun tx_fun/1, ?MODULE, {simple_one_for_one, []}), + exit(no_sofo) + catch error:badarg -> + ok + end. + +%% Just test we don't blow up +ignore(_Config) -> + ?MS:start_link({local, foo}, get_group(group), fun tx_fun/1, ?MODULE, + {fake_strategy_for_ignore, []}). + +startup_failure(_Config) -> + [test_startup_failure(F) || F <- [want_error, want_exit]]. + +test_startup_failure(Fail) -> + process_flag(trap_exit, true), + ?MS:start_link(get_group(group), fun tx_fun/1, ?MODULE, + {one_for_one, [childspec(Fail)]}), + receive + {'EXIT', _, shutdown} -> + ok + after 1000 -> + exit({did_not_exit, Fail}) + end, + process_flag(trap_exit, false). + +%% --------------------------------------------------------------------------- + +with_sups(Fun, Sups) -> + inc_group(), + Pids = [begin {ok, Pid} = start_sup(Sup), Pid end || Sup <- Sups], + Fun(Pids), + [kill(Pid) || Pid <- Pids, is_process_alive(Pid)], + timer:sleep(500), + passed. + +start_sup(Spec) -> + start_sup(Spec, group). + +start_sup({Name, ChildSpecs}, Group) -> + {ok, Pid} = start_sup0(Name, get_group(Group), ChildSpecs), + %% We are not a supervisor, when we kill the supervisor we do not + %% want to die! + unlink(Pid), + {ok, Pid}; + +start_sup(Name, Group) -> + start_sup({Name, []}, Group). + +start_sup0(anon, Group, ChildSpecs) -> + ?MS:start_link(Group, fun tx_fun/1, ?MODULE, + {one_for_one, ChildSpecs}); + +start_sup0(Name, Group, ChildSpecs) -> + ?MS:start_link({local, Name}, Group, fun tx_fun/1, ?MODULE, + {one_for_one, ChildSpecs}). + +childspec(Id) -> + {Id,{?SERVER, start_link, [Id]}, transient, 16#ffffffff, worker, [?MODULE]}. + +pid_of(Id) -> + {received, Pid, ping} = call(Id, ping), + Pid. + +tx_fun(Fun) -> + case mnesia:sync_transaction(Fun) of + {atomic, Result} -> Result; + {aborted, Reason} -> throw({error, Reason}) + end. + +inc_group() -> + Count = case get(counter) of + undefined -> 0; + C -> C + end + 1, + put(counter, Count). + +get_group(Group) -> + {Group, get(counter)}. + +call(Id, Msg) -> call(Id, Msg, 10*1000, 100). + +call(Id, Msg, 0, _Decr) -> + exit({timeout_waiting_for_server, {Id, Msg}, erlang:get_stacktrace()}); + +call(Id, Msg, MaxDelay, Decr) -> + try + gen_server:call(Id, Msg, infinity) + catch exit:_ -> timer:sleep(Decr), + call(Id, Msg, MaxDelay - Decr, Decr) + end. + +kill(Pid) -> kill(Pid, []). +kill(Pid, Wait) when is_pid(Wait) -> kill(Pid, [Wait]); +kill(Pid, Waits) -> + erlang:monitor(process, Pid), + [erlang:monitor(process, P) || P <- Waits], + exit(Pid, bang), + kill_wait(Pid), + [kill_wait(P) || P <- Waits]. + +kill_registered(Pid, Child) -> + {registered_name, Name} = erlang:process_info(Child, registered_name), + kill(Pid, Child), + false = (Child =:= whereis(Name)), + ok. + +kill_wait(Pid) -> + receive + {'DOWN', _Ref, process, Pid, _Reason} -> + ok + end. + +%% --------------------------------------------------------------------------- + +init({fake_strategy_for_ignore, _ChildSpecs}) -> + ignore; + +init({Strategy, ChildSpecs}) -> + {ok, {{Strategy, 0, 1}, ChildSpecs}}. + diff --git a/test/mirrored_supervisor_SUITE_gs.erl b/test/mirrored_supervisor_SUITE_gs.erl new file mode 100644 index 0000000000..867754b4a2 --- /dev/null +++ b/test/mirrored_supervisor_SUITE_gs.erl @@ -0,0 +1,66 @@ +%% 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) 2011-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(mirrored_supervisor_SUITE_gs). + +%% Dumb gen_server we can supervise + +-export([start_link/1]). + +-export([init/1, handle_call/3, handle_info/2, terminate/2, code_change/3, + handle_cast/2]). + +-behaviour(gen_server). + +-define(MS, mirrored_supervisor). + +start_link(want_error) -> + {error, foo}; + +start_link(want_exit) -> + exit(foo); + +start_link(Id) -> + gen_server:start_link({local, Id}, ?MODULE, [], []). + +%% --------------------------------------------------------------------------- + +init([]) -> + {ok, state}. + +handle_call(Msg, _From, State) -> + die_if_my_supervisor_is_evil(), + {reply, {received, self(), Msg}, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +die_if_my_supervisor_is_evil() -> + try lists:keysearch(self(), 2, ?MS:which_children(evil)) of + false -> ok; + _ -> exit(doooom) + catch + exit:{noproc, _} -> ok + end. diff --git a/test/msg_store_SUITE.erl b/test/msg_store_SUITE.erl new file mode 100644 index 0000000000..f63f6cb745 --- /dev/null +++ b/test/msg_store_SUITE.erl @@ -0,0 +1,62 @@ +%% 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) 2011-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(msg_store_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("rabbit_common/include/rabbit.hrl"). + +-compile(export_all). + +-define(T(Fun, Args), (catch apply(rabbit, Fun, Args))). + +all() -> + [ + parameter_validation + ]. + +parameter_validation(_Config) -> + %% make sure it works with default values + ok = ?T(validate_msg_store_io_batch_size_and_credit_disc_bound, + [?CREDIT_DISC_BOUND, ?IO_BATCH_SIZE]), + + %% IO_BATCH_SIZE must be greater than CREDIT_DISC_BOUND initial credit + ok = ?T(validate_msg_store_io_batch_size_and_credit_disc_bound, + [{2000, 500}, 3000]), + {error, _} = ?T(validate_msg_store_io_batch_size_and_credit_disc_bound, + [{2000, 500}, 1500]), + + %% All values must be integers + {error, _} = ?T(validate_msg_store_io_batch_size_and_credit_disc_bound, + [{2000, 500}, "1500"]), + {error, _} = ?T(validate_msg_store_io_batch_size_and_credit_disc_bound, + [{"2000", 500}, abc]), + {error, _} = ?T(validate_msg_store_io_batch_size_and_credit_disc_bound, + [{2000, "500"}, 2048]), + + %% CREDIT_DISC_BOUND must be a tuple + {error, _} = ?T(validate_msg_store_io_batch_size_and_credit_disc_bound, + [[2000, 500], 1500]), + {error, _} = ?T(validate_msg_store_io_batch_size_and_credit_disc_bound, + [2000, 1500]), + + %% config values can't be smaller than default values + {error, _} = ?T(validate_msg_store_io_batch_size_and_credit_disc_bound, + [{1999, 500}, 2048]), + {error, _} = ?T(validate_msg_store_io_batch_size_and_credit_disc_bound, + [{2000, 499}, 2048]), + {error, _} = ?T(validate_msg_store_io_batch_size_and_credit_disc_bound, + [{2000, 500}, 2047]). diff --git a/test/password_hashing_SUITE.erl b/test/password_hashing_SUITE.erl new file mode 100644 index 0000000000..50f0f4e6d1 --- /dev/null +++ b/test/password_hashing_SUITE.erl @@ -0,0 +1,121 @@ +%% 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) 2011-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(password_hashing_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("rabbit_common/include/rabbit.hrl"). + +-compile(export_all). + +all() -> + [ + password_hashing, + change_password + ]. + +%% ------------------------------------------------------------------- +%% Testsuite setup/teardown. +%% ------------------------------------------------------------------- + +init_per_suite(Config) -> + rabbit_ct_helpers:log_environment(), + rabbit_ct_helpers:run_setup_steps(?MODULE, Config). + +end_per_suite(Config) -> + rabbit_ct_helpers:run_teardown_steps(Config). + +%% --------------------------------------------------------------------------- +%% Test cases +%% --------------------------------------------------------------------------- + +password_hashing(Config) -> + passed = rabbit_ct_broker_helpers:run_test_on_broker( + ?config(rmq_nodename, Config), + ?MODULE, password_hashing1, [Config]). + +password_hashing1(_Config) -> + rabbit_password_hashing_sha256 = rabbit_password:hashing_mod(), + application:set_env(rabbit, password_hashing_module, + rabbit_password_hashing_md5), + rabbit_password_hashing_md5 = rabbit_password:hashing_mod(), + application:set_env(rabbit, password_hashing_module, + rabbit_password_hashing_sha256), + rabbit_password_hashing_sha256 = rabbit_password:hashing_mod(), + + rabbit_password_hashing_sha256 = + rabbit_password:hashing_mod(rabbit_password_hashing_sha256), + rabbit_password_hashing_md5 = + rabbit_password:hashing_mod(rabbit_password_hashing_md5), + rabbit_password_hashing_md5 = + rabbit_password:hashing_mod(undefined), + + rabbit_password_hashing_md5 = + rabbit_auth_backend_internal:hashing_module_for_user( + #internal_user{}), + rabbit_password_hashing_md5 = + rabbit_auth_backend_internal:hashing_module_for_user( + #internal_user{ + hashing_algorithm = undefined + }), + rabbit_password_hashing_md5 = + rabbit_auth_backend_internal:hashing_module_for_user( + #internal_user{ + hashing_algorithm = rabbit_password_hashing_md5 + }), + + rabbit_password_hashing_sha256 = + rabbit_auth_backend_internal:hashing_module_for_user( + #internal_user{ + hashing_algorithm = rabbit_password_hashing_sha256 + }), + + passed. + +change_password(Config) -> + passed = rabbit_ct_broker_helpers:run_test_on_broker( + ?config(rmq_nodename, Config), + ?MODULE, change_password1, [Config]). + +change_password1(_Config) -> + UserName = <<"test_user">>, + Password = <<"test_password">>, + case rabbit_auth_backend_internal:lookup_user(UserName) of + {ok, _} -> rabbit_auth_backend_internal:delete_user(UserName); + _ -> ok + end, + ok = application:set_env(rabbit, password_hashing_module, + rabbit_password_hashing_md5), + ok = rabbit_auth_backend_internal:add_user(UserName, Password), + {ok, #auth_user{username = UserName}} = + rabbit_auth_backend_internal:user_login_authentication( + UserName, [{password, Password}]), + ok = application:set_env(rabbit, password_hashing_module, + rabbit_password_hashing_sha256), + {ok, #auth_user{username = UserName}} = + rabbit_auth_backend_internal:user_login_authentication( + UserName, [{password, Password}]), + + NewPassword = <<"test_password1">>, + ok = rabbit_auth_backend_internal:change_password(UserName, NewPassword), + {ok, #auth_user{username = UserName}} = + rabbit_auth_backend_internal:user_login_authentication( + UserName, [{password, NewPassword}]), + + {refused, _, [UserName]} = + rabbit_auth_backend_internal:user_login_authentication( + UserName, [{password, Password}]), + passed. diff --git a/test/rabbit_ctl_timeout_SUITE.erl b/test/rabbit_ctl_timeout_SUITE.erl new file mode 100644 index 0000000000..92b2867a54 --- /dev/null +++ b/test/rabbit_ctl_timeout_SUITE.erl @@ -0,0 +1,173 @@ +%% 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) 2007-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_ctl_timeout_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("rabbit_common/include/rabbit.hrl"). + +-compile(export_all). + +-define(TIMEOUT_LIST_OPS_PASS, 1000). + +all() -> + [ + list_operations_timeout_pass + ]. + +%% ------------------------------------------------------------------- +%% Testsuite setup/teardown. +%% ------------------------------------------------------------------- + +init_per_suite(Config) -> + rabbit_ct_helpers:log_environment(), + rabbit_ct_helpers:run_setup_steps(?MODULE, Config). + +end_per_suite(Config) -> + rabbit_ct_helpers:run_teardown_steps(Config). + +%% ------------------------------------------------------------------- +%% Test cases. +%% ------------------------------------------------------------------- + +list_operations_timeout_pass(Config) -> + passed = rabbit_ct_broker_helpers:run_test_on_broker( + ?config(rmq_nodename, Config), + ?MODULE, list_operations_timeout_pass1, [Config]). + +list_operations_timeout_pass1(_Config) -> + %% create a few things so there is some useful information to list + {_Writer1, Limiter1, Ch1} = rabbit_ct_broker_helpers:test_channel(), + {_Writer2, Limiter2, Ch2} = rabbit_ct_broker_helpers:test_channel(), + + [Q, Q2] = [Queue || Name <- [<<"foo">>, <<"bar">>], + {new, Queue = #amqqueue{}} <- + [rabbit_amqqueue:declare( + rabbit_misc:r(<<"/">>, queue, Name), + false, false, [], none)]], + + ok = rabbit_amqqueue:basic_consume( + Q, true, Ch1, Limiter1, false, 0, <<"ctag1">>, true, [], + undefined), + ok = rabbit_amqqueue:basic_consume( + Q2, true, Ch2, Limiter2, false, 0, <<"ctag2">>, true, [], + undefined), + + %% list users + ok = rabbit_ct_helpers:control_action(add_user, ["foo", "bar"]), + {error, {user_already_exists, _}} = + rabbit_ct_helpers:control_action(add_user, ["foo", "bar"]), + ok = rabbit_ct_helpers:control_action_t(list_users, [], + ?TIMEOUT_LIST_OPS_PASS), + + %% list parameters + ok = rabbit_runtime_parameters_test:register(), + ok = rabbit_ct_helpers:control_action(set_parameter, + ["test", "good", "123"]), + ok = rabbit_ct_helpers:control_action_t(list_parameters, [], + ?TIMEOUT_LIST_OPS_PASS), + ok = rabbit_ct_helpers:control_action(clear_parameter, + ["test", "good"]), + rabbit_runtime_parameters_test:unregister(), + + %% list vhosts + ok = rabbit_ct_helpers:control_action(add_vhost, ["/testhost"]), + {error, {vhost_already_exists, _}} = + rabbit_ct_helpers:control_action(add_vhost, ["/testhost"]), + ok = rabbit_ct_helpers:control_action_t(list_vhosts, [], + ?TIMEOUT_LIST_OPS_PASS), + + %% list permissions + ok = rabbit_ct_helpers:control_action(set_permissions, + ["foo", ".*", ".*", ".*"], + [{"-p", "/testhost"}]), + ok = rabbit_ct_helpers:control_action_t(list_permissions, [], + [{"-p", "/testhost"}], + ?TIMEOUT_LIST_OPS_PASS), + + %% list user permissions + ok = rabbit_ct_helpers:control_action_t(list_user_permissions, ["foo"], + ?TIMEOUT_LIST_OPS_PASS), + + %% list policies + ok = rabbit_ct_helpers:control_action_opts(["set_policy", "name", ".*", + "{\"ha-mode\":\"all\"}"]), + ok = rabbit_ct_helpers:control_action_t(list_policies, [], + ?TIMEOUT_LIST_OPS_PASS), + ok = rabbit_ct_helpers:control_action(clear_policy, ["name"]), + + %% list queues + ok = rabbit_ct_helpers:info_action_t(list_queues, + rabbit_amqqueue:info_keys(), false, + ?TIMEOUT_LIST_OPS_PASS), + + %% list exchanges + ok = rabbit_ct_helpers:info_action_t(list_exchanges, + rabbit_exchange:info_keys(), true, + ?TIMEOUT_LIST_OPS_PASS), + + %% list bindings + ok = rabbit_ct_helpers:info_action_t(list_bindings, + rabbit_binding:info_keys(), true, + ?TIMEOUT_LIST_OPS_PASS), + + %% list connections + {H, P} = rabbit_ct_broker_helpers:find_listener(), + {ok, C1} = gen_tcp:connect(H, P, [binary, {active, false}]), + gen_tcp:send(C1, <<"AMQP", 0, 0, 9, 1>>), + {ok, <<1,0,0>>} = gen_tcp:recv(C1, 3, 100), + + {ok, C2} = gen_tcp:connect(H, P, [binary, {active, false}]), + gen_tcp:send(C2, <<"AMQP", 0, 0, 9, 1>>), + {ok, <<1,0,0>>} = gen_tcp:recv(C2, 3, 100), + + ok = rabbit_ct_helpers:info_action_t( + list_connections, rabbit_networking:connection_info_keys(), false, + ?TIMEOUT_LIST_OPS_PASS), + + %% list consumers + ok = rabbit_ct_helpers:info_action_t( + list_consumers, rabbit_amqqueue:consumer_info_keys(), false, + ?TIMEOUT_LIST_OPS_PASS), + + %% list channels + ok = rabbit_ct_helpers:info_action_t( + list_channels, rabbit_channel:info_keys(), false, + ?TIMEOUT_LIST_OPS_PASS), + + %% do some cleaning up + ok = rabbit_ct_helpers:control_action(delete_user, ["foo"]), + {error, {no_such_user, _}} = + rabbit_ct_helpers:control_action(delete_user, ["foo"]), + + ok = rabbit_ct_helpers:control_action(delete_vhost, ["/testhost"]), + {error, {no_such_vhost, _}} = + rabbit_ct_helpers:control_action(delete_vhost, ["/testhost"]), + + %% close_connection + Conns = rabbit_networking:connections(), + [ok = rabbit_ct_helpers:control_action( + close_connection, [rabbit_misc:pid_to_string(ConnPid), "go away"]) + || ConnPid <- Conns], + + %% cleanup queues + [{ok, _} = rabbit_amqqueue:delete(QR, false, false) || QR <- [Q, Q2]], + + [begin + unlink(Chan), + ok = rabbit_channel:shutdown(Chan) + end || Chan <- [Ch1, Ch2]], + passed. diff --git a/test/resource_monitor_SUITE.erl b/test/resource_monitor_SUITE.erl new file mode 100644 index 0000000000..378b75cc1a --- /dev/null +++ b/test/resource_monitor_SUITE.erl @@ -0,0 +1,64 @@ +%% 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) 2007-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(resource_monitor_SUITE). + +-include_lib("common_test/include/ct.hrl"). + +-compile(export_all). + +all() -> + [ + parse_information_unit + ]. + +%% --------------------------------------------------------------------------- +%% Tests +%% --------------------------------------------------------------------------- + +parse_information_unit(_Config) -> + lists:foreach(fun ({S, V}) -> + V = rabbit_resource_monitor_misc:parse_information_unit(S) + end, + [ + {"1000", {ok, 1000}}, + + {"10kB", {ok, 10000}}, + {"10MB", {ok, 10000000}}, + {"10GB", {ok, 10000000000}}, + + {"10kiB", {ok, 10240}}, + {"10MiB", {ok, 10485760}}, + {"10GiB", {ok, 10737418240}}, + + {"10k", {ok, 10240}}, + {"10M", {ok, 10485760}}, + {"10G", {ok, 10737418240}}, + + {"10KB", {ok, 10000}}, + {"10K", {ok, 10240}}, + {"10m", {ok, 10485760}}, + {"10Mb", {ok, 10000000}}, + + {"0MB", {ok, 0}}, + + {"10 k", {error, parse_error}}, + {"MB", {error, parse_error}}, + {"", {error, parse_error}}, + {"0.5GB", {error, parse_error}}, + {"10TB", {error, parse_error}} + ]), + passed. diff --git a/test/supervisor2_SUITE.erl b/test/supervisor2_SUITE.erl new file mode 100644 index 0000000000..e2b95146c0 --- /dev/null +++ b/test/supervisor2_SUITE.erl @@ -0,0 +1,90 @@ +%% 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) 2011-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(supervisor2_SUITE). + +-behaviour(supervisor2). + +-include_lib("common_test/include/ct.hrl"). + +-compile(export_all). + +all() -> + [ + check_shutdown_stop, + check_shutdown_ignored + ]. + +check_shutdown_stop(_Config) -> + ok = check_shutdown(stop, 200, 200, 2000). + +check_shutdown_ignored(_Config) -> + ok = check_shutdown(ignored, 1, 2, 2000). + +check_shutdown(SigStop, Iterations, ChildCount, SupTimeout) -> + {ok, Sup} = supervisor2:start_link(?MODULE, [SupTimeout]), + Res = lists:foldl( + fun (I, ok) -> + TestSupPid = erlang:whereis(?MODULE), + ChildPids = + [begin + {ok, ChildPid} = + supervisor2:start_child(TestSupPid, []), + ChildPid + end || _ <- lists:seq(1, ChildCount)], + MRef = erlang:monitor(process, TestSupPid), + [P ! SigStop || P <- ChildPids], + ok = supervisor2:terminate_child(Sup, test_sup), + {ok, _} = supervisor2:restart_child(Sup, test_sup), + receive + {'DOWN', MRef, process, TestSupPid, shutdown} -> + ok; + {'DOWN', MRef, process, TestSupPid, Reason} -> + {error, {I, Reason}} + end; + (_, R) -> + R + end, ok, lists:seq(1, Iterations)), + unlink(Sup), + MSupRef = erlang:monitor(process, Sup), + exit(Sup, shutdown), + receive + {'DOWN', MSupRef, process, Sup, _Reason} -> + ok + end, + Res. + +%% ------------------------------------------------------------------- +%% supervisor2 behavior callbacks. +%% ------------------------------------------------------------------- + +start_link() -> + Pid = spawn_link(fun () -> + process_flag(trap_exit, true), + receive stop -> ok end + end), + {ok, Pid}. + +init([Timeout]) -> + {ok, {{one_for_one, 0, 1}, + [{test_sup, {supervisor2, start_link, + [{local, ?MODULE}, ?MODULE, []]}, + transient, Timeout, supervisor, [?MODULE]}]}}; +init([]) -> + {ok, {{simple_one_for_one, 0, 1}, + [{test_worker, {?MODULE, start_link, []}, + temporary, 1000, worker, [?MODULE]}]}}. + diff --git a/test/truncate_SUITE.erl b/test/truncate_SUITE.erl new file mode 100644 index 0000000000..6c78be726d --- /dev/null +++ b/test/truncate_SUITE.erl @@ -0,0 +1,99 @@ +%% 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) 2007-2016 Pivotal Software, Inc. All rights reserved. +%% + +-module(truncate_SUITE). + +-include_lib("common_test/include/ct.hrl"). + +-compile(export_all). + +all() -> + [ + {group, all_tests} + ]. + +groups() -> + [ + {all_tests, [parallel], [ + short_examples_exactly, + term_limit, + large_examples_for_size + ]} + ]. + +init_per_group(_, Config) -> Config. +end_per_group(_, Config) -> Config. + +short_examples_exactly(_Config) -> + F = fun (Term, Exp) -> + Exp = truncate:term(Term, {1, {10, 10, 5, 5}}), + Term = truncate:term(Term, {100000, {10, 10, 5, 5}}) + end, + FSmall = fun (Term, Exp) -> + Exp = truncate:term(Term, {1, {2, 2, 2, 2}}), + Term = truncate:term(Term, {100000, {2, 2, 2, 2}}) + end, + F([], []), + F("h", "h"), + F("hello world", "hello w..."), + F([[h,e,l,l,o,' ',w,o,r,l,d]], [[h,e,l,l,o,'...']]), + F([a|b], [a|b]), + F(<<"hello">>, <<"hello">>), + F([<<"hello world">>], [<<"he...">>]), + F(<<1:1>>, <<1:1>>), + F(<<1:81>>, <<0:56, "...">>), + F({{{{a}}},{b},c,d,e,f,g,h,i,j,k}, {{{'...'}},{b},c,d,e,f,g,h,i,j,'...'}), + FSmall({a,30,40,40,40,40}, {a,30,'...'}), + FSmall([a,30,40,40,40,40], [a,30,'...']), + P = spawn(fun() -> receive die -> ok end end), + F([0, 0.0, <<1:1>>, F, P], [0, 0.0, <<1:1>>, F, P]), + P ! die, + R = make_ref(), + F([R], [R]), + ok. + +term_limit(_Config) -> + W = erlang:system_info(wordsize), + S = <<"abc">>, + 1 = truncate:term_size(S, 4, W), + limit_exceeded = truncate:term_size(S, 3, W), + case 100 - truncate:term_size([S, S], 100, W) of + 22 -> ok; %% 32 bit + 38 -> ok %% 64 bit + end, + case 100 - truncate:term_size([S, [S]], 100, W) of + 30 -> ok; %% ditto + 54 -> ok + end, + limit_exceeded = truncate:term_size([S, S], 6, W), + ok. + +large_examples_for_size(_Config) -> + %% Real world values + Shrink = fun(Term) -> truncate:term(Term, {1, {1000, 100, 50, 5}}) end, + TestSize = fun(Term) -> + true = 5000000 < size(term_to_binary(Term)), + true = 500000 > size(term_to_binary(Shrink(Term))) + end, + TestSize(lists:seq(1, 5000000)), + TestSize(recursive_list(1000, 10)), + TestSize(recursive_list(5000, 20)), + TestSize(gb_sets:from_list([I || I <- lists:seq(1, 1000000)])), + TestSize(gb_trees:from_orddict([{I, I} || I <- lists:seq(1, 1000000)])), + ok. + +recursive_list(S, 0) -> lists:seq(1, S); +recursive_list(S, N) -> [recursive_list(S div N, N-1) || _ <- lists:seq(1, S)]. diff --git a/test/vm_memory_monitor_SUITE.erl b/test/vm_memory_monitor_SUITE.erl new file mode 100644 index 0000000000..195fff7567 --- /dev/null +++ b/test/vm_memory_monitor_SUITE.erl @@ -0,0 +1,42 @@ +%% 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) 2007-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(vm_memory_monitor_SUITE). + +-include_lib("common_test/include/ct.hrl"). + +-compile(export_all). + +all() -> + [ + parse_line_linux + ]. + +%% --------------------------------------------------------------------------- +%% Test cases +%% --------------------------------------------------------------------------- + +parse_line_linux(_Config) -> + lists:foreach(fun ({S, {K, V}}) -> + {K, V} = vm_memory_monitor:parse_line_linux(S) + end, + [{"MemTotal: 0 kB", {'MemTotal', 0}}, + {"MemTotal: 502968 kB ", {'MemTotal', 515039232}}, + {"MemFree: 178232 kB", {'MemFree', 182509568}}, + {"MemTotal: 50296888", {'MemTotal', 50296888}}, + {"MemTotal 502968 kB", {'MemTotal', 515039232}}, + {"MemTotal 50296866 ", {'MemTotal', 50296866}}]), + ok. |
