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:45:11 UTC

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

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 7b91b90  Update fabric_doc_open eunit tests
    omit c3d7bf8  Fix race on couch_db:reopen/1
    omit 39d7803  Fix default security object handling
    omit 127bfda  Fix bug during purge
    omit 6d13153  Fix typos in couch_db_engine.erl
     add 5290a32  Update Jenkins build process:
     add 6d44e17  Add _approx_count_distinct as a builtin reduce function (#1346)
     add 8a46473  Add hyper app to dependencies
     add 0392c51  Finalize in couch_mrview, but make it optional
     add 5fa3c43  Use finalize operation to simplify _stats
     add 398ac18  Ignore trailing characters in a builtin reduce
     add 62f71c0  Fix container for package-building step
     add 994b370  Jenkinsfile: typo
     add 71c33b1  Update skip_deps for 3rd parties eunit (#1386)
     add 2bf04a0  Revert "Introduce bin_opt_info erl_opts compilation option"
     add 76790d5  Add compile's command line options
     add 2fe402f  Remove debug_info from compile options
     add dfa8780  Make bin_opt_info optional based on env variable
     add 41decfa  Allow custom compile options with env variable
     add c7d35c3  Merge pull request #1387 from cloudant/make-bin_opt_info-optional
     add 000766c  Fix active size calculations for views
     add aebdbc4  Optimize couch_key_tree:stem/2
     add 3c98385  Fix couch_key_tree_tests.erl
     add f040d75  Add set_mqd_off_heap utility function
     add a13efba  Call `set_mqd_off_heap` for critical processes
     add f3a0f42  refactor process_request to not drop req (#1375)
     add fe53e43  Prepare to fabric attachment receiver from a fun closure to a tuple
     add 5b5c8a1  Add constant index fields to sort based on the selector (#1376)
     add 103a062  Update snappy dep to CouchDB-1.0.1 with 21.0 support
     add e6272de  Update build dependency docs for FreeBSD
     add 1209036  Add regression runs on new dedicated FreeBSD VM
     add 3358668  fix(_view changes feed): fix function_clause crash in couch_native_process. Crash was caused by a missing implementation of ddoc function for <<"views">> FunPath, implementation is based on FilterFun but matches return values of the erlang:put()  which is called in the native Emit function and also expects ok and false when docs were not emitted.
     add 0377e53  tests(couch_changes): add tests for changes feed filtering using an Erlang view
     add d36149e  Merge pull request #1401 from Spotme/spotme/fix/couch-native-process
     add 5bbfbeb  Don't set context for compaction files during db delete (#1419)
     add 73f1565  remove mention of os daemons and externals in ini files
     add 54577f1  allow socket server configuration for TLS httpd
     add 142eb6b  feat: avoid double builds on PRs
     add 1b15d4c  feat: remove duplicate authentication check
     add 7dfed0c  Added tests for checking http status code depending on cluster quorum
     add bfc610f  Make stem_interactive_updates option work again
     add 80e431f  Fix for issue #1136 - Error 500 deleting DB without quorum
     add 177c22d  Deletion responds 200 after a response from every node, and 202 in other case
     add 71cf9f4  Adjust deletion tests in different cluster quorum conditions
     add 45a0ad9  Add `conflicts: true` option to mango selectors
     add 572234f  Add tests for mango conflict finding
     add e928b88  hook up proxy auth handler to chttpd
     add aa73e4e  Views now retain update_seq after compaction.
     add a5858b9  Replace R16B03 with 17.5.3 for PR#1427
     add 0f130cb  Drop Erlang R16 support
     add 4ea7210  config: improve handling of admin-supplied changes
     add 768e9eb  build: ease pattern matching to be less pedantic about RC
     add a82419b  build: release candidate tarball should have -RCx
     add 5c93cb7  Use couch_util:trim for greater erlang compatibility
     add 3c3546c  string:trim() compat for couch_util:trim()
     add fa3c812  bump deps
     add 1703998  raise timeouts in attachment tests
     add 215f49b  wait for db deletion before db re-creation. Closes #1197
     add dacb658  Clarify bad index creation error messages
     add dd3a6b4  validate bind address by @wyc
     add 8e5caaf  demote notice to debug logs by @wyc
     add 45583af  Optionally prevent non-admins from accessing /_all_dbs
     add 8c2b86a  improve ddoc test reliablilty by waiting for ddoc deletion
     add 3acf15f  Make MD5 hash implementation configurable (#1171)
     add 79eb1af  Report git sha on welcome request
     add 1d69790  Improve detection of git tags/dirty status
     add 6ed65e8  add retry to test_request:request()
     add 3ef3149  re-raise max_http_request_size to 4GB
     add e2f7561  Add missing default case clause, fixes #1450
     add 5678245  Switch fabric attachment receiver to use messages
     add a239f76  bump hyper dependency, fix Windows build
     add c94cc4c  Revert "Make loginUser wait for successful authentication"
     add 91f84f3  Revert "Replace resource expensive bcrypt test with shorter version (#1231)"
     add 7597abf  Revert "Add bcrypt hashing option"
     add 98eec31  Enable replication client _session auth by default
     add b1fbbb1  Bump fauxton dependency
     add cec965f  [travis] 20.1 -> 20.3
     add 10c19dc  bump docs dependency
     add 56bd13d  Improve logging from test_util
     add 2446758  bump fauxton
     add cc1360d  remove obsolete update_notification feature
     add aeced65  Fix _stats reducer when map function emits array
     add 17aec1f  Merge pull request #1484 from cloudant/fix-stats-reducer-for-array
     add d29011b  Fixed use of find ... -printf "%f" on Mac OS by replacing it with -exec basename
     add 0cbaefc  added missing dependencies for Debian-based systems
     add 99e801e  Use new mochiweb recbuf|sndbuf undefined setting
     add 54b2eaa  Bump fauxton
     add 0fefc85  Rename 'module' data provider to 'static_module'
     add cf65280  Add 'callback_module' provider
     add 7a2a390  Update documentation
     add d98e3e1  Merge pull request #1432 from cloudant/support-callback-module-data-provider
     add a7f2aa5  Add rexi ping message
     add a6bc72e  Move mango selector matching to the shard level
     new 1e2e8af  Fix typos in couch_db_engine.erl
     new 00d8379  Fix bug during purge
     new c96df45  Fix default security object handling
     new 82dabd7  Fix race on couch_db:reopen/1
     new 55ff797  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   (7b91b90)
            \
             N -- N -- N   refs/heads/COUCHDB-3326-clustered-purge-pr1-misc-cleanup (55ff797)

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:
 .gitignore                                         |   2 +-
 .travis.yml                                        |  11 +-
 INSTALL.Unix.md                                    |   9 +-
 Jenkinsfile                                        | 153 ++++++++++----
 LICENSE                                            | 135 ++-----------
 Makefile                                           |  62 ++++--
 Makefile.win                                       |  45 ++++-
 NOTICE                                             |   9 +-
 build-aux/couchdb-build-release.sh                 |   6 +-
 configure                                          |   9 +
 rebar.config.script                                |  25 ++-
 rel/overlay/etc/default.ini                        |  53 ++---
 rel/overlay/etc/local.ini                          |  16 +-
 rel/reltool.config                                 |   4 +-
 src/chttpd/src/chttpd.erl                          |  70 ++++++-
 src/chttpd/src/chttpd_auth.erl                     |   4 +
 src/chttpd/src/chttpd_auth_request.erl             |   5 +-
 src/chttpd/src/chttpd_db.erl                       |   1 -
 src/chttpd/src/chttpd_misc.erl                     |  11 +-
 src/chttpd/test/chttpd_welcome_test.erl            |   2 +
 src/couch/rebar.config.script                      |  17 +-
 src/couch/src/couch.app.src                        |   4 +-
 src/couch/src/couch.erl                            |   1 -
 src/couch/src/couch_auth_cache.erl                 |   7 -
 src/couch/src/couch_bt_engine.erl                  |   6 +-
 src/couch/src/couch_db.erl                         |  12 +-
 src/couch/src/couch_db_updater.erl                 |  38 ++--
 src/couch/src/couch_file.erl                       |   8 +-
 src/couch/src/{couch_rand.erl => couch_hash.erl}   |  50 ++---
 src/couch/src/couch_httpd.erl                      |   2 +-
 src/couch/src/couch_httpd_auth.erl                 |  12 +-
 src/couch/src/couch_httpd_misc_handlers.erl        |   2 +-
 src/couch/src/couch_key_tree.erl                   |  83 +++++++-
 src/couch/src/couch_native_process.erl             |  16 +-
 src/couch/src/couch_passwords.erl                  |  19 +-
 src/couch/src/couch_query_servers.erl              |  80 +++++++-
 src/couch/src/couch_server.erl                     |   7 +-
 src/couch/src/couch_stream.erl                     |  18 +-
 src/couch/src/couch_users_db.erl                   |  10 +-
 src/couch/src/couch_util.erl                       |  50 ++++-
 src/couch/src/test_engine_util.erl                 |  11 +-
 src/couch/src/test_request.erl                     |   6 +-
 src/couch/src/test_util.erl                        |   3 +
 src/couch/test/couch_changes_tests.erl             |  38 +++-
 src/couch/test/couch_key_tree_tests.erl            | 197 +++++++++---------
 src/couch/test/couch_passwords_tests.erl           |  42 +---
 src/couch/test/couchdb_attachments_tests.erl       |  12 +-
 src/couch_epi/README.md                            |  35 +++-
 src/couch_epi/src/couch_epi_data.erl               |  13 +-
 src/couch_epi/src/couch_epi_sup.erl                |   5 +-
 src/couch_epi/src/couch_epi_util.erl               |   2 +-
 src/couch_epi/test/couch_epi_tests.erl             |  67 ++++++-
 src/couch_event/src/couch_event_os_sup.erl         |  82 --------
 src/couch_event/src/couch_event_sup2.erl           |   7 -
 .../test/couch_index_ddoc_updated_tests.erl        |   2 +-
 src/couch_log/src/couch_log_server.erl             |   1 +
 src/couch_mrview/src/couch_mrview.erl              |  32 ++-
 src/couch_mrview/src/couch_mrview_compactor.erl    |   2 +
 src/couch_mrview/src/couch_mrview_index.erl        |   3 +-
 src/couch_mrview/src/couch_mrview_util.erl         |  25 ++-
 .../test/couch_mrview_index_info_tests.erl         |  96 ++++++---
 src/couch_replicator/src/couch_replicator_auth.erl |   2 +-
 src/couch_replicator/src/couch_replicator_ids.erl  |   2 +-
 .../test/couch_replicator_many_leaves_tests.erl    |   2 +-
 .../test/couch_replicator_test_helper.erl          |  12 +-
 src/ddoc_cache/src/ddoc_cache_lru.erl              |   1 +
 src/fabric/src/fabric.erl                          |   9 +-
 src/fabric/src/fabric_db_delete.erl                |   6 +-
 ...ric_doc_attachments.erl => fabric_doc_atts.erl} |  28 ++-
 src/fabric/src/fabric_rpc.erl                      |  26 ++-
 src/fabric/src/fabric_view.erl                     |   3 +-
 src/mango/src/mango_cursor.erl                     |  18 +-
 src/mango/src/mango_cursor_view.erl                | 120 +++++++++--
 src/mango/src/mango_error.erl                      |   4 +-
 src/mango/src/mango_execution_stats.erl            |   7 +-
 src/mango/src/mango_idx.erl                        |  36 +---
 src/mango/src/mango_idx_special.erl                |  13 +-
 src/mango/src/mango_idx_view.erl                   |  30 ++-
 src/mango/src/mango_selector.erl                   | 113 ++++++++++-
 src/mango/test/02-basic-find-test.py               |   7 +
 src/mango/test/18-json-sort.py                     | 222 +++++++++++++++++++++
 src/mango/test/19-find-conflicts.py                |  41 ++++
 src/mango/test/20-no-timeout-test.py               |  38 ++++
 src/mango/test/mango.py                            |   5 +
 src/mem3/src/mem3_rep.erl                          |   6 +-
 src/mem3/src/mem3_shards.erl                       |   1 +
 src/rexi/src/rexi.erl                              |   9 +
 src/rexi/src/rexi_server.erl                       |   1 +
 src/rexi/src/rexi_utils.erl                        |   2 +
 src/setup/src/setup.erl                            |  43 ++--
 test/javascript/run                                |   8 +-
 .../with-quorum/attachments.js}                    |  30 +--
 .../with-quorum/attachments_delete.js}             |  28 ++-
 .../attachments_delete_overridden_quorum.js        |  36 ++++
 .../with-quorum/attachments_overridden_quorum.js   |  40 ++++
 .../with-quorum/{db-creation.js => db_creation.js} |   0
 ...reation.js => db_creation_overridden_quorum.js} |  11 +-
 .../db-creation.js => with-quorum/db_deletion.js}  |  16 +-
 ...reation.js => db_deletion_overridden_quorum.js} |  14 +-
 .../with-quorum/{db-creation.js => doc_bulk.js}    |  20 +-
 ...b-creation.js => doc_bulk_overridden_quorum.js} |  20 +-
 .../with-quorum/{db-creation.js => doc_copy.js}    |  20 +-
 .../with-quorum/doc_copy_overridden_quorum.js}     |  26 +--
 .../with-quorum/{db-creation.js => doc_crud.js}    |  24 ++-
 ...b-creation.js => doc_crud_overridden_quorum.js} |  24 ++-
 .../tests-cluster/without-quorum/attachments.js    |  39 ++++
 .../without-quorum/attachments_delete.js           |  37 ++++
 .../attachments_delete_overridden_quorum.js        |  36 ++++
 .../attachments_overridden_quorum.js               |  42 ++++
 .../{db-creation.js => db_creation.js}             |   3 +-
 ...reation.js => db_creation_overridden_quorum.js} |  12 +-
 .../{db-creation.js => db_deletion.js}             |  18 +-
 ...reation.js => db_deletion_overridden_quorum.js} |  15 +-
 .../without-quorum/{db-creation.js => doc_bulk.js} |  20 +-
 ...b-creation.js => doc_bulk_overridden_quorum.js} |  20 +-
 .../without-quorum/{db-creation.js => doc_copy.js} |  20 +-
 ...b-creation.js => doc_copy_overridden_quorum.js} |  23 ++-
 .../without-quorum/{db-creation.js => doc_crud.js} |  25 ++-
 ...b-creation.js => doc_crud_overridden_quorum.js} |  24 ++-
 test/javascript/tests/design_docs.js               |   8 +-
 test/javascript/tests/reduce_builtin.js            |  20 ++
 test/javascript/tests/users_db.js                  |   7 +
 test/javascript/tests/users_db_security.js         | 167 ++--------------
 123 files changed, 2231 insertions(+), 1184 deletions(-)
 copy src/couch/src/{couch_rand.erl => couch_hash.erl} (50%)
 delete mode 100644 src/couch_event/src/couch_event_os_sup.erl
 copy src/fabric/src/{fabric_doc_attachments.erl => fabric_doc_atts.erl} (93%)
 create mode 100644 src/mango/test/18-json-sort.py
 create mode 100644 src/mango/test/19-find-conflicts.py
 create mode 100644 src/mango/test/20-no-timeout-test.py
 copy test/javascript/{tests/large_docs.js => tests-cluster/with-quorum/attachments.js} (54%)
 copy test/javascript/{tests/large_docs.js => tests-cluster/with-quorum/attachments_delete.js} (57%)
 create mode 100644 test/javascript/tests-cluster/with-quorum/attachments_delete_overridden_quorum.js
 create mode 100644 test/javascript/tests-cluster/with-quorum/attachments_overridden_quorum.js
 copy test/javascript/tests-cluster/with-quorum/{db-creation.js => db_creation.js} (100%)
 copy test/javascript/tests-cluster/with-quorum/{db-creation.js => db_creation_overridden_quorum.js} (62%)
 copy test/javascript/tests-cluster/{without-quorum/db-creation.js => with-quorum/db_deletion.js} (70%)
 copy test/javascript/tests-cluster/with-quorum/{db-creation.js => db_deletion_overridden_quorum.js} (67%)
 copy test/javascript/tests-cluster/with-quorum/{db-creation.js => doc_bulk.js} (70%)
 copy test/javascript/tests-cluster/with-quorum/{db-creation.js => doc_bulk_overridden_quorum.js} (63%)
 copy test/javascript/tests-cluster/with-quorum/{db-creation.js => doc_copy.js} (70%)
 copy test/javascript/{tests/large_docs.js => tests-cluster/with-quorum/doc_copy_overridden_quorum.js} (55%)
 copy test/javascript/tests-cluster/with-quorum/{db-creation.js => doc_crud.js} (68%)
 rename test/javascript/tests-cluster/with-quorum/{db-creation.js => doc_crud_overridden_quorum.js} (55%)
 create mode 100644 test/javascript/tests-cluster/without-quorum/attachments.js
 create mode 100644 test/javascript/tests-cluster/without-quorum/attachments_delete.js
 create mode 100644 test/javascript/tests-cluster/without-quorum/attachments_delete_overridden_quorum.js
 create mode 100644 test/javascript/tests-cluster/without-quorum/attachments_overridden_quorum.js
 copy test/javascript/tests-cluster/without-quorum/{db-creation.js => db_creation.js} (89%)
 copy test/javascript/tests-cluster/without-quorum/{db-creation.js => db_creation_overridden_quorum.js} (64%)
 copy test/javascript/tests-cluster/without-quorum/{db-creation.js => db_deletion.js} (72%)
 copy test/javascript/tests-cluster/without-quorum/{db-creation.js => db_deletion_overridden_quorum.js} (65%)
 copy test/javascript/tests-cluster/without-quorum/{db-creation.js => doc_bulk.js} (74%)
 copy test/javascript/tests-cluster/without-quorum/{db-creation.js => doc_bulk_overridden_quorum.js} (67%)
 copy test/javascript/tests-cluster/without-quorum/{db-creation.js => doc_copy.js} (72%)
 copy test/javascript/tests-cluster/without-quorum/{db-creation.js => doc_copy_overridden_quorum.js} (56%)
 copy test/javascript/tests-cluster/without-quorum/{db-creation.js => doc_crud.js} (65%)
 rename test/javascript/tests-cluster/without-quorum/{db-creation.js => doc_crud_overridden_quorum.js} (58%)


[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 c96df45bb7f1d46fef4dc8108f2e90464de8067e
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


[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 82dabd71c0081b6b385b56f228a6b6cf95294a90
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] 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 1e2e8af34969e6cd28efa3dedc79768dfe330337
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] 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 00d8379e0fb85260ee695b65d18075684e840fa1
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 55ff7979c0c2579031e80376d07d0b212a150b71
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