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/14 09:20:10 UTC

[couchdb] branch COUCHDB-3326-clustered-purge-pr1-misc-cleanup updated (55ff797 -> 207b3b0)

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

jiangphcn pushed a change to branch COUCHDB-3326-clustered-purge-pr1-misc-cleanup
in repository https://gitbox.apache.org/repos/asf/couchdb.git.


    omit 55ff797  Update fabric_doc_open eunit tests
    omit 82dabd7  Fix race on couch_db:reopen/1
    omit c96df45  Fix default security object handling
    omit 00d8379  Fix bug during purge
    omit 1e2e8af  Fix typos in couch_db_engine.erl
     add 1e4f32f  Ensure we only receive the correct DOWN message
     add 2a3b4e7  Merge pull request #1553 from apache/ref-match-1544
     add ed1db09  Fix session based replicator auth when endpoints have require_valid_user set
     new 45f9c55  Fix typos in couch_db_engine.erl
     new e994fc7  Fix bug during purge
     new b899b50  Fix default security object handling
     new 2949d2a  Fix race on couch_db:reopen/1
     new 207b3b0  Update fabric_doc_open eunit tests

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (55ff797)
            \
             N -- N -- N   refs/heads/COUCHDB-3326-clustered-purge-pr1-misc-cleanup (207b3b0)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/couch_mrview/src/couch_mrview_show.erl         |  4 +-
 .../src/couch_replicator_auth_session.erl          | 90 +++++++++++++++++++---
 2 files changed, 80 insertions(+), 14 deletions(-)


[couchdb] 01/05: Fix typos in couch_db_engine.erl

Posted by ji...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jiangphcn pushed a commit to branch COUCHDB-3326-clustered-purge-pr1-misc-cleanup
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 45f9c557134ae50a01e888bd18aa4e27f8ff504b
Author: Paul J. Davis <pa...@gmail.com>
AuthorDate: Fri Feb 5 11:49:34 2016 -0600

    Fix typos in couch_db_engine.erl
---
 src/couch/src/couch_db_engine.erl | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/couch/src/couch_db_engine.erl b/src/couch/src/couch_db_engine.erl
index 502faa7..4974201 100644
--- a/src/couch/src/couch_db_engine.erl
+++ b/src/couch/src/couch_db_engine.erl
@@ -168,7 +168,7 @@
 % value would be hard to report its ok to just return the
 % result of os:timestamp/0 as this will just disable idle
 % databases from automatically closing.
--callback last_activity(DbHandle::db_handle()) -> elrang:timestamp().
+-callback last_activity(DbHandle::db_handle()) -> erlang:timestamp().
 
 
 % All of the get_* functions may be called from many
@@ -436,9 +436,9 @@
 %
 %     1. start_key - Start iteration at the provided key or
 %        or just after if the key doesn't exist
-%     2. end_key - Stop iteration prior to visiting the provided
+%     2. end_key - Stop iteration just after the provided key
+%     3. end_key_gt - Stop iteration prior to visiting the provided
 %        key
-%     3. end_key_gt - Stop iteration just after the provided key
 %     4. dir - The atom fwd or rev. This is to be able to iterate
 %        over documents in reverse order. The logic for comparing
 %        start_key, end_key, and end_key_gt are then reversed (ie,
@@ -492,12 +492,12 @@
 % This function is called to fold over the documents (not local
 % documents) in order of their most recent update. Each document
 % in the database should have exactly one entry in this sequence.
-% If a document is updated during a call to this funciton it should
+% If a document is updated during a call to this function it should
 % not be included twice as that will probably lead to Very Bad Things.
 %
 % This should behave similarly to fold_docs/4 in that the supplied
 % user function should be invoked with a #full_doc_info{} record
-% as the first arugment and the current user accumulator as the
+% as the first argument and the current user accumulator as the
 % second argument. The same semantics for the return value from the
 % user function should be handled as in fold_docs/4.
 %


[couchdb] 04/05: Fix race on couch_db:reopen/1

Posted by ji...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jiangphcn pushed a commit to branch COUCHDB-3326-clustered-purge-pr1-misc-cleanup
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 2949d2a54bd1b527a2dd4d47a8a9b8f0987ee9b6
Author: Paul J. Davis <pa...@gmail.com>
AuthorDate: Thu Apr 26 11:39:58 2018 -0500

    Fix race on couch_db:reopen/1
    
    This fixes a minor race by opening the database before closing it. This
    was never found to be an issue in production and was just caught while
    contemplating the PSE test suite.
---
 src/couch/src/couch_db.erl | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/couch/src/couch_db.erl b/src/couch/src/couch_db.erl
index 65ca54a..40c673a 100644
--- a/src/couch/src/couch_db.erl
+++ b/src/couch/src/couch_db.erl
@@ -161,8 +161,11 @@ reopen(#db{} = Db) ->
     % We could have just swapped out the storage engine
     % for this database during a compaction so we just
     % reimplement this as a close/open pair now.
-    close(Db),
-    open(Db#db.name, [{user_ctx, Db#db.user_ctx} | Db#db.options]).
+    try
+        open(Db#db.name, [{user_ctx, Db#db.user_ctx} | Db#db.options])
+    after
+        close(Db)
+    end.
 
 
 % You shouldn't call this. Its part of the ref counting between


[couchdb] 02/05: Fix bug during purge

Posted by ji...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jiangphcn pushed a commit to branch COUCHDB-3326-clustered-purge-pr1-misc-cleanup
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit e994fc730841039b45302f0d776e5c4a67debbee
Author: Paul J. Davis <pa...@gmail.com>
AuthorDate: Thu Apr 26 11:36:49 2018 -0500

    Fix bug during purge
---
 src/couch/src/couch_db_updater.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/couch/src/couch_db_updater.erl b/src/couch/src/couch_db_updater.erl
index acb9ec1..40e836a 100644
--- a/src/couch/src/couch_db_updater.erl
+++ b/src/couch/src/couch_db_updater.erl
@@ -128,7 +128,7 @@ handle_call({purge_docs, IdRevs}, _From, Db) ->
                 % If we purged every #leaf{} in the doc record
                 % then we're removing it completely from the
                 % database.
-                FDIAcc;
+                {FDIAcc, SeqAcc0};
             _ ->
                 % Its possible to purge the #leaf{} that contains
                 % the update_seq where this doc sits in the update_seq


[couchdb] 05/05: Update fabric_doc_open eunit tests

Posted by ji...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jiangphcn pushed a commit to branch COUCHDB-3326-clustered-purge-pr1-misc-cleanup
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 207b3b04ac8dda3e60475e1a4381fc0122ec6ba6
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


[couchdb] 03/05: Fix default security object handling

Posted by ji...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jiangphcn pushed a commit to branch COUCHDB-3326-clustered-purge-pr1-misc-cleanup
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit b899b50764336ca781a94c3bd0472cf47c1c660b
Author: Paul J. Davis <pa...@gmail.com>
AuthorDate: Thu Apr 26 11:38:24 2018 -0500

    Fix default security object handling
    
    There's a race where if a database is opened with a default_security set
    and it crashes before first compact, and is then reopened after the
    default_security option has changed that it will pick the second
    security option. This change fixes the relatively obscure bug
    that was only found during testing.
---
 src/couch/src/couch_bt_engine.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/couch/src/couch_bt_engine.erl b/src/couch/src/couch_bt_engine.erl
index ee0d6d8..c5df11b 100644
--- a/src/couch/src/couch_bt_engine.erl
+++ b/src/couch/src/couch_bt_engine.erl
@@ -727,7 +727,7 @@ init_state(FilePath, Fd, Header0, Options) ->
     % to be written to disk.
     case Header /= Header0 of
         true ->
-            {ok, NewSt} = commit_data(St),
+            {ok, NewSt} = commit_data(St#st{needs_commit = true}),
             NewSt;
         false ->
             St