Tests are moved to rabbitmq-test

This commit is contained in:
Jean-Sébastien Pédron 2015-09-02 11:32:12 +02:00 committed by Jean-Sébastien Pédron
parent 93d830ee5a
commit acab9f2f00
15 changed files with 0 additions and 5281 deletions

View File

@ -1,50 +0,0 @@
%% 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_test).
-export([test_credit_flow_settings/0]).
test_credit_flow_settings() ->
%% 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.

View File

@ -1,384 +0,0 @@
%% 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(gm_qc).
-ifdef(use_proper_qc).
-include_lib("proper/include/proper.hrl").
-define(GROUP, test_group).
-define(MAX_SIZE, 5).
-define(MSG_TIMEOUT, 1000000). %% micros
-export([prop_gm_test/0]).
-behaviour(proper_statem).
-export([initial_state/0, command/1, precondition/2, postcondition/3,
next_state/3]).
-behaviour(gm).
-export([joined/2, members_changed/3, handle_msg/3, handle_terminate/2]).
%% Helpers
-export([do_join/0, do_leave/1, do_send/1, do_proceed1/1, do_proceed2/2]).
%% For insertion into gm
-export([call/3, cast/2, monitor/1, demonitor/1, execute_mnesia_transaction/1]).
-record(state, {seq, %% symbolic and dynamic
instrumented, %% dynamic only
outstanding, %% dynamic only
monitors, %% dynamic only
all_join, %% for symbolic
to_join, %% dynamic only
to_leave %% for symbolic
}).
prop_gm_test() ->
case ?INSTR_MOD of
?MODULE -> ok;
_ -> exit(compile_with_INSTRUMENT_FOR_QC)
end,
process_flag(trap_exit, true),
erlang:register(?MODULE, self()),
?FORALL(Cmds, commands(?MODULE), gm_test(Cmds)).
gm_test(Cmds) ->
{_H, State, Res} = run_commands(?MODULE, Cmds),
cleanup(State),
?WHENFAIL(
io:format("Result: ~p~n", [Res]),
aggregate(command_names(Cmds), Res =:= ok)).
cleanup(S) ->
S2 = ensure_joiners_joined_and_msgs_received(S),
All = gms_joined(S2),
All = gms(S2), %% assertion - none to join
check_stale_members(All),
[gm:leave(GM) || GM <- All],
drain_and_proceed_gms(S2),
[await_death(GM) || GM <- All],
gm:forget_group(?GROUP),
ok.
check_stale_members(All) ->
GMs = [P || P <- processes(), is_gm_process(?GROUP, P)],
case GMs -- All of
[] -> ok;
Rest -> exit({forgot, Rest})
end.
is_gm_process(Group, P) ->
case process_info(P, dictionary) of
undefined -> false;
{dictionary, D} -> {gm, Group} =:= proplists:get_value(process_name, D)
end.
await_death(P) ->
MRef = erlang:monitor(process, P),
await_death(MRef, P).
await_death(MRef, P) ->
receive
{'DOWN', MRef, process, P, _} -> ok;
{'DOWN', _, _, _, _} -> await_death(MRef, P);
{'EXIT', _, normal} -> await_death(MRef, P);
{'EXIT', _, Reason} -> exit(Reason);
{joined, _GM} -> await_death(MRef, P);
{left, _GM} -> await_death(MRef, P);
Anything -> exit({stray_msg, Anything})
end.
%% ---------------------------------------------------------------------------
%% proper_statem
%% ---------------------------------------------------------------------------
initial_state() -> #state{seq = 1,
outstanding = dict:new(),
instrumented = dict:new(),
monitors = dict:new(),
all_join = sets:new(),
to_join = sets:new(),
to_leave = sets:new()}.
command(S) ->
case {length(gms_symb_not_left(S)), length(gms_symb(S))} of
{0, 0} -> qc_join(S);
{0, _} -> frequency([{1, qc_join(S)},
{3, qc_proceed1(S)},
{5, qc_proceed2(S)}]);
_ -> frequency([{1, qc_join(S)},
{1, qc_leave(S)},
{10, qc_send(S)},
{5, qc_proceed1(S)},
{15, qc_proceed2(S)}])
end.
qc_join(_S) -> {call,?MODULE,do_join, []}.
qc_leave(S) -> {call,?MODULE,do_leave,[oneof(gms_symb_not_left(S))]}.
qc_send(S) -> {call,?MODULE,do_send, [oneof(gms_symb_not_left(S))]}.
qc_proceed1(S) -> {call,?MODULE,do_proceed1, [oneof(gms_symb(S))]}.
qc_proceed2(S) -> {call,?MODULE,do_proceed2, [oneof(gms_symb(S)),
oneof(gms_symb(S))]}.
precondition(S, {call, ?MODULE, do_join, []}) ->
length(gms_symb(S)) < ?MAX_SIZE;
precondition(_S, {call, ?MODULE, do_leave, [_GM]}) ->
true;
precondition(_S, {call, ?MODULE, do_send, [_GM]}) ->
true;
precondition(_S, {call, ?MODULE, do_proceed1, [_GM]}) ->
true;
precondition(_S, {call, ?MODULE, do_proceed2, [GM1, GM2]}) ->
GM1 =/= GM2.
postcondition(_S, {call, _M, _F, _A}, _Res) ->
true.
next_state(S = #state{to_join = ToSet,
all_join = AllSet}, GM, {call, ?MODULE, do_join, []}) ->
S#state{to_join = sets:add_element(GM, ToSet),
all_join = sets:add_element(GM, AllSet)};
next_state(S = #state{to_leave = Set}, _Res, {call, ?MODULE, do_leave, [GM]}) ->
S#state{to_leave = sets:add_element(GM, Set)};
next_state(S = #state{seq = Seq,
outstanding = Outstanding}, _Res,
{call, ?MODULE, do_send, [GM]}) ->
case is_pid(GM) andalso lists:member(GM, gms_joined(S)) of
true ->
%% Dynamic state, i.e. runtime
Msg = [{sequence, Seq},
{sent_to, GM},
{dests, gms_joined(S)}],
gm:broadcast(GM, Msg),
Outstanding1 = dict:map(
fun (_GM, Set) ->
gb_sets:add_element(Msg, Set)
end, Outstanding),
drain(S#state{seq = Seq + 1,
outstanding = Outstanding1});
false ->
S
end;
next_state(S, _Res, {call, ?MODULE, do_proceed1, [Pid]}) ->
proceed(Pid, S);
next_state(S, _Res, {call, ?MODULE, do_proceed2, [From, To]}) ->
proceed({From, To}, S).
proceed(K, S = #state{instrumented = Msgs}) ->
case dict:find(K, Msgs) of
{ok, Q} -> case queue:out(Q) of
{{value, Thing}, Q2} ->
S2 = proceed(K, Thing, S),
S2#state{instrumented = dict:store(K, Q2, Msgs)};
{empty, _} ->
S
end;
error -> S
end.
%% ---------------------------------------------------------------------------
%% GM
%% ---------------------------------------------------------------------------
joined(Pid, _Members) -> Pid ! {joined, self()},
ok.
members_changed(_Pid, _Bs, _Ds) -> ok.
handle_msg(Pid, _From, Msg) -> Pid ! {gm, self(), Msg}, ok.
handle_terminate(Pid, _Reason) -> Pid ! {left, self()}.
%% ---------------------------------------------------------------------------
%% Helpers
%% ---------------------------------------------------------------------------
do_join() ->
{ok, GM} = gm:start_link(?GROUP, ?MODULE, self(),
fun execute_mnesia_transaction/1),
GM.
do_leave(GM) ->
gm:leave(GM),
GM.
%% We need to update the state, so do the work in next_state
do_send( _GM) -> ok.
do_proceed1(_Pid) -> ok.
do_proceed2(_From, _To) -> ok.
%% All GMs, joined and to join
gms(#state{outstanding = Outstanding,
to_join = ToJoin}) ->
dict:fetch_keys(Outstanding) ++ sets:to_list(ToJoin).
%% All GMs, joined and to join
gms_joined(#state{outstanding = Outstanding}) ->
dict:fetch_keys(Outstanding).
%% All GMs including those that have left (symbolic)
gms_symb(#state{all_join = AllJoin}) ->
sets:to_list(AllJoin).
%% All GMs not including those that have left (symbolic)
gms_symb_not_left(#state{all_join = AllJoin,
to_leave = ToLeave}) ->
sets:to_list(sets:subtract(AllJoin, ToLeave)).
drain(S) ->
receive
Msg -> drain(handle_msg(Msg, S))
after 10 -> S
end.
drain_and_proceed_gms(S0) ->
S = #state{instrumented = Msgs} = drain(S0),
case dict:size(Msgs) of
0 -> S;
_ -> S1 = dict:fold(
fun (Key, Q, Si) ->
lists:foldl(
fun (Msg, Sij) ->
proceed(Key, Msg, Sij)
end, Si, queue:to_list(Q))
end, S, Msgs),
drain_and_proceed_gms(S1#state{instrumented = dict:new()})
end.
handle_msg({gm, GM, Msg}, S = #state{outstanding = Outstanding}) ->
case dict:find(GM, Outstanding) of
{ok, Set} ->
Set2 = gb_sets:del_element(Msg, Set),
S#state{outstanding = dict:store(GM, Set2, Outstanding)};
error ->
%% Message from GM that has already died. OK.
S
end;
handle_msg({instrumented, Key, Thing}, S = #state{instrumented = Msgs}) ->
Q1 = case dict:find(Key, Msgs) of
{ok, Q} -> queue:in(Thing, Q);
error -> queue:from_list([Thing])
end,
S#state{instrumented = dict:store(Key, Q1, Msgs)};
handle_msg({joined, GM}, S = #state{outstanding = Outstanding,
to_join = ToJoin}) ->
S#state{outstanding = dict:store(GM, gb_sets:empty(), Outstanding),
to_join = sets:del_element(GM, ToJoin)};
handle_msg({left, GM}, S = #state{outstanding = Outstanding,
to_join = ToJoin}) ->
true = dict:is_key(GM, Outstanding) orelse sets:is_element(GM, ToJoin),
S#state{outstanding = dict:erase(GM, Outstanding),
to_join = sets:del_element(GM, ToJoin)};
handle_msg({'DOWN', MRef, _, From, _} = Msg, S = #state{monitors = Mons}) ->
To = dict:fetch(MRef, Mons),
handle_msg({instrumented, {From, To}, {info, Msg}},
S#state{monitors = dict:erase(MRef, Mons)});
handle_msg({'EXIT', _From, normal}, S) ->
S;
handle_msg({'EXIT', _From, Reason}, _S) ->
%% We just trapped exits to get nicer SASL logging.
exit(Reason).
proceed({_From, To}, {cast, Msg}, S) -> gen_server2:cast(To, Msg), S;
proceed({_From, To}, {info, Msg}, S) -> To ! Msg, S;
proceed({From, _To}, {wait, Ref}, S) -> From ! {proceed, Ref}, S;
proceed({From, To}, {mon, Ref}, S) -> add_monitor(From, To, Ref, S);
proceed(_Pid, {demon, MRef}, S) -> erlang:demonitor(MRef), S;
proceed(Pid, {wait, Ref}, S) -> Pid ! {proceed, Ref}, S.
%% NB From here is To in handle_msg/DOWN above, since the msg is going
%% the other way
add_monitor(From, To, Ref, S = #state{monitors = Mons}) ->
MRef = erlang:monitor(process, To),
From ! {mref, Ref, MRef},
S#state{monitors = dict:store(MRef, From, Mons)}.
%% ----------------------------------------------------------------------------
%% Assertions
%% ----------------------------------------------------------------------------
ensure_joiners_joined_and_msgs_received(S0) ->
S = drain_and_proceed_gms(S0),
case outstanding_joiners(S) of
true -> ensure_joiners_joined_and_msgs_received(S);
false -> case outstanding_msgs(S) of
[] -> S;
Out -> exit({outstanding_msgs, Out})
end
end.
outstanding_joiners(#state{to_join = ToJoin}) ->
sets:size(ToJoin) > 0.
outstanding_msgs(#state{outstanding = Outstanding}) ->
dict:fold(fun (GM, Set, OS) ->
case gb_sets:is_empty(Set) of
true -> OS;
false -> [{GM, gb_sets:to_list(Set)} | OS]
end
end, [], Outstanding).
%% ---------------------------------------------------------------------------
%% For insertion into GM
%% ---------------------------------------------------------------------------
call(Pid, Msg, infinity) ->
Ref = make_ref(),
whereis(?MODULE) ! {instrumented, {self(), Pid}, {wait, Ref}},
receive
{proceed, Ref} -> ok
end,
gen_server2:call(Pid, Msg, infinity).
cast(Pid, Msg) ->
whereis(?MODULE) ! {instrumented, {self(), Pid}, {cast, Msg}},
ok.
monitor(Pid) ->
Ref = make_ref(),
whereis(?MODULE) ! {instrumented, {self(), Pid}, {mon, Ref}},
receive
{mref, Ref, MRef} -> MRef
end.
demonitor(MRef) ->
whereis(?MODULE) ! {instrumented, self(), {demon, MRef}},
true.
execute_mnesia_transaction(Fun) ->
Ref = make_ref(),
whereis(?MODULE) ! {instrumented, self(), {wait, Ref}},
receive
{proceed, Ref} -> ok
end,
rabbit_misc:execute_mnesia_transaction(Fun).
-else.
-export([prop_disabled/0]).
prop_disabled() ->
exit({compiled_without_proper,
"PropEr was not present during compilation of the test module. "
"Hence all tests are disabled."}).
-endif.

View File

@ -1,136 +0,0 @@
%% 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_soak_test).
-export([test/0]).
-export([joined/2, members_changed/3, handle_msg/3, handle_terminate/2]).
-behaviour(gm).
-include("gm_specs.hrl").
%% ---------------------------------------------------------------------------
%% Soak test
%% ---------------------------------------------------------------------------
get_state() ->
get(state).
with_state(Fun) ->
put(state, Fun(get_state())).
inc() ->
case 1 + get(count) of
100000 -> Now = time_compat:monotonic_time(),
Start = put(ts, Now),
Diff = time_compat:convert_time_unit(Now - Start,
native,
micro_seconds),
Rate = 100000 / (Diff / 1000000),
io:format("~p seeing ~p msgs/sec~n", [self(), Rate]),
put(count, 0);
N -> put(count, N)
end.
joined([], Members) ->
io:format("Joined ~p (~p members)~n", [self(), length(Members)]),
put(state, dict:from_list([{Member, empty} || Member <- Members])),
put(count, 0),
put(ts, time_compat:monotonic_time()),
ok.
members_changed([], Births, Deaths) ->
with_state(
fun (State) ->
State1 =
lists:foldl(
fun (Born, StateN) ->
false = dict:is_key(Born, StateN),
dict:store(Born, empty, StateN)
end, State, Births),
lists:foldl(
fun (Died, StateN) ->
true = dict:is_key(Died, StateN),
dict:store(Died, died, StateN)
end, State1, Deaths)
end),
ok.
handle_msg([], From, {test_msg, Num}) ->
inc(),
with_state(
fun (State) ->
ok = case dict:find(From, State) of
{ok, died} ->
exit({{from, From},
{received_posthumous_delivery, Num}});
{ok, empty} -> ok;
{ok, Num} -> ok;
{ok, Num1} when Num < Num1 ->
exit({{from, From},
{duplicate_delivery_of, Num},
{expecting, Num1}});
{ok, Num1} ->
exit({{from, From},
{received_early, Num},
{expecting, Num1}});
error ->
exit({{from, From},
{received_premature_delivery, Num}})
end,
dict:store(From, Num + 1, State)
end),
ok.
handle_terminate([], Reason) ->
io:format("Left ~p (~p)~n", [self(), Reason]),
ok.
spawn_member() ->
spawn_link(
fun () ->
random:seed(erlang:phash2([node()]),
time_compat:monotonic_time(),
time_compat:unique_integer()),
%% start up delay of no more than 10 seconds
timer:sleep(random:uniform(10000)),
{ok, Pid} = gm:start_link(
?MODULE, ?MODULE, [],
fun rabbit_misc:execute_mnesia_transaction/1),
Start = random:uniform(10000),
send_loop(Pid, Start, Start + random:uniform(10000)),
gm:leave(Pid),
spawn_more()
end).
spawn_more() ->
[spawn_member() || _ <- lists:seq(1, 4 - random:uniform(4))].
send_loop(_Pid, Target, Target) ->
ok;
send_loop(Pid, Count, Target) when Target > Count ->
case random:uniform(3) of
3 -> gm:confirmed_broadcast(Pid, {test_msg, Count});
_ -> gm:broadcast(Pid, {test_msg, Count})
end,
timer:sleep(random:uniform(5) - 1), %% sleep up to 4 ms
send_loop(Pid, Count + 1, Target).
test() ->
ok = gm:create_tables(),
spawn_member(),
spawn_member().

View File

@ -1,85 +0,0 @@
%% 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_speed_test).
-export([test/3]).
-export([joined/2, members_changed/3, handle_msg/3, handle_terminate/2]).
-export([wile_e_coyote/2]).
-behaviour(gm).
-include("gm_specs.hrl").
%% callbacks
joined(Owner, _Members) ->
Owner ! joined,
ok.
members_changed(_Owner, _Births, _Deaths) ->
ok.
handle_msg(Owner, _From, ping) ->
Owner ! ping,
ok.
handle_terminate(Owner, _Reason) ->
Owner ! terminated,
ok.
%% other
wile_e_coyote(Time, WriteUnit) ->
{ok, Pid} = gm:start_link(?MODULE, ?MODULE, self(),
fun rabbit_misc:execute_mnesia_transaction/1),
receive joined -> ok end,
timer:sleep(1000), %% wait for all to join
timer:send_after(Time, stop),
Start = time_compat:monotonic_time(),
{Sent, Received} = loop(Pid, WriteUnit, 0, 0),
End = time_compat:monotonic_time(),
ok = gm:leave(Pid),
receive terminated -> ok end,
Elapsed = time_compat:convert_time_unit(End - Start,
native,
micro_seconds) / 1000000,
io:format("Sending rate: ~p msgs/sec~nReceiving rate: ~p msgs/sec~n~n",
[Sent/Elapsed, Received/Elapsed]),
ok.
loop(Pid, WriteUnit, Sent, Received) ->
case read(Received) of
{stop, Received1} -> {Sent, Received1};
{ok, Received1} -> ok = write(Pid, WriteUnit),
loop(Pid, WriteUnit, Sent + WriteUnit, Received1)
end.
read(Count) ->
receive
ping -> read(Count + 1);
stop -> {stop, Count}
after 5 ->
{ok, Count}
end.
write(_Pid, 0) -> ok;
write(Pid, N) -> ok = gm:broadcast(Pid, ping),
write(Pid, N - 1).
test(Time, WriteUnit, Nodes) ->
ok = gm:create_tables(),
[spawn(Node, ?MODULE, wile_e_coyote, [Time, WriteUnit]) || Node <- Nodes].

View File

@ -1,186 +0,0 @@
%% 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_tests).
-export([test_join_leave/0,
test_broadcast/0,
test_confirmed_broadcast/0,
test_member_death/0,
test_receive_in_order/0,
all_tests/0]).
-export([joined/2, members_changed/3, handle_msg/3, handle_terminate/2]).
-behaviour(gm).
-include("gm_specs.hrl").
-define(RECEIVE_OR_THROW(Body, Bool, Error),
receive Body ->
true = Bool,
passed
after 1000 ->
throw(Error)
end).
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.
%% ---------------------------------------------------------------------------
%% Functional tests
%% ---------------------------------------------------------------------------
all_tests() ->
passed = test_join_leave(),
passed = test_broadcast(),
passed = test_confirmed_broadcast(),
passed = test_member_death(),
passed = test_receive_in_order(),
passed.
test_join_leave() ->
with_two_members(fun (_Pid, _Pid2) -> passed end).
test_broadcast() ->
test_broadcast(fun gm:broadcast/2).
test_confirmed_broadcast() ->
test_broadcast(fun gm:confirmed_broadcast/2).
test_member_death() ->
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 = (test_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).
test_receive_in_order() ->
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).
test_broadcast(Fun) ->
with_two_members(test_broadcast_fun(Fun)).
test_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).

View File

@ -1,307 +0,0 @@
%% 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_tests).
-export([all_tests/0]).
-export([init/1]).
-behaviour(mirrored_supervisor).
-define(MS, mirrored_supervisor).
-define(SERVER, mirrored_supervisor_tests_gs).
%% ---------------------------------------------------------------------------
%% Functional tests
%% ---------------------------------------------------------------------------
all_tests() ->
passed = test_migrate(),
passed = test_migrate_twice(),
passed = test_already_there(),
passed = test_delete_restart(),
passed = test_which_children(),
passed = test_large_group(),
passed = test_childspecs_at_init(),
passed = test_anonymous_supervisors(),
passed = test_no_migration_on_shutdown(),
passed = test_start_idempotence(),
passed = test_unsupported(),
passed = test_ignore(),
passed = test_startup_failure(),
passed.
%% Simplest test
test_migrate() ->
with_sups(fun([A, _]) ->
?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?
test_migrate_twice() ->
with_sups(fun([A, B]) ->
?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
test_already_there() ->
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
test_delete_restart() ->
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]).
test_which_children() ->
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, [mirrored_supervisor_tests]} = Child,
Pid.
%% Not all the members of the group should actually do the failover
test_large_group() ->
with_sups(fun([A, _, _, _]) ->
?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?
test_childspecs_at_init() ->
S = childspec(worker),
with_sups(fun([A, _]) ->
Pid1 = pid_of(worker),
kill_registered(A, Pid1),
Pid2 = pid_of(worker),
false = (Pid1 =:= Pid2)
end, [{a, [S]}, {b, [S]}]).
test_anonymous_supervisors() ->
with_sups(fun([A, _B]) ->
?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.
test_no_migration_on_shutdown() ->
with_sups(fun([Evil, _]) ->
?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]).
test_start_idempotence() ->
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]).
test_unsupported() ->
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
?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,
passed.
%% Just test we don't blow up
test_ignore() ->
?MS:start_link({local, foo}, get_group(group), fun tx_fun/1, ?MODULE,
{fake_strategy_for_ignore, []}),
passed.
test_startup_failure() ->
[test_startup_failure(F) || F <- [want_error, want_exit]],
passed.
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}}.

View File

@ -1,66 +0,0 @@
%% 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_tests_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.

View File

@ -1,47 +0,0 @@
%% 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(on_disk_store_tunable_parameter_validation_test).
-include("rabbit.hrl").
-export([test_msg_store_parameter_validation/0]).
-define(T(Fun, Args), (catch apply(rabbit, Fun, Args))).
test_msg_store_parameter_validation() ->
%% 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]),
passed.

View File

@ -1,473 +0,0 @@
%% 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(rabbit_backing_queue_qc).
-ifdef(use_proper_qc).
-include("rabbit.hrl").
-include("rabbit_framing.hrl").
-include_lib("proper/include/proper.hrl").
-behaviour(proper_statem).
-define(BQMOD, rabbit_variable_queue).
-define(QUEUE_MAXLEN, 10000).
-define(TIMEOUT_LIMIT, 100).
-define(RECORD_INDEX(Key, Record),
proplists:get_value(
Key, lists:zip(record_info(fields, Record),
lists:seq(2, record_info(size, Record))))).
-export([initial_state/0, command/1, precondition/2, postcondition/3,
next_state/3]).
-export([prop_backing_queue_test/0, publish_multiple/1,
timeout/2, bump_credit/1]).
-record(state, {bqstate,
len, %% int
next_seq_id, %% int
messages, %% gb_trees of seqid => {msg_props, basic_msg}
acks, %% [{acktag, {seqid, {msg_props, basic_msg}}}]
confirms, %% set of msgid
publishing}).%% int
%% Initialise model
initial_state() ->
#state{bqstate = qc_variable_queue_init(qc_test_queue()),
len = 0,
next_seq_id = 0,
messages = gb_trees:empty(),
acks = [],
confirms = gb_sets:new(),
publishing = 0}.
%% Property
prop_backing_queue_test() ->
?FORALL(Cmds, commands(?MODULE, initial_state()),
backing_queue_test(Cmds)).
backing_queue_test(Cmds) ->
{ok, FileSizeLimit} =
application:get_env(rabbit, msg_store_file_size_limit),
application:set_env(rabbit, msg_store_file_size_limit, 512,
infinity),
{ok, MaxJournal} =
application:get_env(rabbit, queue_index_max_journal_entries),
application:set_env(rabbit, queue_index_max_journal_entries, 128,
infinity),
{_H, #state{bqstate = BQ}, Res} = run_commands(?MODULE, Cmds),
application:set_env(rabbit, msg_store_file_size_limit,
FileSizeLimit, infinity),
application:set_env(rabbit, queue_index_max_journal_entries,
MaxJournal, infinity),
?BQMOD:delete_and_terminate(shutdown, BQ),
?WHENFAIL(
io:format("Result: ~p~n", [Res]),
aggregate(command_names(Cmds), Res =:= ok)).
%% Commands
%% Command frequencies are tuned so that queues are normally
%% reasonably short, but they may sometimes exceed
%% ?QUEUE_MAXLEN. Publish-multiple and purging cause extreme queue
%% lengths, so these have lower probabilities. Fetches/drops are
%% sufficiently frequent so that commands that need acktags get decent
%% coverage.
command(S) ->
frequency([{10, qc_publish(S)},
{1, qc_publish_delivered(S)},
{1, qc_publish_multiple(S)}, %% very slow
{9, qc_fetch(S)}, %% needed for ack and requeue
{6, qc_drop(S)}, %%
{15, qc_ack(S)},
{15, qc_requeue(S)},
{3, qc_set_ram_duration_target(S)},
{1, qc_ram_duration(S)},
{1, qc_drain_confirmed(S)},
{1, qc_dropwhile(S)},
{1, qc_is_empty(S)},
{1, qc_timeout(S)},
{1, qc_bump_credit(S)},
{1, qc_purge(S)},
{1, qc_fold(S)}]).
qc_publish(#state{bqstate = BQ}) ->
{call, ?BQMOD, publish,
[qc_message(),
#message_properties{needs_confirming = frequency([{1, true},
{20, false}]),
expiry = oneof([undefined | lists:seq(1, 10)]),
size = 10},
false, self(), noflow, BQ]}.
qc_publish_multiple(#state{}) ->
{call, ?MODULE, publish_multiple, [resize(?QUEUE_MAXLEN, pos_integer())]}.
qc_publish_delivered(#state{bqstate = BQ}) ->
{call, ?BQMOD, publish_delivered,
[qc_message(), #message_properties{size = 10}, self(), noflow, BQ]}.
qc_fetch(#state{bqstate = BQ}) ->
{call, ?BQMOD, fetch, [boolean(), BQ]}.
qc_drop(#state{bqstate = BQ}) ->
{call, ?BQMOD, drop, [boolean(), BQ]}.
qc_ack(#state{bqstate = BQ, acks = Acks}) ->
{call, ?BQMOD, ack, [rand_choice(proplists:get_keys(Acks)), BQ]}.
qc_requeue(#state{bqstate = BQ, acks = Acks}) ->
{call, ?BQMOD, requeue, [rand_choice(proplists:get_keys(Acks)), BQ]}.
qc_set_ram_duration_target(#state{bqstate = BQ}) ->
{call, ?BQMOD, set_ram_duration_target,
[oneof([0, 1, 2, resize(1000, pos_integer()), infinity]), BQ]}.
qc_ram_duration(#state{bqstate = BQ}) ->
{call, ?BQMOD, ram_duration, [BQ]}.
qc_drain_confirmed(#state{bqstate = BQ}) ->
{call, ?BQMOD, drain_confirmed, [BQ]}.
qc_dropwhile(#state{bqstate = BQ}) ->
{call, ?BQMOD, dropwhile, [fun dropfun/1, BQ]}.
qc_is_empty(#state{bqstate = BQ}) ->
{call, ?BQMOD, is_empty, [BQ]}.
qc_timeout(#state{bqstate = BQ}) ->
{call, ?MODULE, timeout, [BQ, ?TIMEOUT_LIMIT]}.
qc_bump_credit(#state{bqstate = BQ}) ->
{call, ?MODULE, bump_credit, [BQ]}.
qc_purge(#state{bqstate = BQ}) ->
{call, ?BQMOD, purge, [BQ]}.
qc_fold(#state{bqstate = BQ}) ->
{call, ?BQMOD, fold, [makefoldfun(pos_integer()), foldacc(), BQ]}.
%% Preconditions
%% Create long queues by only allowing publishing
precondition(#state{publishing = Count}, {call, _Mod, Fun, _Arg})
when Count > 0, Fun /= publish ->
false;
precondition(#state{acks = Acks}, {call, ?BQMOD, Fun, _Arg})
when Fun =:= ack; Fun =:= requeue ->
length(Acks) > 0;
precondition(#state{messages = Messages},
{call, ?BQMOD, publish_delivered, _Arg}) ->
gb_trees:is_empty(Messages);
precondition(_S, {call, ?BQMOD, _Fun, _Arg}) ->
true;
precondition(_S, {call, ?MODULE, timeout, _Arg}) ->
true;
precondition(_S, {call, ?MODULE, bump_credit, _Arg}) ->
true;
precondition(#state{len = Len}, {call, ?MODULE, publish_multiple, _Arg}) ->
Len < ?QUEUE_MAXLEN.
%% Model updates
next_state(S, BQ, {call, ?BQMOD, publish, [Msg, MsgProps, _Del, _Pid, _Flow, _BQ]}) ->
#state{len = Len,
messages = Messages,
confirms = Confirms,
publishing = PublishCount,
next_seq_id = NextSeq} = S,
MsgId = {call, erlang, element, [?RECORD_INDEX(id, basic_message), Msg]},
NeedsConfirm =
{call, erlang, element,
[?RECORD_INDEX(needs_confirming, message_properties), MsgProps]},
S#state{bqstate = BQ,
len = Len + 1,
next_seq_id = NextSeq + 1,
messages = gb_trees:insert(NextSeq, {MsgProps, Msg}, Messages),
publishing = {call, erlang, max, [0, {call, erlang, '-',
[PublishCount, 1]}]},
confirms = case eval(NeedsConfirm) of
true -> gb_sets:add(MsgId, Confirms);
_ -> Confirms
end};
next_state(S, _BQ, {call, ?MODULE, publish_multiple, [PublishCount]}) ->
S#state{publishing = PublishCount};
next_state(S, Res,
{call, ?BQMOD, publish_delivered,
[Msg, MsgProps, _Pid, _Flow, _BQ]}) ->
#state{confirms = Confirms, acks = Acks, next_seq_id = NextSeq} = S,
AckTag = {call, erlang, element, [1, Res]},
BQ1 = {call, erlang, element, [2, Res]},
MsgId = {call, erlang, element, [?RECORD_INDEX(id, basic_message), Msg]},
NeedsConfirm =
{call, erlang, element,
[?RECORD_INDEX(needs_confirming, message_properties), MsgProps]},
S#state{bqstate = BQ1,
next_seq_id = NextSeq + 1,
confirms = case eval(NeedsConfirm) of
true -> gb_sets:add(MsgId, Confirms);
_ -> Confirms
end,
acks = [{AckTag, {NextSeq, {MsgProps, Msg}}}|Acks]
};
next_state(S, Res, {call, ?BQMOD, fetch, [AckReq, _BQ]}) ->
next_state_fetch_and_drop(S, Res, AckReq, 3);
next_state(S, Res, {call, ?BQMOD, drop, [AckReq, _BQ]}) ->
next_state_fetch_and_drop(S, Res, AckReq, 2);
next_state(S, Res, {call, ?BQMOD, ack, [AcksArg, _BQ]}) ->
#state{acks = AcksState} = S,
BQ1 = {call, erlang, element, [2, Res]},
S#state{bqstate = BQ1,
acks = lists:foldl(fun proplists:delete/2, AcksState, AcksArg)};
next_state(S, Res, {call, ?BQMOD, requeue, [AcksArg, _V]}) ->
#state{messages = Messages, acks = AcksState} = S,
BQ1 = {call, erlang, element, [2, Res]},
Messages1 = lists:foldl(fun (AckTag, Msgs) ->
{SeqId, MsgPropsMsg} =
proplists:get_value(AckTag, AcksState),
gb_trees:insert(SeqId, MsgPropsMsg, Msgs)
end, Messages, AcksArg),
S#state{bqstate = BQ1,
len = gb_trees:size(Messages1),
messages = Messages1,
acks = lists:foldl(fun proplists:delete/2, AcksState, AcksArg)};
next_state(S, BQ, {call, ?BQMOD, set_ram_duration_target, _Args}) ->
S#state{bqstate = BQ};
next_state(S, Res, {call, ?BQMOD, ram_duration, _Args}) ->
BQ1 = {call, erlang, element, [2, Res]},
S#state{bqstate = BQ1};
next_state(S, Res, {call, ?BQMOD, drain_confirmed, _Args}) ->
BQ1 = {call, erlang, element, [2, Res]},
S#state{bqstate = BQ1};
next_state(S, Res, {call, ?BQMOD, dropwhile, _Args}) ->
BQ = {call, erlang, element, [2, Res]},
#state{messages = Messages} = S,
Msgs1 = drop_messages(Messages),
S#state{bqstate = BQ, len = gb_trees:size(Msgs1), messages = Msgs1};
next_state(S, _Res, {call, ?BQMOD, is_empty, _Args}) ->
S;
next_state(S, BQ, {call, ?MODULE, timeout, _Args}) ->
S#state{bqstate = BQ};
next_state(S, BQ, {call, ?MODULE, bump_credit, _Args}) ->
S#state{bqstate = BQ};
next_state(S, Res, {call, ?BQMOD, purge, _Args}) ->
BQ1 = {call, erlang, element, [2, Res]},
S#state{bqstate = BQ1, len = 0, messages = gb_trees:empty()};
next_state(S, Res, {call, ?BQMOD, fold, _Args}) ->
BQ1 = {call, erlang, element, [2, Res]},
S#state{bqstate = BQ1}.
%% Postconditions
postcondition(S, {call, ?BQMOD, fetch, _Args}, Res) ->
#state{messages = Messages, len = Len, acks = Acks, confirms = Confrms} = S,
case Res of
{{MsgFetched, _IsDelivered, AckTag}, _BQ} ->
{_SeqId, {_MsgProps, Msg}} = gb_trees:smallest(Messages),
MsgFetched =:= Msg andalso
not proplists:is_defined(AckTag, Acks) andalso
not gb_sets:is_element(AckTag, Confrms) andalso
Len =/= 0;
{empty, _BQ} ->
Len =:= 0
end;
postcondition(S, {call, ?BQMOD, drop, _Args}, Res) ->
#state{messages = Messages, len = Len, acks = Acks, confirms = Confrms} = S,
case Res of
{{MsgIdFetched, AckTag}, _BQ} ->
{_SeqId, {_MsgProps, Msg}} = gb_trees:smallest(Messages),
MsgId = eval({call, erlang, element,
[?RECORD_INDEX(id, basic_message), Msg]}),
MsgIdFetched =:= MsgId andalso
not proplists:is_defined(AckTag, Acks) andalso
not gb_sets:is_element(AckTag, Confrms) andalso
Len =/= 0;
{empty, _BQ} ->
Len =:= 0
end;
postcondition(S, {call, ?BQMOD, publish_delivered, _Args}, {AckTag, _BQ}) ->
#state{acks = Acks, confirms = Confrms} = S,
not proplists:is_defined(AckTag, Acks) andalso
not gb_sets:is_element(AckTag, Confrms);
postcondition(#state{len = Len}, {call, ?BQMOD, purge, _Args}, Res) ->
{PurgeCount, _BQ} = Res,
Len =:= PurgeCount;
postcondition(#state{len = Len}, {call, ?BQMOD, is_empty, _Args}, Res) ->
(Len =:= 0) =:= Res;
postcondition(S, {call, ?BQMOD, drain_confirmed, _Args}, Res) ->
#state{confirms = Confirms} = S,
{ReportedConfirmed, _BQ} = Res,
lists:all(fun (M) -> gb_sets:is_element(M, Confirms) end,
ReportedConfirmed);
postcondition(S, {call, ?BQMOD, fold, [FoldFun, Acc0, _BQ0]}, {Res, _BQ1}) ->
#state{messages = Messages} = S,
{_, Model} = lists:foldl(fun ({_SeqId, {_MsgProps, _Msg}}, {stop, Acc}) ->
{stop, Acc};
({_SeqId, {MsgProps, Msg}}, {cont, Acc}) ->
FoldFun(Msg, MsgProps, false, Acc)
end, {cont, Acc0}, gb_trees:to_list(Messages)),
true = Model =:= Res;
postcondition(#state{bqstate = BQ, len = Len}, {call, _M, _F, _A}, _Res) ->
?BQMOD:len(BQ) =:= Len.
%% Helpers
publish_multiple(_C) ->
ok.
timeout(BQ, 0) ->
BQ;
timeout(BQ, AtMost) ->
case ?BQMOD:needs_timeout(BQ) of
false -> BQ;
_ -> timeout(?BQMOD:timeout(BQ), AtMost - 1)
end.
bump_credit(BQ) ->
case credit_flow:blocked() of
false -> BQ;
true -> receive
{bump_credit, Msg} ->
credit_flow:handle_bump_msg(Msg),
?BQMOD:resume(BQ)
end
end.
qc_message_payload() -> ?SIZED(Size, resize(Size * Size, binary())).
qc_routing_key() -> noshrink(binary(10)).
qc_delivery_mode() -> oneof([1, 2]).
qc_message() -> qc_message(qc_delivery_mode()).
qc_message(DeliveryMode) ->
{call, rabbit_basic, message, [qc_default_exchange(),
qc_routing_key(),
#'P_basic'{delivery_mode = DeliveryMode},
qc_message_payload()]}.
qc_default_exchange() ->
{call, rabbit_misc, r, [<<>>, exchange, <<>>]}.
qc_variable_queue_init(Q) ->
{call, ?BQMOD, init,
[Q, new, function(2, {ok, []})]}.
qc_test_q() -> {call, rabbit_misc, r, [<<"/">>, queue, noshrink(binary(16))]}.
qc_test_queue() -> qc_test_queue(boolean()).
qc_test_queue(Durable) ->
#amqqueue{name = qc_test_q(),
durable = Durable,
auto_delete = false,
arguments = [],
pid = self()}.
rand_choice([]) -> [];
rand_choice(List) -> rand_choice(List, [], random:uniform(length(List))).
rand_choice(_List, Selection, 0) ->
Selection;
rand_choice(List, Selection, N) ->
Picked = lists:nth(random:uniform(length(List)), List),
rand_choice(List -- [Picked], [Picked | Selection],
N - 1).
makefoldfun(Size) ->
fun (Msg, _MsgProps, Unacked, Acc) ->
case {length(Acc) > Size, Unacked} of
{false, false} -> {cont, [Msg | Acc]};
{false, true} -> {cont, Acc};
{true, _} -> {stop, Acc}
end
end.
foldacc() -> [].
dropfun(Props) ->
Expiry = eval({call, erlang, element,
[?RECORD_INDEX(expiry, message_properties), Props]}),
Expiry =/= 1.
drop_messages(Messages) ->
case gb_trees:is_empty(Messages) of
true ->
Messages;
false -> {_Seq, MsgProps_Msg, M2} = gb_trees:take_smallest(Messages),
MsgProps = {call, erlang, element, [1, MsgProps_Msg]},
case dropfun(MsgProps) of
true -> drop_messages(M2);
false -> Messages
end
end.
next_state_fetch_and_drop(S, Res, AckReq, AckTagIdx) ->
#state{len = Len, messages = Messages, acks = Acks} = S,
ResultInfo = {call, erlang, element, [1, Res]},
BQ1 = {call, erlang, element, [2, Res]},
AckTag = {call, erlang, element, [AckTagIdx, ResultInfo]},
S1 = S#state{bqstate = BQ1},
case gb_trees:is_empty(Messages) of
true -> S1;
false -> {SeqId, MsgProp_Msg, M2} = gb_trees:take_smallest(Messages),
S2 = S1#state{len = Len - 1, messages = M2},
case AckReq of
true ->
S2#state{acks = [{AckTag, {SeqId, MsgProp_Msg}}|Acks]};
false ->
S2
end
end.
-else.
-export([prop_disabled/0]).
prop_disabled() ->
exit({compiled_without_proper,
"PropEr was not present during compilation of the test module. "
"Hence all tests are disabled."}).
-endif.

View File

@ -1,72 +0,0 @@
%% 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_runtime_parameters_test).
-behaviour(rabbit_runtime_parameter).
-behaviour(rabbit_policy_validator).
-include("rabbit.hrl").
-export([validate/5, notify/4, notify_clear/3]).
-export([register/0, unregister/0]).
-export([validate_policy/1]).
-export([register_policy_validator/0, unregister_policy_validator/0]).
%----------------------------------------------------------------------------
register() ->
rabbit_registry:register(runtime_parameter, <<"test">>, ?MODULE).
unregister() ->
rabbit_registry:unregister(runtime_parameter, <<"test">>).
validate(_, <<"test">>, <<"good">>, _Term, _User) -> ok;
validate(_, <<"test">>, <<"maybe">>, <<"good">>, _User) -> ok;
validate(_, <<"test">>, <<"admin">>, _Term, none) -> ok;
validate(_, <<"test">>, <<"admin">>, _Term, User) ->
case lists:member(administrator, User#user.tags) of
true -> ok;
false -> {error, "meh", []}
end;
validate(_, <<"test">>, _, _, _) -> {error, "meh", []}.
notify(_, _, _, _) -> ok.
notify_clear(_, _, _) -> ok.
%----------------------------------------------------------------------------
register_policy_validator() ->
rabbit_registry:register(policy_validator, <<"testeven">>, ?MODULE),
rabbit_registry:register(policy_validator, <<"testpos">>, ?MODULE).
unregister_policy_validator() ->
rabbit_registry:unregister(policy_validator, <<"testeven">>),
rabbit_registry:unregister(policy_validator, <<"testpos">>).
validate_policy([{<<"testeven">>, Terms}]) when is_list(Terms) ->
case length(Terms) rem 2 =:= 0 of
true -> ok;
false -> {error, "meh", []}
end;
validate_policy([{<<"testpos">>, Terms}]) when is_list(Terms) ->
case lists:all(fun (N) -> is_integer(N) andalso N > 0 end, Terms) of
true -> ok;
false -> {error, "meh", []}
end;
validate_policy(_) ->
{error, "meh", []}.

File diff suppressed because it is too large Load Diff

View File

@ -1,58 +0,0 @@
%% 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_tests_event_receiver).
-export([start/3, stop/0]).
-export([init/1, handle_call/2, handle_event/2, handle_info/2,
terminate/2, code_change/3]).
-include("rabbit.hrl").
start(Pid, Nodes, Types) ->
Oks = [ok || _ <- Nodes],
{Oks, _} = rpc:multicall(Nodes, gen_event, add_handler,
[rabbit_event, ?MODULE, [Pid, Types]]).
stop() ->
gen_event:delete_handler(rabbit_event, ?MODULE, []).
%%----------------------------------------------------------------------------
init([Pid, Types]) ->
{ok, {Pid, Types}}.
handle_call(_Request, State) ->
{ok, not_understood, State}.
handle_event(Event = #event{type = Type}, State = {Pid, Types}) ->
case lists:member(Type, Types) of
true -> Pid ! Event;
false -> ok
end,
{ok, State}.
handle_info(_Info, State) ->
{ok, State}.
terminate(_Arg, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%----------------------------------------------------------------------------

View File

@ -1,75 +0,0 @@
%% 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_tests).
-behaviour(supervisor2).
-export([test_all/0, start_link/0]).
-export([init/1]).
test_all() ->
ok = check_shutdown(stop, 200, 200, 2000),
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.
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]}]}}.

View File

@ -1,93 +0,0 @@
%% 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(test_sup).
-behaviour(supervisor2).
-export([test_supervisor_delayed_restart/0,
init/1, start_child/0]).
%%----------------------------------------------------------------------------
-ifdef(use_specs).
-spec(test_supervisor_delayed_restart/0 :: () -> 'passed').
-endif.
%%----------------------------------------------------------------------------
%% Public API
%%----------------------------------------------------------------------------
test_supervisor_delayed_restart() ->
passed = with_sup(simple_one_for_one,
fun (SupPid) ->
{ok, _ChildPid} =
supervisor2:start_child(SupPid, []),
test_supervisor_delayed_restart(SupPid)
end),
passed = with_sup(one_for_one, fun test_supervisor_delayed_restart/1).
test_supervisor_delayed_restart(SupPid) ->
ok = ping_child(SupPid),
ok = exit_child(SupPid),
timer:sleep(100),
ok = ping_child(SupPid),
ok = exit_child(SupPid),
timer:sleep(100),
timeout = ping_child(SupPid),
timer:sleep(1010),
ok = ping_child(SupPid),
passed.
with_sup(RestartStrategy, Fun) ->
{ok, SupPid} = supervisor2:start_link(?MODULE, [RestartStrategy]),
Res = Fun(SupPid),
unlink(SupPid),
exit(SupPid, shutdown),
Res.
init([RestartStrategy]) ->
{ok, {{RestartStrategy, 1, 1},
[{test, {test_sup, start_child, []}, {permanent, 1},
16#ffffffff, worker, [test_sup]}]}}.
start_child() ->
{ok, proc_lib:spawn_link(fun run_child/0)}.
ping_child(SupPid) ->
Ref = make_ref(),
with_child_pid(SupPid, fun(ChildPid) -> ChildPid ! {ping, Ref, self()} end),
receive {pong, Ref} -> ok
after 1000 -> timeout
end.
exit_child(SupPid) ->
with_child_pid(SupPid, fun(ChildPid) -> exit(ChildPid, abnormal) end),
ok.
with_child_pid(SupPid, Fun) ->
case supervisor2:which_children(SupPid) of
[{_Id, undefined, worker, [test_sup]}] -> ok;
[{_Id, ChildPid, worker, [test_sup]}] -> Fun(ChildPid);
[] -> ok
end.
run_child() ->
receive {ping, Ref, Pid} -> Pid ! {pong, Ref},
run_child()
end.

View File

@ -1,35 +0,0 @@
%% 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_tests).
-export([all_tests/0]).
%% ---------------------------------------------------------------------------
%% Tests
%% ---------------------------------------------------------------------------
all_tests() ->
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}}]),
passed.