Merge pull request #45 from basho/ku/file-reopen

Add stop and trim command to eqc_statem test on file_proxy
This commit is contained in:
UENISHI Kota 2015-11-19 09:45:41 +09:00
commit fd649c00d2

View file

@ -31,6 +31,7 @@
-define(QC_OUT(P), -define(QC_OUT(P),
eqc:on_output(fun(Str, Args) -> io:format(user, Str, Args) end, P)). eqc:on_output(fun(Str, Args) -> io:format(user, Str, Args) end, P)).
-define(TESTDIR, "./eqc").
%% EUNIT TEST DEFINITION %% EUNIT TEST DEFINITION
eqc_test_() -> eqc_test_() ->
@ -106,13 +107,20 @@ get_written_interval(L) ->
%% INITIALIZATION %% INITIALIZATION
-record(state, {pid, prev_extra = 0, -record(state, {pid, prev_extra = 0,
filename = undefined,
planned_writes=[], planned_writes=[],
planned_trims=[], planned_trims=[],
written=[], written=[],
trimmed=[]}). trimmed=[]}).
initial_state() -> #state{written=[{0,1024}]}. initial_state() ->
initial_state(I, T) -> #state{written=[{0,1024}], {_, _, MS} = os:timestamp(),
Filename = test_server:temp_name("eqc_data") ++ "." ++ integer_to_list(MS),
#state{filename=Filename, written=[{0,1024}]}.
initial_state(I, T) ->
S=initial_state(),
S#state{written=[{0,1024}],
planned_writes=I, planned_writes=I,
planned_trims=T}. planned_trims=T}.
@ -136,11 +144,6 @@ get_overlaps(Offset, Len, [{Pos, Sz} = Ck|T], Acc0)
(Pos < Offset + Len andalso Offset + Len < Pos + Sz) -> (Pos < Offset + Len andalso Offset + Len < Pos + Sz) ->
get_overlaps(Offset, Len, T, [Ck|Acc0]); get_overlaps(Offset, Len, T, [Ck|Acc0]);
get_overlaps(Offset, Len, [_Ck|T], Acc0) -> get_overlaps(Offset, Len, [_Ck|T], Acc0) ->
%% ?debugVal({Offset, Len, _Ck}),
%% ?debugVal(Offset =< Pos andalso Pos < Offset + Len andalso Offset + Len =< Pos + Sz),
%% ?debugVal(Offset =< Pos andalso Pos + Sz < Offset + Len),
%% ?debugVal(Pos < Offset andalso Offset < Pos + Sz andalso Pos + Sz < Offset + Len),
%% ?debugVal(Pos < Offset + Len andalso Offset + Len < Pos + Sz),
get_overlaps(Offset, Len, T, Acc0). get_overlaps(Offset, Len, T, Acc0).
%% Inefficient but simple easy code to verify by eyes - returns all %% Inefficient but simple easy code to verify by eyes - returns all
@ -209,8 +212,6 @@ last_byte(L0) ->
L1 = lists:map(fun({Pos, Sz}) -> Pos + Sz end, L0), L1 = lists:map(fun({Pos, Sz}) -> Pos + Sz end, L0),
lists:last(lists:sort(L1)). lists:last(lists:sort(L1)).
-define(TESTDIR, "./eqc").
cleanup() -> cleanup() ->
[begin [begin
Fs = filelib:wildcard(?TESTDIR ++ Glob), Fs = filelib:wildcard(?TESTDIR ++ Glob),
@ -228,14 +229,12 @@ start_pre(S) ->
start_command(S) -> start_command(S) ->
{call, ?MODULE, start, [S]}. {call, ?MODULE, start, [S]}.
start(_S) -> start(#state{filename=File}) ->
{_, _, MS} = os:timestamp(),
File = test_server:temp_name("eqc_data") ++ "." ++ integer_to_list(MS),
{ok, Pid} = machi_file_proxy:start_link(some_flu, File, ?TESTDIR), {ok, Pid} = machi_file_proxy:start_link(some_flu, File, ?TESTDIR),
unlink(Pid), unlink(Pid),
Pid. Pid.
start_next(S, Pid, _Args) -> start_next(S, Pid, _) ->
S#state{pid = Pid}. S#state{pid = Pid}.
%% read %% read
@ -244,25 +243,19 @@ read_pre(S) ->
S#state.pid /= undefined. S#state.pid /= undefined.
read_args(S) -> read_args(S) ->
[S#state.pid, offset(), len()]. [S#state.pid, oneof([offset(), big_offset()]), len()].
read_post(S, [_Pid, Off, L], Res) -> read_post(S, [_Pid, Off, L], Res) ->
Written = get_overlaps(Off, L, S#state.written, []), Written = get_overlaps(Off, L, S#state.written, []),
Chopped = chop(Off, L, Written), Chopped = chop(Off, L, Written),
Trimmed = get_overlaps(Off, L, S#state.trimmed, []), Trimmed = get_overlaps(Off, L, S#state.trimmed, []),
Eof = lists:max([Pos+Sz||{Pos,Sz}<-S#state.written]), Eof = lists:max([Pos+Sz||{Pos,Sz}<-S#state.written]),
%% ?debugVal({Off, L}),
%% ?debugVal(S),
case Res of case Res of
{ok, {Written0, Trimmed0}} -> {ok, {Written0, Trimmed0}} ->
Written1 = lists:map(fun({_, Pos, Chunk, _}) -> Written1 = lists:map(fun({_, Pos, Chunk, _}) ->
{Pos, iolist_size(Chunk)} {Pos, iolist_size(Chunk)}
end, Written0), end, Written0),
Trimmed1 = lists:map(fun({_, Pos, Sz}) -> {Pos, Sz} end, Trimmed0), Trimmed1 = lists:map(fun({_, Pos, Sz}) -> {Pos, Sz} end, Trimmed0),
%% ?debugVal({Written, Chopped, Written1}),
%% ?debugVal({Trimmed, Trimmed1}),
%% ?assertEqual(Chopped, Written1),
%% ?assertEqual(Trimmed, Trimmed1),
Chopped =:= Written1 Chopped =:= Written1
andalso Trimmed =:= Trimmed1; andalso Trimmed =:= Trimmed1;
%% TODO: such response are ugly, rethink the SPEC %% TODO: such response are ugly, rethink the SPEC
@ -270,8 +263,7 @@ read_post(S, [_Pid, Off, L], Res) ->
true; true;
{error, not_written} when Chopped =:= [] andalso Trimmed =:= [] -> {error, not_written} when Chopped =:= [] andalso Trimmed =:= [] ->
true; true;
Other -> _Other ->
?debugVal(Other),
is_error(Res) is_error(Res)
end. end.
@ -328,7 +320,6 @@ write(Pid, Offset, {Bin, Tag, Csum}) ->
%% append %% append
append_pre(S) -> append_pre(S) ->
?assert(undefined =/= S#state.written),
S#state.pid /= undefined. S#state.pid /= undefined.
%% do not allow appends with empty binary data %% do not allow appends with empty binary data
@ -349,18 +340,30 @@ append_next(S, Res, [_Pid, Extra, {Bin, _Tag, _Csum}]) ->
case is_ok(Res) of case is_ok(Res) of
true -> true ->
Offset = get_offset(Res), Offset = get_offset(Res),
Expected = erlang:max(last_byte(S#state.written) + S#state.prev_extra, S#state{prev_extra = Extra,
last_byte(S#state.trimmed)), written = lists:sort(S#state.written ++ [{Offset, iolist_size(Bin)}])};
?assertEqual(Expected, Offset), _Other ->
S#state{prev_extra = Extra, written = lists:sort(S#state.written ++ [{Offset, iolist_size(Bin)}])};
_ ->
S S
end. end.
%% appends should always succeed unless the disk is full %% appends should always succeed unless the disk is full
%% or there's a hardware failure. %% or there's a hardware failure.
append_post(_S, _Args, Res) -> append_post(S, _Args, Res) ->
true == is_ok(Res). case is_ok(Res) of
true ->
Offset = get_offset(Res),
case erlang:max(last_byte(S#state.written),
last_byte(S#state.trimmed)) + S#state.prev_extra of
Offset ->
true;
UnexpectedByte ->
{wrong_offset_after_append,
{Offset, UnexpectedByte},
{S#state.written, S#state.prev_extra}}
end;
Error ->
Error
end.
%% rewrite %% rewrite
@ -415,6 +418,20 @@ trim_next(S, Res, [_Pid, Offset, Length]) ->
S1#state{prev_extra=0, S1#state{prev_extra=0,
planned_trims=tl(S#state.planned_trims)}. planned_trims=tl(S#state.planned_trims)}.
stop_pre(S) ->
S#state.pid /= undefined.
stop_args(S) ->
[S#state.pid].
stop(Pid) ->
catch machi_file_proxy:stop(Pid).
stop_post(_, _, _) -> true.
stop_next(S, _, _) ->
S#state{pid=undefined, prev_extra=0}.
%% Property %% Property
prop_ok() -> prop_ok() ->
@ -424,15 +441,10 @@ prop_ok() ->
?FORALL(Cmds, parallel_commands(?MODULE, initial_state(I, T)), ?FORALL(Cmds, parallel_commands(?MODULE, initial_state(I, T)),
begin begin
{H, S, Res} = run_parallel_commands(?MODULE, Cmds), {H, S, Res} = run_parallel_commands(?MODULE, Cmds),
%% case S#state.pid of cleanup(),
%% undefined -> noop;
%% Pid ->
%% machi_file_proxy:stop(Pid)
%% end,
pretty_commands(?MODULE, Cmds, {H, S, Res}, pretty_commands(?MODULE, Cmds, {H, S, Res},
aggregate(command_names(Cmds), Res == ok)) aggregate(command_names(Cmds), Res == ok))
end) end)).
).
%% Test for tester functions %% Test for tester functions
chopper_test_() -> chopper_test_() ->