Skip to content

Commit

Permalink
Split tests to where they belong. Add simple statem test.
Browse files Browse the repository at this point in the history
; Split the writer tests to the writer parts. This is not entirely
  correct since they both read and write, but oh, well.
; Provide a simple statem test which opens trees and puts values.
  • Loading branch information
jlouis committed Jan 6, 2012
1 parent de8d092 commit 01d0007
Show file tree
Hide file tree
Showing 4 changed files with 259 additions and 68 deletions.
88 changes: 88 additions & 0 deletions test/fractal_btree_drv.erl
@@ -0,0 +1,88 @@
%% @Doc Drive a set of fractal BTrees
-module(fractal_btree_drv).

-behaviour(gen_server).

%% API
-export([start_link/0]).

-export([open/1,
put/3,
stop/0]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).

-define(SERVER, ?MODULE).

-record(state, { btrees = dict:new() % Map from a name to its tree
}).

%%%===================================================================

start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

call(X) ->
gen_server:call(?SERVER, X, infinity).

open(N) ->
call({open, N}).

put(N, K, V) ->
call({put, N, K, V}).

stop() ->
call(stop).

%%%===================================================================

init([]) ->
{ok, #state{}}.

handle_call({open, N}, _, #state { btrees = D} = State) ->
case fractal_btree:open(N) of
{ok, Tree} ->
{reply, ok, State#state { btrees = dict:store(N, Tree, D)}};
Otherwise ->
{reply, {error, Otherwise}, State}
end;
handle_call({put, N, K, V}, _, #state { btrees = D} = State) ->
Tree = dict:fetch(N, D),
case fractal_btree:put(Tree, K, V) of
ok ->
{reply, ok, State};
Other ->
{reply, {error, Other}, State}
end;
handle_call(stop, _, State) ->
{stop, normal, ok, State};
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.

handle_cast(_Msg, State) ->
{noreply, State}.

handle_info(_Info, State) ->
{noreply, State}.

terminate(_Reason, State) ->
cleanup_trees(State),
ok.

code_change(_OldVsn, State, _Extra) ->
{ok, State}.

%%%===================================================================

%% @todo directory cleanup
cleanup_trees(#state { btrees = BTs }) ->
dict:fold(fun(_Name, Tree, ok) ->
fractal_btree:close(Tree)
end,
ok,
BTs).


39 changes: 39 additions & 0 deletions test/fractal_btree_merger_tests.erl
@@ -0,0 +1,39 @@
-module(fractal_btree_merger_tests).

-ifdef(TEST).
-include_lib("proper/include/proper.hrl").
-include_lib("eunit/include/eunit.hrl").
-endif.

-compile(export_all).

merge_test() ->

{ok, BT1} = fractal_btree_writer:open("test1"),
lists:foldl(fun(N,_) ->
ok = fractal_btree_writer:add(BT1, <<N:128>>, <<"data",N:128>>)
end,
ok,
lists:seq(1,10000,2)),
ok = fractal_btree_writer:close(BT1),


{ok, BT2} = fractal_btree_writer:open("test2"),
lists:foldl(fun(N,_) ->
ok = fractal_btree_writer:add(BT2, <<N:128>>, <<"data",N:128>>)
end,
ok,
lists:seq(2,5001,1)),
ok = fractal_btree_writer:close(BT2),


{Time,{ok,Count}} = timer:tc(fractal_btree_merger2, merge, ["test1", "test2", "test3", 10000]),

error_logger:info_msg("time to merge: ~p/sec (time=~p, count=~p)~n", [1000000/(Time/Count), Time/1000000, Count]),

ok = file:delete("test1"),
ok = file:delete("test2"),
ok = file:delete("test3"),

ok.

136 changes: 68 additions & 68 deletions test/fractal_btree_tests.erl
@@ -1,100 +1,100 @@
-module(fractal_btree_tests).

-ifdef(TEST).
-include_lib("proper/include/proper.hrl").
-include_lib("eunit/include/eunit.hrl").
-endif.

-compile(export_all).

simple_test() ->

{ok, BT} = fractal_btree_writer:open("testdata"),
ok = fractal_btree_writer:add(BT, <<"A">>, <<"Avalue">>),
ok = fractal_btree_writer:add(BT, <<"B">>, <<"Bvalue">>),
ok = fractal_btree_writer:close(BT),

{ok, IN} = fractal_btree_reader:open("testdata"),
{ok, <<"Avalue">>} = fractal_btree_reader:lookup(IN, <<"A">>),
ok = fractal_btree_reader:close(IN),

ok = file:delete("testdata").


simple1_test() ->

{ok, BT} = fractal_btree_writer:open("testdata"),
-behaviour(proper_statem).

Max = 30*1024,
Seq = lists:seq(0, Max),
-compile(export_all).

{Time1,_} = timer:tc(
fun() ->
lists:foreach(
fun(Int) ->
ok = fractal_btree_writer:add(BT, <<Int:128>>, <<"valuevalue/", Int:128>>)
end,
Seq),
ok = fractal_btree_writer:close(BT)
end,
[]),
-export([command/1, initial_state/0,
next_state/3, postcondition/3,
precondition/2]).

error_logger:info_msg("time to insert: ~p/sec~n", [1000000/(Time1/Max)]),
-record(state, { open = dict:new(),
closed = dict:new() }).
-define(SERVER, fractal_btree_drv).

{ok, IN} = fractal_btree_reader:open("testdata"),
{ok, <<"valuevalue/", 2048:128>>} = fractal_btree_reader:lookup(IN, <<2048:128>>),
full_test_() ->
{setup,
spawn,
fun () -> ok end,
fun (_) -> ok end,
[{timeout, 120, ?_test(test_proper())},
?_test(test_tree())]}.

qc_opts() -> [{numtests, 400}].

{Time2,Count} = timer:tc(
fun() -> fractal_btree_reader:fold(fun(Key, <<"valuevalue/", Key/binary>>, N) ->
N+1
end,
0,
IN)
end,
[]),
test_proper() ->
[?assertEqual([], proper:module(?MODULE, qc_opts()))].

error_logger:info_msg("time to scan: ~p/sec~n", [1000000/(Time2/Max)]),

Max = Count-1,
initial_state() ->
#state { }.

g_btree_name() ->
?LET(I, integer(1,10),
"Btree_" ++ integer_to_list(I)).

ok = fractal_btree_reader:close(IN),
cmd_close_args(#state { open = Open }) ->
oneof(dict:fetch_keys(Open)).

ok = file:delete("testdata").
cmd_put_args(#state { open = Open }) ->
?LET({Name, Key, Value},
{oneof(dict:fetch_keys(Open)), binary(), binary()},
[Name, Key, Value]).

command(#state { open = Open} = S) ->
frequency(
[ {100, {call, ?SERVER, open, [g_btree_name()]}} ] ++
[ {2000, {call, ?SERVER, put, cmd_put_args(S)}}
|| dict:size(Open) > 0]).

merge_test() ->
precondition(#state { open = Open }, {call, ?SERVER, put, [Name, K, V]}) ->
dict:is_key(Name, Open);
precondition(#state { open = Open }, {call, ?SERVER, open, [Name]}) ->
not (dict:is_key(Name, Open)).

{ok, BT1} = fractal_btree_writer:open("test1"),
lists:foldl(fun(N,_) ->
ok = fractal_btree_writer:add(BT1, <<N:128>>, <<"data",N:128>>)
end,
ok,
lists:seq(1,10000,2)),
ok = fractal_btree_writer:close(BT1),
next_state(#state { open = Open} = S, _Res,
{call, ?SERVER, put, [Name, Key, Value]}) ->
S#state { open = dict:update(Name,
fun(Dict) ->
dict:store(Key, Value, Dict)
end,
Open)};
next_state(#state { open = Open} = S, _Res, {call, ?SERVER, open, [Name]}) ->
S#state { open = dict:store(Name, dict:new(), Open) }.

postcondition(_S, {call, ?SERVER, put, [_Name, _Key, _Value]}, ok) ->
true;
postcondition(_S, {call, ?SERVER, open, [_Name]}, ok) ->
true;
postcondition(_, _, _) ->
false.

{ok, BT2} = fractal_btree_writer:open("test2"),
lists:foldl(fun(N,_) ->
ok = fractal_btree_writer:add(BT2, <<N:128>>, <<"data",N:128>>)
end,
ok,
lists:seq(2,5001,1)),
ok = fractal_btree_writer:close(BT2),

prop_dict_agree() ->
?FORALL(Cmds, commands(?MODULE),
?TRAPEXIT(
begin
fractal_btree_drv:start_link(),
{History,State,Result} = run_commands(?MODULE, Cmds),
fractal_btree_drv:stop(),
?WHENFAIL(io:format("History: ~w\nState: ~w\nResult: ~w\n",
[History,State,Result]),
aggregate(command_names(Cmds), Result =:= ok))
end)).

{Time,{ok,Count}} = timer:tc(fractal_btree_merger2, merge, ["test1", "test2", "test3", 10000]),
%% ----------------------------------------------------------------------

error_logger:info_msg("time to merge: ~p/sec (time=~p, count=~p)~n", [1000000/(Time/Count), Time/1000000, Count]),

ok = file:delete("test1"),
ok = file:delete("test2"),
ok = file:delete("test3"),

ok.
%% UNIT TESTS -----------------------------------------------------------------


tree_test() ->
test_tree() ->

application:start(sasl),

Expand Down
64 changes: 64 additions & 0 deletions test/fractal_btree_writer_tests.erl
@@ -0,0 +1,64 @@
-module(fractal_btree_writer_tests).

-ifdef(TEST).
-include_lib("proper/include/proper.hrl").
-include_lib("eunit/include/eunit.hrl").
-endif.

-compile(export_all).

simple_test() ->

{ok, BT} = fractal_btree_writer:open("testdata"),
ok = fractal_btree_writer:add(BT, <<"A">>, <<"Avalue">>),
ok = fractal_btree_writer:add(BT, <<"B">>, <<"Bvalue">>),
ok = fractal_btree_writer:close(BT),

{ok, IN} = fractal_btree_reader:open("testdata"),
{ok, <<"Avalue">>} = fractal_btree_reader:lookup(IN, <<"A">>),
ok = fractal_btree_reader:close(IN),

ok = file:delete("testdata").


simple1_test() ->

{ok, BT} = fractal_btree_writer:open("testdata"),

Max = 30*1024,
Seq = lists:seq(0, Max),

{Time1,_} = timer:tc(
fun() ->
lists:foreach(
fun(Int) ->
ok = fractal_btree_writer:add(BT, <<Int:128>>, <<"valuevalue/", Int:128>>)
end,
Seq),
ok = fractal_btree_writer:close(BT)
end,
[]),

error_logger:info_msg("time to insert: ~p/sec~n", [1000000/(Time1/Max)]),

{ok, IN} = fractal_btree_reader:open("testdata"),
{ok, <<"valuevalue/", 2048:128>>} = fractal_btree_reader:lookup(IN, <<2048:128>>),


{Time2,Count} = timer:tc(
fun() -> fractal_btree_reader:fold(fun(Key, <<"valuevalue/", Key/binary>>, N) ->
N+1
end,
0,
IN)
end,
[]),

error_logger:info_msg("time to scan: ~p/sec~n", [1000000/(Time2/Max)]),

Max = Count-1,


ok = fractal_btree_reader:close(IN),

ok = file:delete("testdata").

0 comments on commit 01d0007

Please sign in to comment.