%% ------------------------------------------------------------------- %% %% Copyright (c) 2007-2015 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(machi_cr_client_test). -behaviour(gen_server). -include("machi.hrl"). -include("machi_projection.hrl"). -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). smoke_test() -> os:cmd("rm -rf ./data.a ./data.b ./data.c"), {ok, SupPid} = machi_flu_sup:start_link(), error_logger:tty(false), try Prefix = <<"pre">>, Chunk1 = <<"yochunk">>, Host = "localhost", PortBase = 4444, Os = [{ignore_stability_time, true}, {active_mode, false}], {ok,_}=machi_flu_psup:start_flu_package(a, PortBase+0, "./data.a", Os), {ok,_}=machi_flu_psup:start_flu_package(b, PortBase+1, "./data.b", Os), {ok,_}=machi_flu_psup:start_flu_package(c, PortBase+2, "./data.c", Os), D = orddict:from_list( [{a,{p_srvr,a,machi_flu1_client,"localhost",PortBase+0,[]}}, {b,{p_srvr,b,machi_flu1_client,"localhost",PortBase+1,[]}}, {c,{p_srvr,c,machi_flu1_client,"localhost",PortBase+2,[]}}]), %% Force the chain to repair & fully assemble as quickly as possible. %% 1. Use set_chain_members() on all 3 %% 2. Force a to run repair in a tight loop %% 3. Stop as soon as we see UPI=[a,b,c] and also author=c. %% Otherwise, we can have a race with later, minor %% projection changes which will change our understanding of %% the epoch id. (C is the author with highest weight.) %% 4. Wait until all others are using epoch id from #3. %% %% Damn, this is a pain to make 100% deterministic, bleh. ok = machi_chain_manager1:set_chain_members(a_chmgr, D), ok = machi_chain_manager1:set_chain_members(b_chmgr, D), ok = machi_chain_manager1:set_chain_members(c_chmgr, D), TickAll = fun() -> [begin Pid ! tick_check_environment, timer:sleep(50) end || Pid <- [a_chmgr,b_chmgr,c_chmgr] ] end, _ = lists:foldl( fun(_, [{c,[a,b,c]}]=Acc) -> Acc; (_, Acc) -> TickAll(), % has some sleep time inside Xs = [begin {ok, Prj} = machi_projection_store:read_latest_projection(PStore, private), {Prj#projection_v1.author_server, Prj#projection_v1.upi} end || PStore <- [a_pstore,b_pstore,c_pstore] ], lists:usort(Xs) end, undefined, lists:seq(1,10000)), %% Everyone is settled on the same damn epoch id. {ok, EpochID} = machi_flu1_client:get_latest_epochid(Host, PortBase+0, private), {ok, EpochID} = machi_flu1_client:get_latest_epochid(Host, PortBase+1, private), {ok, EpochID} = machi_flu1_client:get_latest_epochid(Host, PortBase+2, private), %% Whew ... ok, now start some damn tests. {ok, C1} = machi_cr_client:start_link([P || {_,P}<-orddict:to_list(D)]), machi_cr_client:append_chunk(C1, Prefix, Chunk1), %% {machi_flu_psup:stop_flu_package(c), timer:sleep(50)}, {ok, {Off1,Size1,File1}} = machi_cr_client:append_chunk(C1, Prefix, Chunk1), {ok, Chunk1} = machi_cr_client:read_chunk(C1, File1, Off1, Size1), {ok, PPP} = machi_flu1_client:read_latest_projection(Host, PortBase+0, private), %% Verify that the client's CR wrote to all of them. [{ok, Chunk1} = machi_flu1_client:read_chunk( Host, PortBase+X, EpochID, File1, Off1, Size1) || X <- [0,1,2] ], %% Test read repair: Manually write to head, then verify that %% read-repair fixes all. FooOff1 = Off1 + (1024*1024), [{error, not_written} = machi_flu1_client:read_chunk( Host, PortBase+X, EpochID, File1, FooOff1, Size1) || X <- [0,1,2] ], ok = machi_flu1_client:write_chunk(Host, PortBase+0, EpochID, File1, FooOff1, Chunk1), {ok, Chunk1} = machi_cr_client:read_chunk(C1, File1, FooOff1, Size1), [{X,{ok, Chunk1}} = {X,machi_flu1_client:read_chunk( Host, PortBase+X, EpochID, File1, FooOff1, Size1)} || X <- [0,1,2] ], %% Test read repair: Manually write to middle, then same checking. FooOff2 = Off1 + (2*1024*1024), Chunk2 = <<"Middle repair chunk">>, Size2 = size(Chunk2), ok = machi_flu1_client:write_chunk(Host, PortBase+1, EpochID, File1, FooOff2, Chunk2), {ok, Chunk2} = machi_cr_client:read_chunk(C1, File1, FooOff2, Size2), [{X,{ok, Chunk2}} = {X,machi_flu1_client:read_chunk( Host, PortBase+X, EpochID, File1, FooOff2, Size2)} || X <- [0,1,2] ], ok after error_logger:tty(true), catch application:stop(machi), exit(SupPid, normal) end. -endif. % TEST.