Fix broken EUnit tests (been in PULSE land too long)

This commit is contained in:
Scott Lystig Fritchie 2014-02-25 16:15:01 +09:00
parent 20a2a51649
commit a64a09338d
6 changed files with 151 additions and 65 deletions

View file

@ -64,7 +64,10 @@ append_page(Sequencer, P, Page, Retries) when Retries < 50 ->
write_single_page(#proj{epoch=Epoch} = P, LPN, Page) -> write_single_page(#proj{epoch=Epoch} = P, LPN, Page) ->
Chain = project_to_chain(LPN, P), Chain = project_to_chain(LPN, P),
write_single_page_to_chain(Chain, Chain, Epoch, LPN, Page, 1, ok). write_single_page_to_chain(Chain, Chain, Epoch, LPN, Page, 1).
write_single_page_to_chain(Chain, Chain, Epoch, LPN, Page, Nth) ->
write_single_page_to_chain(Chain, Chain, Epoch, LPN, Page, Nth, ok).
write_single_page_to_chain([], _Chain, _Epoch, _LPN, _Page, _Nth, Reply) -> write_single_page_to_chain([], _Chain, _Epoch, _LPN, _Page, _Nth, Reply) ->
Reply; Reply;

View file

@ -93,14 +93,15 @@ trim(Pid, Epoch, LogicalPN)
fill(Pid, Epoch, LogicalPN) fill(Pid, Epoch, LogicalPN)
when is_integer(Epoch), Epoch > 0, is_integer(LogicalPN), LogicalPN > 0 -> when is_integer(Epoch), Epoch > 0, is_integer(LogicalPN), LogicalPN > 0 ->
g_call(Pid, {fill, Epoch, LogicalPN}, infinity). Res = g_call(Pid, {fill, Epoch, LogicalPN}, infinity),
undo_special_pulse_test_result(Res).
g_call(Pid, Arg, Timeout) -> g_call(Pid, Arg, Timeout) ->
LC1 = lamport_clock:get(), LC1 = lclock_get(),
msc(self(), Pid, Arg), msc(self(), Pid, Arg),
{Res, LC2} = gen_server:call(Pid, {Arg, LC1}, Timeout), {Res, LC2} = gen_server:call(Pid, {Arg, LC1}, Timeout),
msc(Pid, self(), Res), msc(Pid, self(), Res),
lamport_clock:update(LC2), lclock_update(LC2),
Res. Res.
-ifdef(TEST). -ifdef(TEST).
@ -119,7 +120,7 @@ get__trim_watermark(Pid) ->
%%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%%
init({Dir, ExpPageSize, ExpMaxMem}) -> init({Dir, ExpPageSize, ExpMaxMem}) ->
lamport_clock:init(), lclock_init(),
MemFile = memfile_path(Dir), MemFile = memfile_path(Dir),
filelib:ensure_dir(MemFile), filelib:ensure_dir(MemFile),
@ -157,11 +158,11 @@ handle_call(Call, From, #state{max_logical_page=unknown} = State) ->
handle_call({{write, ClientEpoch, _LogicalPN, _PageBin}, LC1}, _From, handle_call({{write, ClientEpoch, _LogicalPN, _PageBin}, LC1}, _From,
#state{min_epoch=MinEpoch} = State) #state{min_epoch=MinEpoch} = State)
when ClientEpoch < MinEpoch -> when ClientEpoch < MinEpoch ->
LC2 = lamport_clock:update(LC1), LC2 = lclock_update(LC1),
{reply, {error_badepoch, LC2}, State}; {reply, {error_badepoch, LC2}, State};
handle_call({{write, _ClientEpoch, LogicalPN, PageBin}, LC1}, _From, handle_call({{write, _ClientEpoch, LogicalPN, PageBin}, LC1}, _From,
#state{max_logical_page=MLPN} = State) -> #state{max_logical_page=MLPN} = State) ->
LC2 = lamport_clock:update(LC1), LC2 = lclock_update(LC1),
case check_write(LogicalPN, PageBin, State) of case check_write(LogicalPN, PageBin, State) of
{ok, Offset} -> {ok, Offset} ->
ok = write_page(Offset, LogicalPN, PageBin, State), ok = write_page(Offset, LogicalPN, PageBin, State),
@ -176,20 +177,20 @@ handle_call({{write, _ClientEpoch, LogicalPN, PageBin}, LC1}, _From,
handle_call({{read, ClientEpoch, _LogicalPN}, LC1}, _From, handle_call({{read, ClientEpoch, _LogicalPN}, LC1}, _From,
#state{min_epoch=MinEpoch} = State) #state{min_epoch=MinEpoch} = State)
when ClientEpoch < MinEpoch -> when ClientEpoch < MinEpoch ->
LC2 = lamport_clock:update(LC1), LC2 = lclock_update(LC1),
{reply, {error_badepoch, LC2}, State}; {reply, {error_badepoch, LC2}, State};
handle_call({{read, _ClientEpoch, LogicalPN}, LC1}, _From, State) -> handle_call({{read, _ClientEpoch, LogicalPN}, LC1}, _From, State) ->
LC2 = lamport_clock:update(LC1), LC2 = lclock_update(LC1),
Reply = read_page(LogicalPN, State), Reply = read_page(LogicalPN, State),
?EVENT_LOG({flu, read, self(), LogicalPN, Reply}), ?EVENT_LOG({flu, read, self(), LogicalPN, Reply}),
{reply, {Reply, LC2}, State}; {reply, {Reply, LC2}, State};
handle_call({{seal, ClientEpoch}, LC1}, _From, #state{min_epoch=MinEpoch} = State) handle_call({{seal, ClientEpoch}, LC1}, _From, #state{min_epoch=MinEpoch} = State)
when ClientEpoch =< MinEpoch -> when ClientEpoch =< MinEpoch ->
LC2 = lamport_clock:update(LC1), LC2 = lclock_update(LC1),
{reply, {error_badepoch, LC2}, State}; {reply, {error_badepoch, LC2}, State};
handle_call({{seal, ClientEpoch}, LC1}, _From, #state{max_logical_page=MLPN}=State) -> handle_call({{seal, ClientEpoch}, LC1}, _From, #state{max_logical_page=MLPN}=State) ->
LC2 = lamport_clock:update(LC1), LC2 = lclock_update(LC1),
NewState = State#state{min_epoch=ClientEpoch}, NewState = State#state{min_epoch=ClientEpoch},
ok = write_hard_state(NewState), ok = write_hard_state(NewState),
{reply, {{ok, MLPN}, LC2}, NewState}; {reply, {{ok, MLPN}, LC2}, NewState};
@ -197,10 +198,10 @@ handle_call({{seal, ClientEpoch}, LC1}, _From, #state{max_logical_page=MLPN}=Sta
handle_call({{trim, ClientEpoch, _LogicalPN}, LC1}, _From, handle_call({{trim, ClientEpoch, _LogicalPN}, LC1}, _From,
#state{min_epoch=MinEpoch} = State) #state{min_epoch=MinEpoch} = State)
when ClientEpoch < MinEpoch -> when ClientEpoch < MinEpoch ->
LC2 = lamport_clock:update(LC1), LC2 = lclock_update(LC1),
{reply, {error_badepoch, LC2}, State}; {reply, {error_badepoch, LC2}, State};
handle_call({{trim, _ClientEpoch, LogicalPN}, LC1}, _From, State) -> handle_call({{trim, _ClientEpoch, LogicalPN}, LC1}, _From, State) ->
LC2 = lamport_clock:update(LC1), LC2 = lclock_update(LC1),
{Reply, NewState} = do_trim_or_fill(trim, LogicalPN, State), {Reply, NewState} = do_trim_or_fill(trim, LogicalPN, State),
?EVENT_LOG({flu, trim, self(), LogicalPN, Reply}), ?EVENT_LOG({flu, trim, self(), LogicalPN, Reply}),
{reply, {Reply, LC2}, NewState}; {reply, {Reply, LC2}, NewState};
@ -208,10 +209,10 @@ handle_call({{trim, _ClientEpoch, LogicalPN}, LC1}, _From, State) ->
handle_call({{fill, ClientEpoch, _LogicalPN}, LC1}, _From, handle_call({{fill, ClientEpoch, _LogicalPN}, LC1}, _From,
#state{min_epoch=MinEpoch} = State) #state{min_epoch=MinEpoch} = State)
when ClientEpoch < MinEpoch -> when ClientEpoch < MinEpoch ->
LC2 = lamport_clock:update(LC1), LC2 = lclock_update(LC1),
{reply, {error_badepoch, LC2}, State}; {reply, {error_badepoch, LC2}, State};
handle_call({{fill, _ClientEpoch, LogicalPN}, LC1}, _From, State) -> handle_call({{fill, _ClientEpoch, LogicalPN}, LC1}, _From, State) ->
LC2 = lamport_clock:update(LC1), LC2 = lclock_update(LC1),
{Reply, NewState} = do_trim_or_fill(fill, LogicalPN, State), {Reply, NewState} = do_trim_or_fill(fill, LogicalPN, State),
?EVENT_LOG({flu, fill, self(), LogicalPN, Reply}), ?EVENT_LOG({flu, fill, self(), LogicalPN, Reply}),
{reply, {Reply, LC2}, NewState}; {reply, {Reply, LC2}, NewState};
@ -439,3 +440,27 @@ msc(_From, _To, _Tag) ->
msc(_From, _To, _Tag) -> msc(_From, _To, _Tag) ->
ok. ok.
-endif. % PULSE_HACkING -endif. % PULSE_HACkING
-ifdef(PULSE).
lclock_init() ->
lamport_clock:init().
lclock_get() ->
lamport_clock:get().
lclock_update(LC) ->
lamport_clock:update(LC).
-else. % PULSE
lclock_init() ->
ok.
lclock_get() ->
ok.
lclock_update(_LC) ->
ok.
-endif. % PLUSE

View file

@ -33,6 +33,7 @@
-ifdef(TEST). -ifdef(TEST).
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
-compile(export_all).
-ifdef(PULSE). -ifdef(PULSE).
-compile({parse_transform, pulse_instrument}). -compile({parse_transform, pulse_instrument}).
-endif. -endif.
@ -50,15 +51,15 @@ stop(Pid) ->
gen_server:call(Pid, stop, infinity). gen_server:call(Pid, stop, infinity).
get(Pid, NumPages) -> get(Pid, NumPages) ->
{LPN, LC} = gen_server:call(Pid, {get, NumPages, lamport_clock:get()}, {LPN, LC} = gen_server:call(Pid, {get, NumPages, lclock_get()},
infinity), infinity),
lamport_clock:update(LC), lclock_update(LC),
LPN. LPN.
%%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%%
init({FLUs, TypeOrSeed}) -> init({FLUs, TypeOrSeed}) ->
lamport_clock:init(), lclock_init(),
MLP = get_max_logical_page(FLUs), MLP = get_max_logical_page(FLUs),
if TypeOrSeed == standard -> if TypeOrSeed == standard ->
{ok, MLP + 1}; {ok, MLP + 1};
@ -69,10 +70,10 @@ init({FLUs, TypeOrSeed}) ->
end. end.
handle_call({get, NumPages, LC}, _From, MLP) when is_integer(MLP) -> handle_call({get, NumPages, LC}, _From, MLP) when is_integer(MLP) ->
NewLC = lamport_clock:update(LC), NewLC = lclock_update(LC),
{reply, {MLP, NewLC}, MLP + NumPages}; {reply, {MLP, NewLC}, MLP + NumPages};
handle_call({get, NumPages, LC}, _From, {MLP, BadPercent, MaxDifference}) -> handle_call({get, NumPages, LC}, _From, {MLP, BadPercent, MaxDifference}) ->
NewLC = lamport_clock:update(LC), NewLC = lclock_update(LC),
Fudge = case random:uniform(100) of Fudge = case random:uniform(100) of
N when N < BadPercent -> N when N < BadPercent ->
random:uniform(MaxDifference * 2) - MaxDifference; random:uniform(MaxDifference * 2) - MaxDifference;
@ -94,7 +95,7 @@ handle_info(_Info, MLP) ->
{noreply, MLP}. {noreply, MLP}.
terminate(_Reason, _MLP) -> terminate(_Reason, _MLP) ->
%% io:format(user, "C=~w,", [lamport_clock:get()]), %% io:format(user, "C=~w,", [lclock_get()]),
ok. ok.
code_change(_OldVsn, MLP, _Extra) -> code_change(_OldVsn, MLP, _Extra) ->
@ -107,51 +108,26 @@ get_max_logical_page(FLUs) ->
FLU <- FLUs, FLU <- FLUs,
{ok, Ps} <- [corfurl_flu:status(FLU)]]). {ok, Ps} <- [corfurl_flu:status(FLU)]]).
%%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% -ifdef(PULSE).
-ifdef(TEST). lclock_init() ->
-ifndef(PULSE). lamport_clock:init().
smoke_test() -> lclock_get() ->
BaseDir = "/tmp/" ++ atom_to_list(?MODULE) ++ ".", lamport_clock:get().
PageSize = 8,
NumPages = 500,
NumFLUs = 4,
MyDir = fun(X) -> BaseDir ++ integer_to_list(X) end,
Del = fun() -> [ok = corfurl_util:delete_dir(MyDir(X)) ||
X <- lists:seq(1, NumFLUs)] end,
Del(), lclock_update(LC) ->
FLUs = [begin lamport_clock:update(LC).
element(2, corfurl_flu:start_link(MyDir(X),
PageSize, NumPages*PageSize))
end || X <- lists:seq(1, NumFLUs)],
FLUsNums = lists:zip(FLUs, lists:seq(1, NumFLUs)),
try -else. % PULSE
[ok = corfurl_flu:write(FLU, 1, PageNum, <<42:(8*8)>>) ||
{FLU, PageNum} <- FLUsNums],
MLP0 = NumFLUs,
NumFLUs = get_max_logical_page(FLUs),
%% Excellent. Now let's start the sequencer and see if it gets lclock_init() ->
%% the same answer. If yes, then the first get will return MLP1, ok.
%% yadda yadda.
MLP1 = MLP0 + 1,
MLP3 = MLP0 + 3,
MLP4 = MLP0 + 4,
{ok, Sequencer} = start_link(FLUs),
try
MLP1 = get(Sequencer, 2),
MLP3 = get(Sequencer, 1),
MLP4 = get(Sequencer, 1)
after
stop(Sequencer)
end
after
[ok = corfurl_flu:stop(FLU) || FLU <- FLUs],
Del()
end.
-endif. % not PULSE lclock_get() ->
-endif. % TEST ok.
lclock_update(_LC) ->
ok.
-endif. % PLUSE

View file

@ -505,6 +505,8 @@ check_trace(Trace0, _Cmds, _Seed) ->
?QC_FMT("*Trace: ~p\n", [Trace]), ?QC_FMT("*Trace: ~p\n", [Trace]),
?QC_FMT("*ModsReads: ~p\n", [eqc_temporal:unions([Mods,Reads])]), ?QC_FMT("*ModsReads: ~p\n", [eqc_temporal:unions([Mods,Reads])]),
?QC_FMT("*InvalidTtns: ~p\n", [InvalidTransitions]), ?QC_FMT("*InvalidTtns: ~p\n", [InvalidTransitions]),
?QC_FMT("*ValuesR: ~p\n", [eqc_temporal:unions([ValuesR, StartsDones])]),
?QC_FMT("*Calls: ~p\n", [Calls]),
?QC_FMT("*BadReads: ~p\n", [BadReads]) ?QC_FMT("*BadReads: ~p\n", [BadReads])
end, end,
conjunction( conjunction(

View file

@ -0,0 +1,80 @@
%% -------------------------------------------------------------------
%%
%% Copyright (c) 2014 Basho Technologies, Inc. All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License. You may obtain
%% a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------
-module(corfurl_sequencer_test).
-compile(export_all).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-compile(export_all).
-ifdef(PULSE).
-compile({parse_transform, pulse_instrument}).
-endif.
-endif.
-define(M, corfurl_sequencer).
-ifdef(TEST).
-ifndef(PULSE).
smoke_test() ->
BaseDir = "/tmp/" ++ atom_to_list(?MODULE) ++ ".",
PageSize = 8,
NumPages = 500,
NumFLUs = 4,
MyDir = fun(X) -> BaseDir ++ integer_to_list(X) end,
Del = fun() -> [ok = corfurl_util:delete_dir(MyDir(X)) ||
X <- lists:seq(1, NumFLUs)] end,
Del(),
FLUs = [begin
element(2, corfurl_flu:start_link(MyDir(X),
PageSize, NumPages*PageSize))
end || X <- lists:seq(1, NumFLUs)],
FLUsNums = lists:zip(FLUs, lists:seq(1, NumFLUs)),
try
[ok = corfurl_flu:write(FLU, 1, PageNum, <<42:(8*8)>>) ||
{FLU, PageNum} <- FLUsNums],
MLP0 = NumFLUs,
NumFLUs = ?M:get_max_logical_page(FLUs),
%% Excellent. Now let's start the sequencer and see if it gets
%% the same answer. If yes, then the first get will return MLP1,
%% yadda yadda.
MLP1 = MLP0 + 1,
MLP3 = MLP0 + 3,
MLP4 = MLP0 + 4,
{ok, Sequencer} = ?M:start_link(FLUs),
try
MLP1 = ?M:get(Sequencer, 2),
MLP3 = ?M:get(Sequencer, 1),
MLP4 = ?M:get(Sequencer, 1)
after
?M:stop(Sequencer)
end
after
[ok = corfurl_flu:stop(FLU) || FLU <- FLUs],
Del()
end.
-endif. % not PULSE
-endif. % TEST

View file

@ -106,7 +106,7 @@ smoke1_test() ->
%% Simulate a failed write to the chain. %% Simulate a failed write to the chain.
[F6a, F6b, F6c] = Chain6 = ?M:project_to_chain(6, P1), [F6a, F6b, F6c] = Chain6 = ?M:project_to_chain(6, P1),
NotHead6 = [F6b, F6c], NotHead6 = [F6b, F6c],
ok = ?M:write_single_page_to_chain([F6a], Epoch, 6, Pg6, 1), ok = ?M:write_single_page_to_chain([F6a], [F6a], Epoch, 6, Pg6, 1),
%% Does the chain look as expected? %% Does the chain look as expected?
{ok, Pg6} = corfurl_flu:read(?M:flu_pid(F6a), Epoch, 6), {ok, Pg6} = corfurl_flu:read(?M:flu_pid(F6a), Epoch, 6),