You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ji...@apache.org on 2018/08/09 02:46:51 UTC

[couchdb] 05/06: Update fabric_doc_open eunit tests

This is an automated email from the ASF dual-hosted git repository.

jiangphcn pushed a commit to branch COUCHDB-3326-clustered-purge-pr2-simplify-mem3-rep
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 3dfeeae5d89005b277edc58cef44600bdbf858ae
Author: Paul J. Davis <pa...@gmail.com>
AuthorDate: Wed May 23 12:32:48 2018 -0500

    Update fabric_doc_open eunit tests
    
    Modernize and fix the eunit tests in fabric_doc_open.erl
---
 src/fabric/src/fabric_doc_open.erl | 631 ++++++++++++++++++-------------------
 1 file changed, 310 insertions(+), 321 deletions(-)

diff --git a/src/fabric/src/fabric_doc_open.erl b/src/fabric/src/fabric_doc_open.erl
index 9c45bd9..93f73a8 100644
--- a/src/fabric/src/fabric_doc_open.erl
+++ b/src/fabric/src/fabric_doc_open.erl
@@ -174,85 +174,84 @@ format_reply(not_found, _) ->
 format_reply(Else, _) ->
     Else.
 
-is_r_met_test() ->
-    Workers0 = [],
-    Workers1 = [nil],
-    Workers2 = [nil,nil],
-
-    % Successful cases
-
-    ?assertEqual(
-        {true, foo},
-        is_r_met([], [fabric_util:kv(foo,2)], 2)
-    ),
-
-    ?assertEqual(
-        {true, foo},
-        is_r_met([], [fabric_util:kv(foo,3)], 2)
-    ),
-
-    ?assertEqual(
-        {true, foo},
-        is_r_met([], [fabric_util:kv(foo,1)], 1)
-    ),
-
-    ?assertEqual(
-        {true, foo},
-        is_r_met([], [fabric_util:kv(foo,2), fabric_util:kv(bar,1)], 2)
-    ),
-
-    ?assertEqual(
-        {true, bar},
-        is_r_met([], [fabric_util:kv(bar,1), fabric_util:kv(bar,2)], 2)
-    ),
-
-    ?assertEqual(
-        {true, bar},
-        is_r_met([], [fabric_util:kv(bar,2), fabric_util:kv(foo,1)], 2)
-    ),
-
-    % Not met, but wait for more messages
-
-    ?assertEqual(
-        wait_for_more,
-        is_r_met(Workers2, [fabric_util:kv(foo,1)], 2)
-    ),
-
-    ?assertEqual(
-        wait_for_more,
-        is_r_met(Workers2, [fabric_util:kv(foo,2)], 3)
-    ),
-
-    ?assertEqual(
-        wait_for_more,
-        is_r_met(Workers2, [fabric_util:kv(foo,1), fabric_util:kv(bar,1)], 2)
-    ),
-
-    % Not met, bail out
-
-    ?assertEqual(
-        no_more_workers,
-        is_r_met(Workers0, [fabric_util:kv(foo,1)], 2)
-    ),
-
-    ?assertEqual(
-        no_more_workers,
-        is_r_met(Workers1, [fabric_util:kv(foo,1)], 2)
-    ),
-
-    ?assertEqual(
-        no_more_workers,
-        is_r_met(Workers1, [fabric_util:kv(foo,1), fabric_util:kv(bar,1)], 2)
-    ),
-
-    ?assertEqual(
-        no_more_workers,
-        is_r_met(Workers1, [fabric_util:kv(foo,2)], 3)
-    ),
-
-    ok.
-
-handle_message_down_test() ->
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+
+setup() ->
+    meck:new([
+        couch_log,
+        couch_stats,
+        fabric,
+        fabric_util,
+        mem3,
+        rexi,
+        rexi_monitor
+    ], [passthrough]).
+
+
+teardown(_) ->
+    meck:unload().
+
+
+open_doc_test_() ->
+    {
+        foreach,
+        fun setup/0,
+        fun teardown/1,
+        [
+            t_is_r_met(),
+            t_handle_message_down(),
+            t_handle_message_exit(),
+            t_handle_message_reply(),
+            t_read_repair(),
+            t_handle_response_quorum_met(),
+            t_get_doc_info()
+        ]
+    }.
+
+
+t_is_r_met() ->
+    ?_test(begin
+        Workers0 = [],
+        Workers1 = [nil],
+        Workers2 = [nil, nil],
+
+        SuccessCases = [
+            {{true, foo}, [fabric_util:kv(foo, 2)], 2},
+            {{true, foo}, [fabric_util:kv(foo, 3)], 2},
+            {{true, foo}, [fabric_util:kv(foo, 1)], 1},
+            {{true, foo}, [fabric_util:kv(foo, 2), fabric_util:kv(bar, 1)], 2},
+            {{true, bar}, [fabric_util:kv(bar, 1), fabric_util:kv(bar, 2)], 2},
+            {{true, bar}, [fabric_util:kv(bar, 2), fabric_util:kv(foo, 1)], 2}
+        ],
+        lists:foreach(fun({Expect, Replies, Q}) ->
+            ?assertEqual(Expect, is_r_met(Workers0, Replies, Q))
+        end, SuccessCases),
+
+        WaitForMoreCases = [
+            {[fabric_util:kv(foo, 1)], 2},
+            {[fabric_util:kv(foo, 2)], 3},
+            {[fabric_util:kv(foo, 1), fabric_util:kv(bar, 1)], 2}
+        ],
+        lists:foreach(fun({Replies, Q}) ->
+            ?assertEqual(wait_for_more, is_r_met(Workers2, Replies, Q))
+        end, WaitForMoreCases),
+
+        FailureCases = [
+            {Workers0, [fabric_util:kv(foo, 1)], 2},
+            {Workers1, [fabric_util:kv(foo, 1)], 2},
+            {Workers1, [fabric_util:kv(foo, 1), fabric_util:kv(bar, 1)], 2},
+            {Workers1, [fabric_util:kv(foo, 2)], 3}
+        ],
+        lists:foreach(fun({Workers, Replies, Q}) ->
+            ?assertEqual(no_more_workers, is_r_met(Workers, Replies, Q))
+        end, FailureCases)
+    end).
+
+
+t_handle_message_down() ->
     Node0 = 'foo@localhost',
     Node1 = 'bar@localhost',
     Down0 = {rexi_DOWN, nil, {nil, Node0}, nil},
@@ -261,279 +260,269 @@ handle_message_down_test() ->
     Worker1 = #shard{node=Node1},
     Workers1 = Workers0 ++ [Worker1],
 
-    % Stop when no more workers are left
-    ?assertEqual(
-        {stop, #acc{workers=[]}},
-        handle_message(Down0, nil, #acc{workers=Workers0})
-    ),
+    ?_test(begin
+        % Stop when no more workers are left
+        ?assertEqual(
+            {stop, #acc{workers=[]}},
+            handle_message(Down0, nil, #acc{workers=Workers0})
+        ),
 
-    % Continue when we have more workers
-    ?assertEqual(
-        {ok, #acc{workers=[Worker1]}},
-        handle_message(Down0, nil, #acc{workers=Workers1})
-    ),
+        % Continue when we have more workers
+        ?assertEqual(
+            {ok, #acc{workers=[Worker1]}},
+            handle_message(Down0, nil, #acc{workers=Workers1})
+        ),
 
-    % A second DOWN removes the remaining workers
-    ?assertEqual(
-        {stop, #acc{workers=[]}},
-        handle_message(Down1, nil, #acc{workers=[Worker1]})
-    ),
+        % A second DOWN removes the remaining workers
+        ?assertEqual(
+            {stop, #acc{workers=[]}},
+            handle_message(Down1, nil, #acc{workers=[Worker1]})
+        )
+    end).
 
-    ok.
 
-handle_message_exit_test() ->
+t_handle_message_exit() ->
     Exit = {rexi_EXIT, nil},
     Worker0 = #shard{ref=erlang:make_ref()},
     Worker1 = #shard{ref=erlang:make_ref()},
 
-    % Only removes the specified worker
-    ?assertEqual(
-        {ok, #acc{workers=[Worker1]}},
-        handle_message(Exit, Worker0, #acc{workers=[Worker0, Worker1]})
-    ),
-
-    ?assertEqual(
-        {ok, #acc{workers=[Worker0]}},
-        handle_message(Exit, Worker1, #acc{workers=[Worker0, Worker1]})
-    ),
+    ?_test(begin
+        % Only removes the specified worker
+        ?assertEqual(
+            {ok, #acc{workers=[Worker1]}},
+            handle_message(Exit, Worker0, #acc{workers=[Worker0, Worker1]})
+        ),
 
-    % We bail if it was the last worker
-    ?assertEqual(
-        {stop, #acc{workers=[]}},
-        handle_message(Exit, Worker0, #acc{workers=[Worker0]})
-    ),
+        ?assertEqual(
+            {ok, #acc{workers=[Worker0]}},
+            handle_message(Exit, Worker1, #acc{workers=[Worker0, Worker1]})
+        ),
 
-    ok.
+        % We bail if it was the last worker
+        ?assertEqual(
+            {stop, #acc{workers=[]}},
+            handle_message(Exit, Worker0, #acc{workers=[Worker0]})
+        )
+    end).
 
-handle_message_reply_test() ->
-    start_meck_(),
-    meck:expect(rexi, kill, fun(_, _) -> ok end),
 
+t_handle_message_reply() ->
     Worker0 = #shard{ref=erlang:make_ref()},
     Worker1 = #shard{ref=erlang:make_ref()},
     Worker2 = #shard{ref=erlang:make_ref()},
     Workers = [Worker0, Worker1, Worker2],
     Acc0 = #acc{workers=Workers, r=2, replies=[]},
 
-    % Test that we continue when we haven't met R yet
-    ?assertEqual(
-        {ok, Acc0#acc{
-            workers=[Worker0, Worker1],
-            replies=[fabric_util:kv(foo,1)]
-        }},
-        handle_message(foo, Worker2, Acc0)
-    ),
-
-    ?assertEqual(
-        {ok, Acc0#acc{
-            workers=[Worker0, Worker1],
-            replies=[fabric_util:kv(bar,1), fabric_util:kv(foo,1)]
-        }},
-        handle_message(bar, Worker2, Acc0#acc{
-            replies=[fabric_util:kv(foo,1)]
-        })
-    ),
-
-    % Test that we don't get a quorum when R isn't met. q_reply
-    % isn't set and state remains unchanged and {stop, NewAcc}
-    % is returned. Bit subtle on the assertions here.
-
-    ?assertEqual(
-        {stop, Acc0#acc{workers=[],replies=[fabric_util:kv(foo,1)]}},
-        handle_message(foo, Worker0, Acc0#acc{workers=[Worker0]})
-    ),
-
-    ?assertEqual(
-        {stop, Acc0#acc{
-            workers=[],
-            replies=[fabric_util:kv(bar,1), fabric_util:kv(foo,1)]
-        }},
-        handle_message(bar, Worker0, Acc0#acc{
-            workers=[Worker0],
-            replies=[fabric_util:kv(foo,1)]
-        })
-    ),
-
-    % Check that when R is met we stop with a new state and
-    % a q_reply.
-
-    ?assertEqual(
-        {stop, Acc0#acc{
-            workers=[],
-            replies=[fabric_util:kv(foo,2)],
-            state=r_met,
-            q_reply=foo
-        }},
-        handle_message(foo, Worker1, Acc0#acc{
-            workers=[Worker0, Worker1],
-            replies=[fabric_util:kv(foo,1)]
-        })
-    ),
-
-    ?assertEqual(
-        {stop, Acc0#acc{
-            workers=[],
-            r=1,
-            replies=[fabric_util:kv(foo,1)],
-            state=r_met,
-            q_reply=foo
-        }},
-        handle_message(foo, Worker0, Acc0#acc{r=1})
-    ),
-
-    ?assertEqual(
-        {stop, Acc0#acc{
-            workers=[],
-            replies=[fabric_util:kv(bar,1), fabric_util:kv(foo,2)],
-            state=r_met,
-            q_reply=foo
-        }},
-        handle_message(foo, Worker0, Acc0#acc{
-            workers=[Worker0],
-            replies=[fabric_util:kv(bar,1), fabric_util:kv(foo,1)]
-        })
-    ),
-
-    stop_meck_(),
-    ok.
-
-read_repair_test() ->
-    start_meck_(),
-    meck:expect(couch_log, notice, fun(_, _) -> ok end),
-    meck:expect(couch_stats, increment_counter, fun(_) -> ok end),
-
+    ?_test(begin
+        meck:expect(rexi, kill, fun(_, _) -> ok end),
+
+        % Test that we continue when we haven't met R yet
+        ?assertMatch(
+            {ok, #acc{
+                workers=[Worker0, Worker1],
+                replies=[{foo, {foo, 1}}]
+            }},
+            handle_message(foo, Worker2, Acc0)
+        ),
+
+        ?assertMatch(
+            {ok, #acc{
+                workers=[Worker0, Worker1],
+                replies=[{bar, {bar, 1}}, {foo, {foo, 1}}]
+            }},
+            handle_message(bar, Worker2, Acc0#acc{
+                replies=[{foo, {foo, 1}}]
+            })
+        ),
+
+        % Test that we don't get a quorum when R isn't met. q_reply
+        % isn't set and state remains unchanged and {stop, NewAcc}
+        % is returned. Bit subtle on the assertions here.
+
+        ?assertMatch(
+            {stop, #acc{workers=[], replies=[{foo, {foo, 1}}]}},
+            handle_message(foo, Worker0, Acc0#acc{workers=[Worker0]})
+        ),
+
+        ?assertMatch(
+            {stop, #acc{
+                workers=[],
+                replies=[{bar, {bar, 1}}, {foo, {foo, 1}}]
+            }},
+            handle_message(bar, Worker0, Acc0#acc{
+                workers=[Worker0],
+                replies=[{foo, {foo, 1}}]
+            })
+        ),
+
+        % Check that when R is met we stop with a new state and
+        % a q_reply.
+
+        ?assertMatch(
+            {stop, #acc{
+                workers=[],
+                replies=[{foo, {foo, 2}}],
+                state=r_met,
+                q_reply=foo
+            }},
+            handle_message(foo, Worker1, Acc0#acc{
+                workers=[Worker0, Worker1],
+                replies=[{foo, {foo, 1}}]
+            })
+        ),
+
+        ?assertEqual(
+            {stop, #acc{
+                workers=[],
+                r=1,
+                replies=[{foo, {foo, 1}}],
+                state=r_met,
+                q_reply=foo
+            }},
+            handle_message(foo, Worker0, Acc0#acc{r=1})
+        ),
+
+        ?assertMatch(
+            {stop, #acc{
+                workers=[],
+                replies=[{bar, {bar, 1}}, {foo, {foo, 2}}],
+                state=r_met,
+                q_reply=foo
+            }},
+            handle_message(foo, Worker0, Acc0#acc{
+                workers=[Worker0],
+                replies=[{bar, {bar, 1}}, {foo, {foo, 1}}]
+            })
+        )
+    end).
+
+
+t_read_repair() ->
     Foo1 = {ok, #doc{revs = {1,[<<"foo">>]}}},
     Foo2 = {ok, #doc{revs = {2,[<<"foo2">>,<<"foo">>]}}},
     NFM = {not_found, missing},
 
-    % Test when we have actual doc data to repair
-
-    meck:expect(fabric, update_docs, fun(_, [_], _) -> {ok, []} end),
-    Acc0 = #acc{
-        dbname = <<"name">>,
-        replies = [fabric_util:kv(Foo1,1)]
-    },
-    ?assertEqual(Foo1, read_repair(Acc0)),
-
-    meck:expect(fabric, update_docs, fun(_, [_, _], _) -> {ok, []} end),
-    Acc1 = #acc{
-        dbname = <<"name">>,
-        replies = [fabric_util:kv(Foo1,1), fabric_util:kv(Foo2,1)]
-    },
-    ?assertEqual(Foo2, read_repair(Acc1)),
+    ?_test(begin
+        meck:expect(couch_log, notice, fun(_, _) -> ok end),
+        meck:expect(couch_stats, increment_counter, fun(_) -> ok end),
 
-    % Test when we have nothing but errors
+        % Test when we have actual doc data to repair
+        meck:expect(fabric, update_docs, fun(_, [_], _) -> {ok, []} end),
+        Acc0 = #acc{
+            dbname = <<"name">>,
+            replies = [fabric_util:kv(Foo1,1)]
+        },
+        ?assertEqual(Foo1, read_repair(Acc0)),
 
-    Acc2 = #acc{replies=[fabric_util:kv(NFM, 1)]},
-    ?assertEqual(NFM, read_repair(Acc2)),
+        meck:expect(fabric, update_docs, fun(_, [_, _], _) -> {ok, []} end),
+        Acc1 = #acc{
+            dbname = <<"name">>,
+            replies = [fabric_util:kv(Foo1,1), fabric_util:kv(Foo2,1)]
+        },
+        ?assertEqual(Foo2, read_repair(Acc1)),
 
-    Acc3 = #acc{replies=[fabric_util:kv(NFM,1), fabric_util:kv(foo,2)]},
-    ?assertEqual(NFM, read_repair(Acc3)),
+        % Test when we have nothing but errors
+        Acc2 = #acc{replies=[fabric_util:kv(NFM, 1)]},
+        ?assertEqual(NFM, read_repair(Acc2)),
 
-    Acc4 = #acc{replies=[fabric_util:kv(foo,1), fabric_util:kv(bar,1)]},
-    ?assertEqual(bar, read_repair(Acc4)),
+        Acc3 = #acc{replies=[fabric_util:kv(NFM,1), fabric_util:kv(foo,2)]},
+        ?assertEqual(NFM, read_repair(Acc3)),
 
-    stop_meck_(),
-    ok.
+        Acc4 = #acc{replies=[fabric_util:kv(foo,1), fabric_util:kv(bar,1)]},
+        ?assertEqual(bar, read_repair(Acc4))
+    end).
 
-handle_response_quorum_met_test() ->
-    start_meck_(),
-    meck:expect(couch_log, notice, fun(_, _) -> ok end),
-    meck:expect(fabric, update_docs, fun(_, _, _) -> {ok, []} end),
-    meck:expect(couch_stats, increment_counter, fun(_) -> ok end),
 
+t_handle_response_quorum_met() ->
     Foo1 = {ok, #doc{revs = {1,[<<"foo">>]}}},
     Foo2 = {ok, #doc{revs = {2,[<<"foo2">>,<<"foo">>]}}},
     Bar1 = {ok, #doc{revs = {1,[<<"bar">>]}}},
 
-    BasicOkAcc = #acc{
-        state=r_met,
-        replies=[fabric_util:kv(Foo1,2)],
-        q_reply=Foo1
-    },
-    ?assertEqual(Foo1, handle_response(BasicOkAcc)),
+    ?_test(begin
+        meck:expect(couch_log, notice, fun(_, _) -> ok end),
+        meck:expect(fabric, update_docs, fun(_, _, _) -> {ok, []} end),
+        meck:expect(couch_stats, increment_counter, fun(_) -> ok end),
 
-    WithAncestorsAcc = #acc{
-        state=r_met,
-        replies=[fabric_util:kv(Foo1,1), fabric_util:kv(Foo2,2)],
-        q_reply=Foo2
-    },
-    ?assertEqual(Foo2, handle_response(WithAncestorsAcc)),
-
-    % This also checks when the quorum isn't the most recent
-    % revision.
-    DeeperWinsAcc = #acc{
-        state=r_met,
-        replies=[fabric_util:kv(Foo1,2), fabric_util:kv(Foo2,1)],
-        q_reply=Foo1
-    },
-    ?assertEqual(Foo2, handle_response(DeeperWinsAcc)),
-
-    % Check that we return the proper doc based on rev
-    % (ie, pos is equal)
-    BiggerRevWinsAcc = #acc{
-        state=r_met,
-        replies=[fabric_util:kv(Foo1,1), fabric_util:kv(Bar1,2)],
-        q_reply=Bar1
-    },
-    ?assertEqual(Foo1, handle_response(BiggerRevWinsAcc)),
-
-    % r_not_met is a proxy to read_repair so we rely on
-    % read_repair_test for those conditions.
-
-    stop_meck_(),
-    ok.
-
-get_doc_info_test() ->
-    start_meck_(),
-    meck:new([mem3, rexi_monitor, fabric_util]),
-    meck:expect(fabric, update_docs, fun(_, _, _) -> {ok, []} end),
-    meck:expect(couch_stats, increment_counter, fun(_) -> ok end),
-    meck:expect(fabric_util, submit_jobs, fun(_, _, _) -> ok end),
-    meck:expect(fabric_util, create_monitors, fun(_) -> ok end),
-    meck:expect(rexi_monitor, stop, fun(_) -> ok end),
-    meck:expect(mem3, shards, fun(_, _) -> ok end),
-    meck:expect(mem3, n, fun(_) -> 3 end),
-    meck:expect(mem3, quorum, fun(_) -> 2 end),
-
-    meck:expect(fabric_util, recv, fun(_, _, _, _) ->
-        {ok, #acc{state = r_not_met}}
-    end),
-    Rsp1 = fabric_doc_open:go("test", "one", [doc_info]),
-    ?assertEqual({error, quorum_not_met}, Rsp1),
-
-    Rsp2 = fabric_doc_open:go("test", "one", [{doc_info, full}]),
-    ?assertEqual({error, quorum_not_met}, Rsp2),
-
-    meck:expect(fabric_util, recv, fun(_, _, _, _) ->
-        {ok, #acc{state = r_met, q_reply = not_found}}
-    end),
-    MissingRsp1 = fabric_doc_open:go("test", "one", [doc_info]),
-    ?assertEqual({not_found, missing}, MissingRsp1),
-    MissingRsp2 = fabric_doc_open:go("test", "one", [{doc_info, full}]),
-    ?assertEqual({not_found, missing}, MissingRsp2),
-
-    meck:expect(fabric_util, recv, fun(_, _, _, _) ->
-        A = #doc_info{},
-        {ok, #acc{state = r_met, q_reply = {ok, A}}}
-    end),
-    {ok, Rec1} = fabric_doc_open:go("test", "one", [doc_info]),
-    ?assert(is_record(Rec1, doc_info)),
-
-    meck:expect(fabric_util, recv, fun(_, _, _, _) ->
-        A = #full_doc_info{deleted = true},
-        {ok, #acc{state = r_met, q_reply = {ok, A}}}
-    end),
-    Rsp3 = fabric_doc_open:go("test", "one", [{doc_info, full}]),
-    ?assertEqual({not_found, deleted}, Rsp3),
-    {ok, Rec2} = fabric_doc_open:go("test", "one", [{doc_info, full},deleted]),
-    ?assert(is_record(Rec2, full_doc_info)),
-
-    meck:unload([mem3, rexi_monitor, fabric_util]),
-    stop_meck_().
-
-start_meck_() ->
-    meck:new([couch_log, rexi, fabric, couch_stats]).
-
-stop_meck_() ->
-    meck:unload([couch_log, rexi, fabric, couch_stats]).
+        BasicOkAcc = #acc{
+            state=r_met,
+            replies=[fabric_util:kv(Foo1,2)],
+            q_reply=Foo1
+        },
+        ?assertEqual(Foo1, handle_response(BasicOkAcc)),
+
+        WithAncestorsAcc = #acc{
+            state=r_met,
+            replies=[fabric_util:kv(Foo1,1), fabric_util:kv(Foo2,2)],
+            q_reply=Foo2
+        },
+        ?assertEqual(Foo2, handle_response(WithAncestorsAcc)),
+
+        % This also checks when the quorum isn't the most recent
+        % revision.
+        DeeperWinsAcc = #acc{
+            state=r_met,
+            replies=[fabric_util:kv(Foo1,2), fabric_util:kv(Foo2,1)],
+            q_reply=Foo1
+        },
+        ?assertEqual(Foo2, handle_response(DeeperWinsAcc)),
+
+        % Check that we return the proper doc based on rev
+        % (ie, pos is equal)
+        BiggerRevWinsAcc = #acc{
+            state=r_met,
+            replies=[fabric_util:kv(Foo1,1), fabric_util:kv(Bar1,2)],
+            q_reply=Bar1
+        },
+        ?assertEqual(Foo1, handle_response(BiggerRevWinsAcc))
+
+        % r_not_met is a proxy to read_repair so we rely on
+        % read_repair_test for those conditions.
+    end).
+
+
+t_get_doc_info() ->
+    ?_test(begin
+        meck:expect(fabric, update_docs, fun(_, _, _) -> {ok, []} end),
+        meck:expect(couch_stats, increment_counter, fun(_) -> ok end),
+        meck:expect(fabric_util, submit_jobs, fun(_, _, _) -> ok end),
+        meck:expect(fabric_util, create_monitors, fun(_) -> ok end),
+        meck:expect(rexi_monitor, stop, fun(_) -> ok end),
+        meck:expect(mem3, shards, fun(_, _) -> ok end),
+        meck:expect(mem3, n, fun(_) -> 3 end),
+        meck:expect(mem3, quorum, fun(_) -> 2 end),
+
+        meck:expect(fabric_util, recv, fun(_, _, _, _) ->
+            {ok, #acc{state = r_not_met}}
+        end),
+        Rsp1 = fabric_doc_open:go("test", "one", [doc_info]),
+        ?assertEqual({error, quorum_not_met}, Rsp1),
+
+        Rsp2 = fabric_doc_open:go("test", "one", [{doc_info, full}]),
+        ?assertEqual({error, quorum_not_met}, Rsp2),
+
+        meck:expect(fabric_util, recv, fun(_, _, _, _) ->
+            {ok, #acc{state = r_met, q_reply = not_found}}
+        end),
+        MissingRsp1 = fabric_doc_open:go("test", "one", [doc_info]),
+        ?assertEqual({not_found, missing}, MissingRsp1),
+        MissingRsp2 = fabric_doc_open:go("test", "one", [{doc_info, full}]),
+        ?assertEqual({not_found, missing}, MissingRsp2),
+
+        meck:expect(fabric_util, recv, fun(_, _, _, _) ->
+            A = #doc_info{},
+            {ok, #acc{state = r_met, q_reply = {ok, A}}}
+        end),
+        {ok, Rec1} = fabric_doc_open:go("test", "one", [doc_info]),
+        ?assert(is_record(Rec1, doc_info)),
+
+        meck:expect(fabric_util, recv, fun(_, _, _, _) ->
+            A = #full_doc_info{deleted = true},
+            {ok, #acc{state = r_met, q_reply = {ok, A}}}
+        end),
+        Rsp3 = fabric_doc_open:go("test", "one", [{doc_info, full}]),
+        ?assertEqual({not_found, deleted}, Rsp3),
+        {ok, Rec2} = fabric_doc_open:go("test", "one", [{doc_info, full},deleted]),
+        ?assert(is_record(Rec2, full_doc_info))
+    end).
+
+-endif.
\ No newline at end of file