summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEmile Joubert <emile@rabbitmq.com>2011-06-21 18:30:07 +0100
committerEmile Joubert <emile@rabbitmq.com>2011-06-21 18:30:07 +0100
commit6455387577aaced51e14984e1e75c73bd2b79449 (patch)
tree3248873af0721e4a3fbe2ec6ff7cf7f7a41c952a /src
parent11936a400994d2a447f0c3aad7b5fdc779f858dc (diff)
downloadrabbitmq-server-git-6455387577aaced51e14984e1e75c73bd2b79449.tar.gz
More realistic tests
Diffstat (limited to 'src')
-rw-r--r--src/rabbit_backing_queue_qc.erl144
1 files changed, 83 insertions, 61 deletions
diff --git a/src/rabbit_backing_queue_qc.erl b/src/rabbit_backing_queue_qc.erl
index 95832842dd..f5cd7f95b1 100644
--- a/src/rabbit_backing_queue_qc.erl
+++ b/src/rabbit_backing_queue_qc.erl
@@ -15,9 +15,14 @@
%%
-module(rabbit_backing_queue_qc).
+-include("rabbit.hrl").
+-include("rabbit_framing.hrl").
+-include_lib("proper/include/proper.hrl").
-behaviour(proper_statem).
+-define(BQMOD, rabbit_variable_queue).
+
-export([initial_state/0, command/1, precondition/2, postcondition/3,
next_state/3]).
@@ -28,109 +33,125 @@
messages,
acks}).
--include("rabbit.hrl").
--include("rabbit_framing.hrl").
--include_lib("proper/include/proper.hrl").
initial_state() ->
VQ = qc_variable_queue_init(qc_test_queue()),
- #state{bqstate=VQ, messages = [], acks = []}.
+ #state{bqstate=VQ, messages = queue:new(), acks = []}.
prop_backing_queue_test() ->
?FORALL(Cmds, commands(?MODULE, initial_state()),
begin
- {_H, _S, Res} = run_commands(?MODULE, Cmds),
+ {_H, #state{bqstate = VQ}, Res} = run_commands(?MODULE, Cmds),
+ rabbit_variable_queue:delete_and_terminate(shutdown, VQ),
?WHENFAIL(
- io:format("Result: ~p~n", [Res]),
- aggregate(command_names(Cmds), Res =:= ok))
+ io:format("Result: ~p~n", [Res]),
+ aggregate(command_names(Cmds), Res =:= ok))
end).
%% Commands
-command(S) ->
- frequency([{5, qc_publish(S)},
- {3, qc_fetch(S)},
- {2, qc_ack(S)},
- {2, qc_requeue(S)},
- {1, qc_ram(S)}]).
+command(#state{bqstate = VQ} = S) ->
+ ?SIZED(Size,
+ frequency([{Size, qc_publish(S)},
+ {Size, qc_fetch(S)},
+ {Size, qc_ack(S)},
+ {Size, qc_requeue(S)},
+ {Size, qc_ram(S)},
+ {1, {call, ?BQMOD, purge, [VQ]}}])).
qc_publish(#state{bqstate = VQ}) ->
- {call, rabbit_variable_queue, publish,
- [qc_message(), #message_properties{}, self(), VQ]}.
+ {call, ?BQMOD, publish,
+ [qc_message(), #message_properties{}, self(), VQ]}.
qc_fetch(#state{bqstate = VQ}) ->
- {call, rabbit_variable_queue, fetch, [true, VQ]}.
+ {call, ?BQMOD, fetch, [boolean(), VQ]}.
qc_ack(#state{bqstate = VQ, acks = Acks}) ->
- {call, rabbit_variable_queue, ack, [sublist(Acks), VQ]}.
+ {call, ?BQMOD, ack, [rand_choice(proplists:get_keys(Acks)), VQ]}.
qc_requeue(#state{bqstate = VQ, acks = Acks}) ->
- {call, rabbit_variable_queue, requeue,
- [sublist(Acks), fun(MsgOpts) -> MsgOpts end, VQ]}.
+ {call, ?BQMOD, requeue,
+ [rand_choice(proplists:get_keys(Acks)), fun(MsgOpts) -> MsgOpts end, VQ]}.
qc_ram(#state{bqstate = VQ}) ->
- {call, rabbit_variable_queue, set_ram_duration_target,
- [oneof([0, infinity]), VQ]}.
+ {call, ?BQMOD, set_ram_duration_target,
+ [oneof([0, infinity]), VQ]}.
%% Preconditions
-precondition(_S, {call, rabbit_variable_queue, Fun, _Arg})
- when Fun =:= publish; Fun =:= fetch; Fun =:= set_ram_duration_target ->
- true;
-precondition(#state{acks = Acks}, {call, rabbit_variable_queue, Fun, _Arg})
+precondition(#state{acks = Acks}, {call, ?BQMOD, Fun, _Arg})
when Fun =:= ack; Fun =:= requeue ->
- length(Acks) > 0.
+ length(Acks) > 0;
+precondition(_S, {call, ?BQMOD, _Fun, _Arg}) ->
+ true.
%% Next state
-next_state(S, VQ, {call, rabbit_variable_queue, publish,
- [Msg, _MsgProps, _Pid, _VQ]}) ->
+next_state(S, VQ, {call, ?BQMOD, publish, [Msg, _MsgProps, _Pid, _VQ]}) ->
#state{messages = Messages} = S,
- S#state{bqstate=VQ, messages= [Msg | Messages]};
-
-next_state(S, Res, {call, rabbit_variable_queue, fetch, [AckReq, _VQ]}) ->
- #state{messages = M, acks = Acks} = S,
- ResultDetails = {call, erlang, element, [1, Res]},
- AckTag = {call, erlang, element, [3, ResultDetails]},
- VQ1 = {call, erlang, element, [2, Res]},
- S1 = S#state{bqstate = VQ1},
- case M of
- [] -> S1;
- [_|_] -> Msg = lists:last(M),
- case AckReq of
- true -> S1#state{messages = M -- [Msg],
- acks = Acks ++ [AckTag]};
- false -> throw(non_ack_not_supported)
- end
+ S#state{bqstate = VQ, messages = queue:in(Msg, Messages)};
+
+next_state(S, Res, {call, ?BQMOD, fetch, [AckReq, _VQ]}) ->
+ #state{messages = Messages, acks = Acks} = S,
+ ResultInfo = {call, erlang, element, [1, Res]},
+ VQ1 = {call, erlang, element, [2, Res]},
+ AckTag = {call, erlang, element, [3, ResultInfo]},
+ S1 = S#state{bqstate = VQ1},
+ case queue:out(Messages) of
+ {empty, _M2} ->
+ S1;
+ {{value, Msg}, M2} ->
+ S2 = S1#state{messages = M2},
+ case AckReq of
+ true -> S2#state{acks = Acks ++ [{AckTag, Msg}]};
+ false -> S2
+ end
end;
-next_state(S, Res, {call, rabbit_variable_queue, ack, [AcksArg, _VQ]}) ->
+next_state(S, Res, {call, ?BQMOD, ack, [AcksArg, _VQ]}) ->
#state{acks = AcksState} = S,
VQ1 = {call, erlang, element, [2, Res]},
S#state{bqstate = VQ1,
- acks = AcksState -- AcksArg};
+ acks = propvals_by_keys(AcksState, AcksArg)};
-next_state(S, Res, {call, rabbit_variable_queue, requeue, [AcksArg, _F, _V]}) ->
+next_state(S, Res, {call, ?BQMOD, requeue, [AcksArg, _F, _V]}) ->
#state{messages = Messages, acks = AcksState} = S,
VQ1 = {call, erlang, element, [2, Res]},
+ RequeueMsgs = [proplists:get_value(Key, AcksState) || Key <- AcksArg ],
S#state{bqstate = VQ1,
- messages = AcksArg ++ Messages,
- acks = AcksState -- AcksArg};
+ messages = queue:join(Messages, queue:from_list(RequeueMsgs)),
+ acks = propvals_by_keys(AcksState, AcksArg)};
+
+next_state(S, VQ, {call, ?BQMOD, set_ram_duration_target, _A}) ->
+ S#state{bqstate = VQ};
-next_state(S, VQ, {call, rabbit_variable_queue, set_ram_duration_target, _A}) ->
- S#state{bqstate = VQ}.
+next_state(S, Res, {call, ?BQMOD, purge, _A}) ->
+ VQ1 = {call, erlang, element, [2, Res]},
+ S#state{bqstate = VQ1, messages = queue:new()}.
%% Postconditions
+postcondition(#state{messages = Messages}, {call, ?BQMOD, fetch, _Args}, Res) ->
+ case Res of
+ {{MsgFetched, _IsDelivered, _AckTag, _Remaining_Len}, _VQ} ->
+ MsgFetched =:= queue:head(Messages);
+ {empty, _VQ} ->
+ queue:len(Messages) =:= 0
+ end;
+
+postcondition(#state{messages = Messages}, {call, ?BQMOD, purge, _Args}, Res) ->
+ {PurgeCount, _VQ} = Res,
+ queue:len(Messages) =:= PurgeCount;
+
postcondition(#state{bqstate = VQ,
messages = Messages},
- {call, _Mod, _Fun, _Args}, _Res) ->
- rabbit_variable_queue:len(VQ) =:= length(Messages).
+ {call, ?BQMOD, _Fun, _Args}, _Res) ->
+ ?BQMOD:len(VQ) =:= queue:len(Messages).
%% Helpers
qc_message_payload() ->
- binary().
+ ?SIZED(Size, resize(Size * Size, binary())).
qc_routing_key() ->
noshrink(binary(10)).
@@ -152,7 +173,7 @@ qc_default_exchange() ->
{call, rabbit_misc, r, [<<>>, exchange, <<>>]}.
qc_variable_queue_init(Q) ->
- {call, rabbit_variable_queue, init,
+ {call, ?BQMOD, init,
[Q, false, nop(2), nop(2), nop(2), nop(1)]}.
qc_test_q() ->
@@ -170,12 +191,13 @@ qc_test_queue(Durable) ->
nop(N) -> function(N, ok).
-sublist(List) ->
+propvals_by_keys(Props, Keys) ->
+ lists:filter(fun ({Key, _Msg}) ->
+ not lists:member(Key, Keys)
+ end, Props).
+
+rand_choice(List) ->
case List of
[] -> [];
- _ -> Item = lists:nth(random:uniform(length(List)), List),
- case random:uniform(3) of
- 1 -> [Item];
- _ -> [Item | sublist(List -- [Item])]
- end
+ _ -> [lists:nth(random:uniform(length(List)), List)]
end.