Anonymous avatar Anonymous committed 0de8e59 Merge

Merge remote branch 'rzezeski/unit_tests-1.0' into ut1

Comments (0)

Files changed (8)

test/luwak_checksum_tests.erl

+-module(luwak_checksum_tests).
+
+-include_lib("eunit/include/eunit.hrl").
+
+one_off_checksum_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      Sha = crypto:sha(<<"chilled monkey brains">>),
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{tree_order,2},{block_size,2}], dict:new()),
+      {ok, _, File1} = luwak_io:put_range(Riak, File, 0, <<"chilled monkey brains">>),
+      timer:sleep(100),
+      Checksum = luwak_checksum:sha1(Riak, File1),
+      ?assertEqual(Sha, Checksum)
+    end).
+
+do_a_simple_checksum_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      Sha = crypto:sha(<<"chilled monkey brains">>),
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{checksumming,true}], dict:new()),
+      {ok, _, File1} = luwak_io:put_range(Riak, File, 0, <<"chilled monkey brains">>),
+      ?assertEqual({sha1,Sha}, luwak_file:get_property(File1,checksum))
+    end).

test/luwak_file_tests.erl

+-module(luwak_file_tests).
+
+-include_lib("eunit/include/eunit.hrl").
+
+object_creation_test() ->
+  test_helper:riak_test(fun(Riak) ->  
+      Dict = dict:new(),
+      luwak_file:create(Riak, <<"file1">>, dict:store(key, value, Dict)),
+      {ok, Obj} = luwak_file:get(Riak, <<"file1">>),
+      Attr = luwak_file:get_attributes(Obj),
+      ?assertEqual({ok, value}, dict:find(key, Attr))
+    end).
+    
+set_attributes_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      Dict = dict:new(),
+      {ok, Obj} = luwak_file:create(Riak, <<"file1">>, dict:store(key, value, Dict)),
+      {ok, Obj2} = luwak_file:set_attributes(Riak, Obj, dict:store(key, blah, Dict)),
+      Attr = luwak_file:get_attributes(Obj2),
+      ?assertEqual({ok, blah}, dict:find(key, Attr))
+    end).
+    
+exists_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, _Obj} = luwak_file:create(Riak, <<"file1">>, dict:new()),
+      ?assertEqual({ok, true}, luwak_file:exists(Riak, <<"file1">>))
+    end).
+  
+delete_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, _Obj} = luwak_file:create(Riak, <<"file1">>, dict:new()),
+      ok = luwak_file:delete(Riak, <<"file1">>),
+      ?assertEqual({ok, false}, luwak_file:exists(Riak, <<"file1">>))
+    end).
+

test/luwak_get_stream_tests.erl

+-module(luwak_get_stream_tests).
+
+-include_lib("eunit/include/eunit.hrl").
+
+simple_get_stream_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{block_size,3},{tree_order,3}], dict:new()),
+      {ok, _Written, File1} = luwak_io:put_range(Riak, File, 0, <<"wontyoupleasetouchmymonkey">>),
+      GetStream = luwak_get_stream:start(Riak, File1, 0, 26),
+      timer:sleep(100),
+      ?assertEqual({<<"won">>, 0}, luwak_get_stream:recv(GetStream, 1000)),
+      ?assertEqual({<<"tyo">>, 3}, luwak_get_stream:recv(GetStream, 1000)),
+      ?assertEqual({<<"upl">>, 6}, luwak_get_stream:recv(GetStream, 1000)),
+      ?assertEqual({<<"eas">>, 9}, luwak_get_stream:recv(GetStream, 1000)),
+      ?assertEqual({<<"eto">>, 12}, luwak_get_stream:recv(GetStream, 1000)),
+      ?assertEqual({<<"uch">>, 15}, luwak_get_stream:recv(GetStream, 1000)),
+      ?assertEqual({<<"mym">>, 18}, luwak_get_stream:recv(GetStream, 1000)),
+      ?assertEqual({<<"onk">>, 21}, luwak_get_stream:recv(GetStream, 1000)),
+      ?assertEqual({<<"ey">>, 24}, luwak_get_stream:recv(GetStream, 1000)),
+      ?assertEqual(eos, luwak_get_stream:recv(GetStream, 1000))
+    end).
+    
+three_level_tree_stream_test_() ->
+  Test = fun() ->
+    test_helper:riak_test(fun(Riak) ->
+        {ok, File} = luwak_file:create(Riak, <<"file1">>, [{block_size,2},{tree_order,2}], dict:new()),
+        {ok, _Written, File1} = luwak_io:put_range(Riak, File, 0, <<"wontyoupleasetouchmymonkey">>),
+        GetStream = luwak_get_stream:start(Riak, File1, 3, 10),
+        ?assertEqual({<<"t">>, 3}, luwak_get_stream:recv(GetStream, 1000)),
+        ?assertEqual({<<"yo">>, 4}, luwak_get_stream:recv(GetStream, 1000)),
+        ?assertEqual({<<"up">>, 6}, luwak_get_stream:recv(GetStream, 1000)),
+        ?assertEqual({<<"le">>, 8}, luwak_get_stream:recv(GetStream, 1000)),
+        ?assertEqual({<<"as">>, 10}, luwak_get_stream:recv(GetStream, 1000)),
+        ?assertEqual({<<"e">>, 12}, luwak_get_stream:recv(GetStream, 1000)),
+        ?assertEqual(eos, luwak_get_stream:recv(GetStream, 1000))
+      end)
+    end,
+  {timeout, 30000, Test}.
+
+read_beyond_file_end_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{block_size,2},{tree_order,2}], dict:new()),
+      {ok, _Written, File1} = luwak_io:put_range(Riak, File, 0, <<"wontyoupleasetouchmymonkey">>),
+      GetStream = luwak_get_stream:start(Riak, File1, 30, 10),
+      ?assertEqual(eos, luwak_get_stream:recv(GetStream, 1000))
+    end).
+
+%% @doc Makes a simple file, named Name, with BlockCount blocks, each
+%%      filled with BlockSize characters.
+%%      Ex: make_standard_range_file(R, <<"foo">>, 5, 3)
+%%      will make a file named "foo" with the contents:
+%%      aaaaabbbbbccccc
+%% @spec make_standard_range_file(riak_client(), binary(),
+%%                                integer(), integer())
+%%         -> {ok, Contents::binary(), FileHandle::luwak_file()}
+make_standard_range_file(Riak, Name, BlockSize, BlockCount) ->
+    {ok, File} = luwak_file:create(Riak, Name,
+                                   [{block_size, BlockSize}],
+                                   dict:new()),
+    Data = iolist_to_binary(
+             [ lists:duplicate(BlockSize, $a+N) ||
+                 N <- lists:seq(0, BlockCount-1) ]),
+    {ok, _, NewFile} = luwak_io:put_range(Riak, File, 0, Data),
+    {ok, Data, NewFile}.
+
+%% tests a get_range that specifies an offset+length that ends in
+%% the middle of a block
+%% Ex: aaaaaaaaaa bbbbbbbbbb cccccccccc
+%%                ^start      end^
+partial_end_block_get_range_test() ->
+    test_helper:riak_test(
+      fun(Riak) ->
+              {ok, Data, File} =  make_standard_range_file(
+                                    Riak, <<"endblockrange">>, 10, 3),
+              Read = read_stream(
+                       luwak_get_stream:start(Riak, File, 10, 14)),
+              <<_:10/binary, Expected:14/binary, _/binary>> = Data,
+              ?assertEqual(Expected, Read)
+      end).
+
+%% tests a get_range that specifies an offset that lands in the
+%% middle of a block
+%% Ex: aaaaaaaaaa bbbbbbbbbb cccccccccc
+%%          ^start       end^
+partial_start_block_get_range_test() ->
+    test_helper:riak_test(
+      fun(Riak) ->
+              {ok, Data, File} = make_standard_range_file(
+                                   Riak, <<"startblockrange">>, 10, 3),
+              Read = read_stream(
+                       luwak_get_stream:start(Riak, File, 5, 15)),
+              <<_:5/binary, Expected:15/binary, _/binary>> = Data,
+              ?assertEqual(Expected, Read)
+      end).
+
+
+%% tests a get_range that starts and ends in the same block, but
+%% is unaligned with that block
+%% Ex: aaaaaaaaaa bbbbbbbbbb cccccccccc
+%%                 ^st end^
+partial_middle_block_get_range_test() ->
+    test_helper:riak_test(
+      fun(Riak) ->
+              {ok, Data, File} = make_standard_range_file(
+                                   Riak, <<"midblockrange">>, 10, 3),
+               Read = read_stream(
+                        luwak_get_stream:start(Riak, File, 11, 8)),
+               <<_:11/binary, Expected:8/binary, _/binary>> = Data,
+              ?assertEqual(Expected, Read)
+      end).
+
+read_stream(Stream) ->
+    read_stream(Stream, luwak_get_stream:recv(Stream, 1000), []).
+
+read_stream(_, eos, Acc) ->
+    iolist_to_binary(lists:reverse(Acc));
+read_stream(Stream, {Data, _}, Acc) ->
+    read_stream(Stream,
+                luwak_get_stream:recv(Stream, 1000),
+                [Data|Acc]).

test/luwak_io_tests.erl

+-module(luwak_io_tests).
+
+-include_lib("eunit/include/eunit.hrl").
+
+simple_put_range_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{block_size,5}], dict:new()),
+      {ok, Written, _} = luwak_io:put_range(Riak, File, 0, <<"fuckyourcouch">>),
+      Hash1 = <<"4622b193a65e6f2a7873b6bef7e3b0cf18867f687e48f40fd9eabf840d5f0ebbd65bfff586e5c38ba50e473516e8f270b6687a1f271586baf648a38aa489dd91">>,
+      Hash2 = <<"08d5f211d13a9fb1e9b6902771b80459fedbb9e138b96d7a6dc3b92ad87997d24b65cc1a8594cc14b226cd511acf03eb3f4b24c7b67d270665d5bf5cb43f8fa6">>,
+      Hash3 = <<"6f01ab53f4498ccfa5de27d9fa1fd1aa3c088958588db410bc35055012e6ed2795c39d8abe454402062436434b15acc78baddb016c370cd445579401562ea316">>,
+      {ok, Block1} = Riak:get(<<"luwak_node">>, Hash1, 2),
+      {ok, Block2} = Riak:get(<<"luwak_node">>, Hash2, 2),
+      {ok, Block3} = Riak:get(<<"luwak_node">>, Hash3, 2),
+      ?assertEqual(<<"fucky">>, luwak_block:data(Block1)),
+      ?assertEqual(<<"ourco">>, luwak_block:data(Block2)),
+      ?assertEqual(<<"uch">>, luwak_block:data(Block3)),
+      ?assertEqual([{Hash1,5},{Hash2,5},{Hash3,3}], Written)
+    end).
+
+simple_get_range_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{block_size,2},{tree_order,3}], dict:new()),
+      {ok, _Written, File1} = luwak_io:put_range(Riak, File, 0, <<"fuckyourcouch">>),
+      Blocks = luwak_io:get_range(Riak, File1, 3, 5),
+      ok = file:write_file("tree4.dot", luwak_tree:visualize_tree(Riak, luwak_file:get_property(File1, root))),
+      ?assertEqual(<<"kyour">>, iolist_to_binary(Blocks))
+    end).
+    
+read_beyond_eof_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{block_size,2},{tree_order,3}], dict:new()),
+      {ok, _Written, File1} = luwak_io:put_range(Riak, File, 0, <<"fuckyourcouch">>),
+      Blocks = luwak_io:get_range(Riak, File1, 14, 5),
+      ?assertEqual([], Blocks)
+    end).
+
+multilevel_get_range_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{block_size,3},{tree_order,3}], dict:new()),
+      {ok, _Written, File1} = luwak_io:put_range(Riak, File, 0, <<"wontyoupleasetouchmymonkey">>),
+      Blocks = luwak_io:get_range(Riak, File1, 4, 9),
+      ok = file:write_file("tree5.dot", luwak_tree:visualize_tree(Riak, luwak_file:get_property(File1, root))),
+      ?assertEqual(<<"youplease">>, iolist_to_binary(Blocks))
+    end).
+
+%% @doc Makes a simple file, named Name, with BlockCount blocks, each
+%%      filled with BlockSize characters.
+%%      Ex: make_standard_range_file(R, <<"foo">>, 5, 3)
+%%      will make a file named "foo" with the contents:
+%%      aaaaabbbbbccccc
+%% @spec make_standard_range_file(riak_client(), binary(),
+%%                                integer(), integer())
+%%         -> {ok, Contents::binary(), FileHandle::luwak_file()}
+make_standard_range_file(Riak, Name, BlockSize, BlockCount) ->
+    {ok, File} = luwak_file:create(Riak, Name,
+                                   [{block_size, BlockSize}],
+                                   dict:new()),
+    Data = iolist_to_binary(
+             [ lists:duplicate(BlockSize, $a+N) ||
+                 N <- lists:seq(0, BlockCount-1) ]),
+    {ok, _, NewFile} = luwak_io:put_range(Riak, File, 0, Data),
+    {ok, Data, NewFile}.
+
+%% tests a get_range that specifies an offset+length that ends in
+%% the middle of a block
+%% Ex: aaaaaaaaaa bbbbbbbbbb cccccccccc
+%%                ^start      end^
+partial_end_block_get_range_test() ->
+    test_helper:riak_test(
+      fun(Riak) ->
+              {ok, Data, File} =  make_standard_range_file(
+                                    Riak, <<"endblockrange">>, 10, 3),
+              Read = iolist_to_binary(
+                       luwak_io:get_range(Riak, File, 10, 14)),
+              <<_:10/binary, Expected:14/binary, _/binary>> = Data,
+              ?assertEqual(Expected, Read)
+      end).
+
+%% tests a get_range that specifies an offset that lands in the
+%% middle of a block
+%% Ex: aaaaaaaaaa bbbbbbbbbb cccccccccc
+%%          ^start       end^
+partial_start_block_get_range_test() ->
+    test_helper:riak_test(
+      fun(Riak) ->
+              {ok, Data, File} = make_standard_range_file(
+                                   Riak, <<"startblockrange">>, 10, 3),
+              Read = iolist_to_binary(
+                       luwak_io:get_range(Riak, File, 5, 15)),
+              <<_:5/binary, Expected:15/binary, _/binary>> = Data,
+              ?assertEqual(Expected, Read)
+      end).
+
+%% tests a get_range that starts and ends in the same block, but
+%% is unaligned with that block
+%% Ex: aaaaaaaaaa bbbbbbbbbb cccccccccc
+%%                 ^st end^
+partial_middle_block_get_range_test() ->
+    test_helper:riak_test(
+      fun(Riak) ->
+              {ok, Data, File} = make_standard_range_file(
+                                   Riak, <<"midblockrange">>, 10, 3),
+               Read = iolist_to_binary(
+                        luwak_io:get_range(Riak, File, 11, 8)),
+               <<_:11/binary, Expected:8/binary, _/binary>> = Data,
+              ?assertEqual(Expected, Read)
+      end).
+
+eof_get_range_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{block_size,3},{tree_order,3}], dict:new()),
+      {ok, _Written, File1} = luwak_io:put_range(Riak, File, 0, <<"wontyoupleasetouchmymonkey">>),
+      ok = file:write_file("tree6.dot", luwak_tree:visualize_tree(Riak, luwak_file:get_property(File1, root))),
+      Blocks = luwak_io:get_range(Riak, File1, 20, 20),
+      ?assertEqual(<<"monkey">>, iolist_to_binary(Blocks))
+    end).
+
+truncate_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{block_size,3},{tree_order,3}], dict:new()),
+      {ok, _Written, File1} = luwak_io:put_range(Riak, File, 0, <<"wontyoupleasetouchmymonkey">>),
+      {ok, File2} = luwak_io:truncate(Riak, File1, 7),
+      ok = file:write_file("tree7.dot", luwak_tree:visualize_tree(Riak, luwak_file:get_property(File2, root))),
+      Blocks = luwak_io:get_range(Riak, File2, 0, 7),
+      ?assertEqual(<<"wontyou">>, iolist_to_binary(Blocks))
+    end).
+
+sub_block_partial_write_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"basho">>, [{block_size,1000}], dict:new()),
+      S = luwak_put_stream:start_link(Riak, File, 0, 1000),
+      B1 = crypto:rand_bytes(33),
+      luwak_put_stream:send(S, B1),
+      luwak_put_stream:close(S),
+      timer:sleep(100),
+      {ok, File2} = luwak_file:get(Riak, <<"basho">>),
+      S1 = luwak_put_stream:start_link(Riak, File2, 33, 1000),
+      B2 = crypto:rand_bytes(33),
+      luwak_put_stream:send(S1, B2),
+      luwak_put_stream:close(S1),
+      timer:sleep(100),
+      {ok, File3} = luwak_file:get(Riak, <<"basho">>),
+      Blocks = luwak_io:get_range(Riak, File3, 0, 66),
+      ?debugFmt("blocks ~p~n", [Blocks]),
+      ?assertEqual(<<B1/binary, B2/binary>>, iolist_to_binary(Blocks))
+    end).
+
+%% overwrite a file with more data than the file already had, but not
+%% enough to touch the next block boundary
+overwrite_nonfull_block_test() ->
+    test_helper:riak_test(fun(Riak) ->
+        {ok, F0} = luwak_file:create(Riak,
+                                     <<"basho1">>,
+                                     [{block_size, 4}],
+                                     dict:new()),
+        S0 = luwak_put_stream:start_link(Riak, F0, 0, 1000),
+        luwak_put_stream:send(S0, <<"a">>),
+        luwak_put_stream:close(S0),
+        timer:sleep(100),
+
+        {ok, F1} = luwak_file:get(Riak, <<"basho1">>),
+        S1 = luwak_put_stream:start_link(Riak, F1, 0, 1000),
+        luwak_put_stream:send(S1, <<"aa">>),
+        luwak_put_stream:close(S1),
+        timer:sleep(100),
+
+        {ok, F2} = luwak_file:get(Riak, <<"basho1">>),
+        Blocks = luwak_io:get_range(Riak, F2, 0, 4),
+        ?debugFmt("blocks ~p~n", [Blocks]),
+        ?assertEqual(<<"aa">>, iolist_to_binary(Blocks))
+      end).

test/luwak_put_stream_tests.erl

+-module(luwak_put_stream_tests).
+
+-include_lib("eunit/include/eunit.hrl").
+
+aligned_put_stream_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{block_size,3},{tree_order,3}], dict:new()),
+      PutStream = luwak_put_stream:start(Riak, File, 0, 1000),
+      Input = [<<"hey">>, <<"why">>, <<"are">>, <<"you">>, <<"drp">>],
+      lists:foreach(fun(B) -> luwak_put_stream:send(PutStream, B) end, Input),
+      luwak_put_stream:close(PutStream),
+      {ok, File2} = luwak_put_stream:status(PutStream, 1000),
+      Blocks = luwak_io:get_range(Riak, File2, 0, 15),
+      ?assertEqual(<<"heywhyareyoudrp">>, iolist_to_binary(Blocks))
+    end).
+
+unaligned_put_stream_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{block_size,3},{tree_order,3}], dict:new()),
+      {ok, _, File1} = luwak_io:put_range(Riak, File, 0, <<"heywhyareyoudrp">>),
+      ok = file:write_file("tree8.dot", luwak_tree:visualize_tree(Riak, luwak_file:get_property(File1, root))),
+      PutStream = luwak_put_stream:start(Riak, File1, 4, 1000),
+      Input = [<<"her">>, <<"pdr">>, <<"p">>],
+      lists:foreach(fun(B) -> luwak_put_stream:send(PutStream, B) end, Input),
+      luwak_put_stream:close(PutStream),
+      {ok, File2} = luwak_put_stream:status(PutStream, 1000),
+      ok = file:write_file("tree9.dot", luwak_tree:visualize_tree(Riak, luwak_file:get_property(File2, root))),
+      Blocks = luwak_io:get_range(Riak, File2, 0, 15),
+      timer:sleep(100),
+      ?assertEqual(<<"heywherpdrpudrp">>, iolist_to_binary(Blocks))
+    end).

test/luwak_tree_tests.erl

+-module(luwak_tree_tests).
+
+-include_lib("eunit/include/eunit.hrl").
+-include_lib("luwak/include/luwak.hrl").
+
+create_simple_tree_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{tree_order,4},{block_size,5}], dict:new()),
+      {ok, _Written, File2} = luwak_io:put_range(Riak, File, 0, <<"fuckyourcouch">>),
+      BHash1 = <<"4622b193a65e6f2a7873b6bef7e3b0cf18867f687e48f40fd9eabf840d5f0ebbd65bfff586e5c38ba50e473516e8f270b6687a1f271586baf648a38aa489dd91">>,
+      BHash2 = <<"08d5f211d13a9fb1e9b6902771b80459fedbb9e138b96d7a6dc3b92ad87997d24b65cc1a8594cc14b226cd511acf03eb3f4b24c7b67d270665d5bf5cb43f8fa6">>,
+      BHash3 = <<"6f01ab53f4498ccfa5de27d9fa1fd1aa3c088958588db410bc35055012e6ed2795c39d8abe454402062436434b15acc78baddb016c370cd445579401562ea316">>,
+      RootHash = <<"08b8b5439aecd6ab572f44fafd4cef1d1ae7adb09382046f02ad192437e7d7ff96f7fcd964c133c2039089eb03c7e219bbd272e60e3f2c6c7d1d12f8f01a5f7f">>,
+      Root = luwak_file:get_property(File2, root),
+      ?assertEqual(RootHash, Root),
+      {ok, RootNode} = luwak_tree:get(Riak, Root),
+      Children = RootNode#n.children,
+      ?assertEqual([{BHash1,5},{BHash2,5},{BHash3,3}], Children)
+    end).
+
+create_and_overwrite_middle_tree_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{tree_order,4},{block_size,5}], dict:new()),
+      {ok, _Written1, File2} = luwak_io:put_range(Riak, File, 0, <<"fuckyourcouch">>),
+      _BHash1 = <<"4622b193a65e6f2a7873b6bef7e3b0cf18867f687e48f40fd9eabf840d5f0ebbd65bfff586e5c38ba50e473516e8f270b6687a1f271586baf648a38aa489dd91">>,
+      _BHash2 = <<"08d5f211d13a9fb1e9b6902771b80459fedbb9e138b96d7a6dc3b92ad87997d24b65cc1a8594cc14b226cd511acf03eb3f4b24c7b67d270665d5bf5cb43f8fa6">>,
+      BHash3 = <<"6f01ab53f4498ccfa5de27d9fa1fd1aa3c088958588db410bc35055012e6ed2795c39d8abe454402062436434b15acc78baddb016c370cd445579401562ea316">>,
+      {ok, _Written2, File3} = luwak_io:put_range(Riak, File2, 1, <<"ballstoyou">>),
+      BHash1_2 = <<"3717fd47d84a96cb99791d1c24d652a712e2841f2a3d0a282d22f9a477453bb7c394a1989115acf882fb867483cc2ba429f2280c1014cd82cc95aa8f1e8a1e4c">>,
+      BHash2_2 = <<"16c46831340abea94de6a5369466c0e8f710c15e2eec684067b89b27ca48856d7833933d28a1213cff5887bc57e5fdbb1d5e19bff7c6bb1f412a5db74612314b">>,
+      RootHash2 = <<"53bfd159bbc194ff331dbdcd19f9ab98480b554f88708a342ac2eb1f94229d0444a47a9d5fa5d8b14d1a6264d3df0dde3225f4c21536ed5874fbb0adfabc28eb">>,
+      Root = luwak_file:get_property(File3, root),
+      ?assertEqual(RootHash2, Root),
+      {ok, RootNode} = luwak_tree:get(Riak, Root),
+      Children = RootNode#n.children,
+      ?assertEqual([{BHash1_2,5},{BHash2_2,5},{BHash3,3}], Children)
+    end).
+
+create_multilevel_tree_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{tree_order,5},{block_size,1}], dict:new()),
+      {ok, _Written1, File2} = luwak_io:put_range(Riak, File, 0, <<"fuckyourcouch">>),
+      Blocks = [ {skerl:hexhash(512, list_to_binary([C])), 1} || C <- binary_to_list(<<"fuckyourcouch">>) ],
+      {FirstNodeChildren, Tail1} = lists:split(5, Blocks),
+      {SecondNodeChildren, ThirdNodeChildren} = lists:split(5, Tail1),
+      Node1 = skerl:hexhash(512, term_to_binary(FirstNodeChildren)),
+      Node2 = skerl:hexhash(512, term_to_binary(SecondNodeChildren)),
+      Node3 = skerl:hexhash(512, term_to_binary(ThirdNodeChildren)),
+      RootChildren = [{Node1,5}, {Node2,5}, {Node3,3}],
+      Root1 = skerl:hexhash(512, term_to_binary(RootChildren)),
+      ?assertEqual(Root1, luwak_file:get_property(File2, root)),
+      {ok, RootNode} = luwak_tree:get(Riak, Root1),
+      ?assertEqual(RootChildren, RootNode#n.children),
+      {ok, Node1Node} = luwak_tree:get(Riak, Node1),
+      {ok, Node2Node} = luwak_tree:get(Riak, Node2),
+      {ok, Node3Node} = luwak_tree:get(Riak, Node3),
+      ?assertEqual(FirstNodeChildren, Node1Node#n.children),
+      ?assertEqual(SecondNodeChildren, Node2Node#n.children),
+      ?assertEqual(ThirdNodeChildren, Node3Node#n.children)
+    end).
+
+create_and_overwrite_multilevel_tree_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{tree_order,5},{block_size,1}], dict:new()),
+      {ok, _Written1, File2} = luwak_io:put_range(Riak, File, 0, <<"fuckyourcouch">>),
+      % ok = file:write_file("tree1.dot", luwak_tree:visualize_tree(Riak, luwak_file:get_property(File2, root))),
+      {ok, _Written2, File3} = luwak_io:put_range(Riak, File2, 1, <<"ballstoyou">>),
+      Blocks = [ {skerl:hexhash(512, list_to_binary([C])), 1} || C <- binary_to_list(<<"fballstoyouch">>) ],
+      {FirstNodeChildren, Tail1} = lists:split(5, Blocks),
+      {SecondNodeChildren, ThirdNodeChildren} = lists:split(5, Tail1),
+      Node1 = skerl:hexhash(512, term_to_binary(FirstNodeChildren)),
+      Node2 = skerl:hexhash(512, term_to_binary(SecondNodeChildren)),
+      Node3 = skerl:hexhash(512, term_to_binary(ThirdNodeChildren)),
+      RootChildren = [{Node1,5}, {Node2,5}, {Node3,3}],
+      Root1 = skerl:hexhash(512, term_to_binary(RootChildren)),
+      ok = file:write_file("tree2.dot", luwak_tree:visualize_tree(Riak, luwak_file:get_property(File3, root))),
+      ?assertEqual(Root1, luwak_file:get_property(File3, root)),
+            {ok, RootNode} = luwak_tree:get(Riak, Root1),
+      ?assertEqual(RootChildren, RootNode#n.children),
+      {ok, Node1Node} = luwak_tree:get(Riak, Node1),
+      {ok, Node2Node} = luwak_tree:get(Riak, Node2),
+      {ok, Node3Node} = luwak_tree:get(Riak, Node3),
+      ?assertEqual(FirstNodeChildren, Node1Node#n.children),
+      ?assertEqual(SecondNodeChildren, Node2Node#n.children),
+      ?assertEqual(ThirdNodeChildren, Node3Node#n.children)
+    end).
+
+create_and_append_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{tree_order,3},{block_size,2}], dict:new()),
+      {ok, _Written1, File2} = luwak_io:put_range(Riak, File, 0, <<"wontyouplease">>),
+      {ok, _Written2, File3} = luwak_io:put_range(Riak, File2, 13, <<"touchmymonkey">>),
+      _Blocks = [ {skerl:hexhash(512, X), 2} || <<X:2/binary>> <= <<"wontyoupleasetouchmymonkey">> ],
+      ok = file:write_file("tree3.dot", luwak_tree:visualize_tree(Riak, luwak_file:get_property(File3, root))),
+      ?assertEqual(<<"wontyoupleasetouchmymonkey">>, iolist_to_binary(luwak_io:get_range(Riak, File3, 0, 26)))      
+    end).
+
+append_beyond_pointer_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{tree_order,3},{block_size,2}], dict:new()),
+      {ok, _Written1, File2} = luwak_io:put_range(Riak, File, 0, <<"wontyouplease">>),
+      {ok, _Written2, File3} = luwak_io:put_range(Riak, File2, 15, <<"touchmymonkey">>),
+      ?assertEqual(<<"wontyoupleasetouchmymonkey">>, iolist_to_binary(luwak_io:get_range(Riak, File3, 0, 26)))
+    end).
+
+block_at_test() ->
+  test_helper:riak_test(fun(Riak) ->
+      {ok, File} = luwak_file:create(Riak, <<"file1">>, [{tree_order,3},{block_size,3}], dict:new()),
+      {ok, _Written1, File1} = luwak_io:put_range(Riak, File, 0, <<"heywhyareyoudrp">>),
+      {ok, Block} = luwak_tree:block_at(Riak, File1, 9),
+      Data = luwak_block:data(Block),
+      timer:sleep(1000),
+      ?assertEqual(<<"you">>, Data)
+    end).

test/luwak_tree_utils_tests.erl

+-module(luwak_tree_utils_tests).
+
+-include_lib("eunit/include/eunit.hrl").
+-include_lib("luwak/include/luwak.hrl").
+
+left_list_larger_subtree_test() ->
+    A = [{a,100}, {b,50}, {c,200}],
+    B = [{d,50}, {e,50}, {f,50}, {g,50}, {h,50}],
+    ?assertEqual({{[{a,100}, {b,50}], [{c,200}]},
+                  {[{d,50}, {e,50}, {f,50}], [{g,50}, {h,50}]}},
+                 luwak_tree_utils:longest_divisable_subtree(A, B)).
+
+right_list_larger_subtree_test() ->
+    A = [{a,100}, {b,50}, {c,200}],
+    B = [{d,50}, {e,50}, {f,50}, {g,50}, {h,50}],
+    ?assertEqual({{[{d,50}, {e,50}, {f,50}, {g,50}, {h,50}], []},
+                  {[{a,100}, {b,50}, {c,200}], []}},
+                 luwak_tree_utils:longest_divisable_subtree(B, A)).
+
+equal_list_subtree_test() ->
+    A = [{a,100}, {b,50}, {c,200}],
+    B = [{d,50}, {e,50}, {f,50}, {g,50}, {h,50}, {i,50}, {j,50}],
+    ?assertEqual({{A, []},
+                  {B, []}},
+                 luwak_tree_utils:longest_divisable_subtree(A, B)).
+
+no_subtree_test() ->
+    A = [{a,100}],
+    B = [{b,50}],
+    ?assertEqual({{[], A},
+                  {[], B}},
+                 luwak_tree_utils:longest_divisable_subtree(A, B)).
+
+split_at_length_test() ->
+    A = [{a, 100}, {b, 50}, {c,200}],
+    ?assertEqual({[{a,100},{b,50}],
+                  [{c,200}]},
+                 luwak_tree_utils:split_at_length(A, 200)).
+
+split_at_length_left_bias_test() ->
+    A = [{a,100},{b,50},{c,200}],
+    ?assertEqual({A,[]},
+                 luwak_tree_utils:split_at_length_left_bias(A, 200)).
+
+simple_five_way_split_test() ->
+    Nodes = [{a,100},{b,100},{c,100},{d,100},{e,100}],
+    Blocks = [{f,50},{g,50},{h,50},{i,50}],
+    {NodeSplit,BlockSplit} = luwak_tree_utils:five_way_split(0, Nodes, 150, Blocks),
+    ?assertEqual(#split{
+                    head=[{a,100}],
+                    midhead=[{b,100}],
+                    middle=[{c,100}],
+                    midtail=[{d,100}],
+                    tail=[{e,100}]}, NodeSplit),
+    ?assertEqual(#split{
+                    midhead=[{f,50}],
+                    middle=[{g,50},{h,50}],
+                    midtail=[{i,50}]}, BlockSplit).
+
+no_head_five_way_split_test() ->
+    Nodes = [{a,100},{b,100},{c,100},{d,100},{e,100}],
+    Blocks = [{f,50},{g,50},{h,50},{i,50}],
+    {NodeSplit,BlockSplit} = luwak_tree_utils:five_way_split(0, Nodes, 50, Blocks),
+    ?assertEqual(#split{
+                    head=[],
+                    midhead=[{a,100}],
+                    middle=[{b,100}],
+                    midtail=[{c,100}],
+                    tail=[{d,100},{e,100}]}, NodeSplit),
+    ?assertEqual(#split{
+                    midhead=[{f,50}],
+                    middle=[{g,50},{h,50}],
+                    midtail=[{i,50}]}, BlockSplit).
+
+equal_start_five_way_split_test() ->
+    Nodes = [{a,100},{b,100},{c,100},{d,100},{e,100}],
+    Blocks = [{f,50},{g,50},{h,50},{i,50}],
+    {NodeSplit,BlockSplit} = luwak_tree_utils:five_way_split(0, Nodes, 0, Blocks),
+    ?assertEqual(#split{
+                    head=[],
+                    midhead=[],
+                    middle=[{a,100},{b,100}],
+                    midtail=[],
+                    tail=[{c,100},{d,100},{e,100}]}, NodeSplit),
+    ?assertEqual(#split{
+                    midhead=[],
+                    middle=[{f,50},{g,50},{h,50},{i,50}],
+                    midtail=[]}, BlockSplit).
+
+appending_five_way_split_test() ->
+    Nodes = [{a,6},{b,6},{c,1}],
+    Blocks = [{d,2},{e,2},{f,2},{g,2},{h,2},{i,2},{j,2}],
+    _A = {NodeSplit,_BlockSplit} = luwak_tree_utils:five_way_split(0, Nodes, 12, Blocks),
+    ?assertEqual(#split{
+                    head=[{a,6},{b,6}],
+                    middle=[{c,1}]}, NodeSplit).
+
+first_block_five_way_split_test() ->
+    Nodes = [{a,1},{b,1},{c,1}],
+    Blocks = [{a,1}],
+    {NodeSplit, BlockSplit} = luwak_tree_utils:five_way_split(9, Nodes, 9, Blocks),
+    ?assertEqual(#split{middle=[{a,1}],tail=[{b,1},{c,1}]}, NodeSplit),
+    ?assertEqual(#split{middle=Blocks}, BlockSplit).
+
+subtree_split_test() ->
+    ListA = [{a,50},{b,50}, {c,50}],
+    ListB = [{d,150}, {e,100}],
+    ?assertEqual({{[{a,50},{b,50}],[{c,50}]},
+                  {[{d,150}],[{e,100}]}},
+                 luwak_tree_utils:shortest_subtree_split(ListA, ListB, 50, 0)).

test/test_helper.erl

+-module(test_helper).
+
+-export([riak_test/1]).
+
+riak_test(Fun) ->
+  start_riak(),
+  {ok, Riak} = riak:local_client(),
+  Ret = (catch Fun(Riak)),
+  stop_riak(),
+  case Ret of
+    {'EXIT', Err} -> throw(Err);
+    _ -> Ret
+  end.
+
+start_riak() ->
+    [] = os:cmd("epmd -daemon"),
+    case net_kernel:start([test_luwak, shortnames]) of
+        {ok,_} -> ok;
+        {error,{already_started,_}} -> ok
+    end,
+  % Dir = "/tmp/ring-" ++ os:getpid(),
+  % filelib:ensure_dir(Dir ++ "/"),
+  % application:set_env(riak_core, ring_state_dir, Dir),
+  application:set_env(riak_kv, storage_backend, riak_kv_cache_backend),
+  error_logger:delete_report_handler(error_logger_tty_h),
+  application:start(sasl),
+  error_logger:delete_report_handler(sasl_report_tty_h),
+  load_and_start_apps([crypto,
+                       os_mon,
+                       runtime_tools,
+                       mochiweb,
+                       webmachine,
+                       riak_core,
+                       luke,
+                       erlang_js,
+                       skerl,
+                       bitcask,
+                       riak_kv]).
+    
+stop_riak() ->
+  application:stop(riak_kv).
+  
+load_and_start_apps([]) -> ok;
+load_and_start_apps([App|Tail]) ->
+  application:load(App),
+  application:start(App),
+  load_and_start_apps(Tail).
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.