You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by va...@apache.org on 2020/04/07 16:18:43 UTC

[couchdb] branch prototype/fdb-layer updated (5652e72 -> 1d6799f)

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

vatamane pushed a change to branch prototype/fdb-layer
in repository https://gitbox.apache.org/repos/asf/couchdb.git.


    from 5652e72  remove defer and load_ddocs from mango_utils
     new 2ba98a8  Return better responses for endpoints which are not implemented
     new 1be2363  Fix POST _all_docs/queries endpoint
     new e71a77d  Do not allow editing _security in _user database
     new 1d6799f  Start running chttpd eunit tests

The 4 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:
 Makefile                                           |   2 +-
 src/chttpd/src/chttpd_db.erl                       |  27 ++---
 src/chttpd/src/chttpd_httpd_handlers.erl           |  32 +++++-
 src/chttpd/src/chttpd_test_util.erl                |   2 +-
 src/chttpd/src/chttpd_view.erl                     |  20 ++--
 .../eunit/chttpd_db_bulk_get_multipart_test.erl    |  31 +++---
 src/chttpd/test/eunit/chttpd_db_bulk_get_test.erl  |  30 +++---
 src/chttpd/test/eunit/chttpd_db_test.erl           |  38 ++-----
 src/chttpd/test/eunit/chttpd_dbs_info_test.erl     |  13 ++-
 .../test/eunit/chttpd_open_revs_error_test.erl     | 112 ---------------------
 src/chttpd/test/eunit/chttpd_purge_tests.erl       |   6 +-
 src/chttpd/test/eunit/chttpd_security_tests.erl    |  57 ++++++-----
 src/chttpd/test/eunit/chttpd_view_test.erl         |   4 +-
 src/couch/src/couch_db.erl                         |   2 +
 14 files changed, 133 insertions(+), 243 deletions(-)
 delete mode 100644 src/chttpd/test/eunit/chttpd_open_revs_error_test.erl


[couchdb] 04/04: Start running chttpd eunit tests

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

vatamane pushed a commit to branch prototype/fdb-layer
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 1d6799f5239af5e36d089ae605f943a13bb4ed99
Author: Nick Vatamaniuc <va...@apache.org>
AuthorDate: Mon Apr 6 17:53:40 2020 -0400

    Start running chttpd eunit tests
    
    Enable running all chttpd tests. Some fixes needed for this to happen are:
    
     * Some tests were not valid (checking shard maps, etc) and were deleted
    
     * Some tests were disabled either because functionality is not implemented yet
       or simply to minimize the diff between 3.x and this branch for when we have
       to rebase
    
     * Some applications used for index querying had to be started explicitly
    
     * Mock updated to use new version of modules instead of old ones
---
 Makefile                                           |   2 +-
 src/chttpd/src/chttpd_test_util.erl                |   2 +-
 src/chttpd/src/chttpd_view.erl                     |  10 +-
 .../eunit/chttpd_db_bulk_get_multipart_test.erl    |  31 +++---
 src/chttpd/test/eunit/chttpd_db_bulk_get_test.erl  |  30 +++---
 src/chttpd/test/eunit/chttpd_db_test.erl           |  38 ++-----
 src/chttpd/test/eunit/chttpd_dbs_info_test.erl     |  13 ++-
 .../test/eunit/chttpd_open_revs_error_test.erl     | 112 ---------------------
 src/chttpd/test/eunit/chttpd_purge_tests.erl       |   6 +-
 src/chttpd/test/eunit/chttpd_security_tests.erl    |  57 ++++++-----
 src/chttpd/test/eunit/chttpd_view_test.erl         |   4 +-
 src/couch/src/couch_db.erl                         |   2 +
 12 files changed, 92 insertions(+), 215 deletions(-)

diff --git a/Makefile b/Makefile
index cc33c61..592093e 100644
--- a/Makefile
+++ b/Makefile
@@ -160,7 +160,7 @@ endif
 
 .PHONY: check-fdb
 check-fdb:
-	make eunit apps=couch_eval,couch_expiring_cache,ctrace,couch_jobs,couch_views,fabric,mango
+	make eunit apps=couch_eval,couch_expiring_cache,ctrace,couch_jobs,couch_views,fabric,mango,chttpd
 	make elixir tests=test/elixir/test/basics_test.exs,test/elixir/test/replication_test.exs,test/elixir/test/map_test.exs,test/elixir/test/all_docs_test.exs,test/elixir/test/bulk_docs_test.exs
 	make exunit tests=src/couch_rate/test/exunit/
 	make mango-test
diff --git a/src/chttpd/src/chttpd_test_util.erl b/src/chttpd/src/chttpd_test_util.erl
index a1a08ef..8930a5a 100644
--- a/src/chttpd/src/chttpd_test_util.erl
+++ b/src/chttpd/src/chttpd_test_util.erl
@@ -21,7 +21,7 @@ start_couch() ->
     start_couch(?CONFIG_CHAIN).
 
 start_couch(IniFiles) ->
-    test_util:start_couch(IniFiles, [chttpd]).
+    test_util:start_couch(IniFiles, [couch_js, couch_views, chttpd]).
 
 stop_couch(Ctx) ->
     test_util:stop_couch(Ctx).
diff --git a/src/chttpd/src/chttpd_view.erl b/src/chttpd/src/chttpd_view.erl
index 3ef9c24..c9340fb 100644
--- a/src/chttpd/src/chttpd_view.erl
+++ b/src/chttpd/src/chttpd_view.erl
@@ -136,7 +136,7 @@ check_multi_query_reduce_view_overrides_test_() ->
 t_check_include_docs_throw_validation_error() ->
     ?_test(begin
         Req = #httpd{qs = []},
-        Db = test_util:fake_db([{name, <<"foo">>}]),
+        Db = #{name => <<"foo">>},
         Query = {[{<<"include_docs">>, true}]},
         Throw = {query_parse_error, <<"`include_docs` is invalid for reduce">>},
         ?assertThrow(Throw, multi_query_view(Req, Db, ddoc, <<"v">>, [Query]))
@@ -146,7 +146,7 @@ t_check_include_docs_throw_validation_error() ->
 t_check_user_can_override_individual_query_type() ->
     ?_test(begin
         Req = #httpd{qs = []},
-        Db = test_util:fake_db([{name, <<"foo">>}]),
+        Db = #{name => <<"foo">>},
         Query = {[{<<"include_docs">>, true}, {<<"reduce">>, false}]},
         multi_query_view(Req, Db, ddoc, <<"v">>, [Query]),
         ?assertEqual(1, meck:num_calls(chttpd, start_delayed_json_response, '_'))
@@ -157,7 +157,7 @@ setup_all() ->
     Views = [#mrview{reduce_funs = [{<<"v">>, <<"_count">>}]}],
     meck:expect(couch_mrview_util, ddoc_to_mrst, 2, {ok, #mrst{views = Views}}),
     meck:expect(chttpd, start_delayed_json_response, 4, {ok, resp}),
-    meck:expect(fabric, query_view, 7, {ok, #vacc{}}),
+    meck:expect(couch_views, query, 6, {ok, #vacc{}}),
     meck:expect(chttpd, send_delayed_chunk, 2, {ok, resp}),
     meck:expect(chttpd, end_delayed_json_response, 1, ok).
 
@@ -169,8 +169,8 @@ teardown_all(_) ->
 setup() ->
     meck:reset([
         chttpd,
-        couch_mrview_util,
-        fabric
+        couch_views,
+        couch_mrview_util
     ]).
 
 
diff --git a/src/chttpd/test/eunit/chttpd_db_bulk_get_multipart_test.erl b/src/chttpd/test/eunit/chttpd_db_bulk_get_multipart_test.erl
index 86a8eab..c0095d5 100644
--- a/src/chttpd/test/eunit/chttpd_db_bulk_get_multipart_test.erl
+++ b/src/chttpd/test/eunit/chttpd_db_bulk_get_multipart_test.erl
@@ -39,7 +39,7 @@ setup() ->
         couch_epi,
         couch_httpd,
         couch_stats,
-        fabric,
+        fabric2_db,
         mochireq
     ]),
     spawn_accumulator().
@@ -78,13 +78,13 @@ bulk_get_test_() ->
 
 should_require_docs_field(_) ->
     Req = fake_request({[{}]}),
-    Db  = test_util:fake_db([{name, <<"foo">>}]),
+    Db  = #{name => <<"foo">>},
     ?_assertThrow({bad_request, _}, chttpd_db:db_req(Req, Db)).
 
 
 should_not_accept_specific_query_params(_) ->
     Req = fake_request({[{<<"docs">>, []}]}),
-    Db  = test_util:fake_db([{name, <<"foo">>}]),
+    Db  = #{name => <<"foo">>},
     lists:map(fun (Param) ->
         {Param, ?_assertThrow({bad_request, _}, begin
             BadReq = Req#httpd{qs = [{Param, ""}]},
@@ -95,7 +95,7 @@ should_not_accept_specific_query_params(_) ->
 
 should_return_empty_results_on_no_docs(Pid) ->
     Req = fake_request({[{<<"docs">>, []}]}),
-    Db  = test_util:fake_db([{name, <<"foo">>}]),
+    Db  = #{name => <<"foo">>},
     chttpd_db:db_req(Req, Db),
     Results = get_results_from_response(Pid),
     ?_assertEqual([], Results).
@@ -104,7 +104,7 @@ should_return_empty_results_on_no_docs(Pid) ->
 should_get_doc_with_all_revs(Pid) ->
     DocId = <<"docudoc">>,
     Req = fake_request(DocId),
-    Db  = test_util:fake_db([{name, <<"foo">>}]),
+    Db  = #{name => <<"foo">>},
 
     DocRevA = #doc{id = DocId, body = {[{<<"_rev">>, <<"1-ABC">>}]}},
     DocRevB = #doc{id = DocId, body = {[{<<"_rev">>, <<"1-CDE">>}]}},
@@ -120,7 +120,7 @@ should_validate_doc_with_bad_id(Pid) ->
     DocId = <<"_docudoc">>,
 
     Req = fake_request(DocId),
-    Db  = test_util:fake_db([{name, <<"foo">>}]),
+    Db  = #{name => <<"foo">>},
     chttpd_db:db_req(Req, Db),
 
     Result = get_results_from_response(Pid),
@@ -137,7 +137,7 @@ should_validate_doc_with_bad_rev(Pid) ->
     Rev = <<"revorev">>,
 
     Req = fake_request(DocId, Rev),
-    Db  = test_util:fake_db([{name, <<"foo">>}]),
+    Db  = #{name => <<"foo">>},
     chttpd_db:db_req(Req, Db),
 
     Result = get_results_from_response(Pid),
@@ -154,7 +154,7 @@ should_validate_missing_doc(Pid) ->
     Rev = <<"1-revorev">>,
 
     Req = fake_request(DocId, Rev),
-    Db  = test_util:fake_db([{name, <<"foo">>}]),
+    Db  = #{name => <<"foo">>},
     mock_open_revs([{1,<<"revorev">>}], {ok, []}),
     chttpd_db:db_req(Req, Db),
 
@@ -172,7 +172,7 @@ should_validate_bad_atts_since(Pid) ->
     Rev = <<"1-revorev">>,
 
     Req = fake_request(DocId, Rev, <<"badattsince">>),
-    Db  = test_util:fake_db([{name, <<"foo">>}]),
+    Db  = #{name => <<"foo">>},
     mock_open_revs([{1,<<"revorev">>}], {ok, []}),
     chttpd_db:db_req(Req, Db),
 
@@ -190,14 +190,13 @@ should_include_attachments_when_atts_since_specified(_) ->
     Rev = <<"1-revorev">>,
 
     Req = fake_request(DocId, Rev, [<<"1-abc">>]),
-    Db  = test_util:fake_db([{name, <<"foo">>}]),
+    Db  = #{name => <<"foo">>},
     mock_open_revs([{1,<<"revorev">>}], {ok, []}),
     chttpd_db:db_req(Req, Db),
 
-    ?_assert(meck:called(fabric, open_revs,
-                         ['_', DocId, [{1, <<"revorev">>}],
-                         [{atts_since, [{1, <<"abc">>}]}, attachments,
-                          {user_ctx, undefined}]])).
+    Options = [{atts_since, [{1, <<"abc">>}]}, attachments],
+    ?_assert(meck:called(fabric2_db, open_doc_revs, ['_', DocId,
+        [{1, <<"revorev">>}], Options])).
 
 %% helpers
 
@@ -217,7 +216,7 @@ fake_request(DocId, Rev, AttsSince) ->
 
 
 mock_open_revs(RevsReq0, RevsResp) ->
-    ok = meck:expect(fabric, open_revs,
+    ok = meck:expect(fabric2_db, open_doc_revs,
                      fun(_, _, RevsReq1, _) ->
                          ?assertEqual(RevsReq0, RevsReq1),
                          RevsResp
@@ -259,7 +258,7 @@ mock(couch_stats) ->
     ok = meck:expect(couch_stats, update_gauge, fun(_, _) -> ok end),
     ok;
 mock(fabric) ->
-    ok = meck:new(fabric, [passthrough]),
+    ok = meck:new(fabric2_db, [passthrough]),
     ok;
 mock(config) ->
     ok = meck:new(config, [passthrough]),
diff --git a/src/chttpd/test/eunit/chttpd_db_bulk_get_test.erl b/src/chttpd/test/eunit/chttpd_db_bulk_get_test.erl
index 1a34112..0e47783 100644
--- a/src/chttpd/test/eunit/chttpd_db_bulk_get_test.erl
+++ b/src/chttpd/test/eunit/chttpd_db_bulk_get_test.erl
@@ -99,7 +99,8 @@ should_get_doc_with_all_revs(Pid) ->
     DocRevB = #doc{id = DocId, body = {[{<<"_rev">>, <<"1-CDE">>}]}},
 
     mock_open_revs(all, {ok, [{ok, DocRevA}, {ok, DocRevB}]}),
-    chttpd_db:db_req(Req, test_util:fake_db([{name, <<"foo">>}])),
+    Db = #{name => <<"foo">>},
+    chttpd_db:db_req(Req, Db),
 
     [{Result}] = get_results_from_response(Pid),
     ?assertEqual(DocId, couch_util:get_value(<<"id">>, Result)),
@@ -119,7 +120,8 @@ should_validate_doc_with_bad_id(Pid) ->
     DocId = <<"_docudoc">>,
 
     Req = fake_request(DocId),
-    chttpd_db:db_req(Req, test_util:fake_db([{name, <<"foo">>}])),
+    Db = #{name => <<"foo">>},
+    chttpd_db:db_req(Req, Db),
 
     [{Result}] = get_results_from_response(Pid),
     ?assertEqual(DocId, couch_util:get_value(<<"id">>, Result)),
@@ -142,7 +144,8 @@ should_validate_doc_with_bad_rev(Pid) ->
     Rev = <<"revorev">>,
 
     Req = fake_request(DocId, Rev),
-    chttpd_db:db_req(Req, test_util:fake_db([{name, <<"foo">>}])),
+    Db = #{name => <<"foo">>},
+    chttpd_db:db_req(Req, Db),
 
     [{Result}] = get_results_from_response(Pid),
     ?assertEqual(DocId, couch_util:get_value(<<"id">>, Result)),
@@ -166,7 +169,8 @@ should_validate_missing_doc(Pid) ->
 
     Req = fake_request(DocId, Rev),
     mock_open_revs([{1,<<"revorev">>}], {ok, []}),
-    chttpd_db:db_req(Req, test_util:fake_db([{name, <<"foo">>}])),
+    Db = #{name => <<"foo">>},
+    chttpd_db:db_req(Req, Db),
 
     [{Result}] = get_results_from_response(Pid),
     ?assertEqual(DocId, couch_util:get_value(<<"id">>, Result)),
@@ -190,7 +194,8 @@ should_validate_bad_atts_since(Pid) ->
 
     Req = fake_request(DocId, Rev, <<"badattsince">>),
     mock_open_revs([{1,<<"revorev">>}], {ok, []}),
-    chttpd_db:db_req(Req, test_util:fake_db([{name, <<"foo">>}])),
+    Db = #{name => <<"foo">>},
+    chttpd_db:db_req(Req, Db),
 
     [{Result}] = get_results_from_response(Pid),
     ?assertEqual(DocId, couch_util:get_value(<<"id">>, Result)),
@@ -214,12 +219,13 @@ should_include_attachments_when_atts_since_specified(_) ->
 
     Req = fake_request(DocId, Rev, [<<"1-abc">>]),
     mock_open_revs([{1,<<"revorev">>}], {ok, []}),
-    chttpd_db:db_req(Req, test_util:fake_db([{name, <<"foo">>}])),
+    Db = #{name => <<"foo">>},
+    chttpd_db:db_req(Req, Db),
+
+    Options = [{atts_since, [{1, <<"abc">>}]}, attachments],
+    ?_assert(meck:called(fabric2_db, open_doc_revs, ['_', DocId,
+        [{1, <<"revorev">>}], Options])).
 
-    ?_assert(meck:called(fabric, open_revs,
-                         ['_', DocId, [{1, <<"revorev">>}],
-                          [{atts_since, [{1, <<"abc">>}]}, attachments,
-                           {user_ctx, undefined}]])).
 
 %% helpers
 
@@ -239,7 +245,7 @@ fake_request(DocId, Rev, AttsSince) ->
 
 
 mock_open_revs(RevsReq0, RevsResp) ->
-    ok = meck:expect(fabric, open_revs,
+    ok = meck:expect(fabric2_db, open_doc_revs,
                      fun(_, _, RevsReq1, _) ->
                          ?assertEqual(RevsReq0, RevsReq1),
                          RevsResp
@@ -276,7 +282,7 @@ mock(couch_stats) ->
     ok = meck:expect(couch_stats, update_gauge, fun(_, _) -> ok end),
     ok;
 mock(fabric) ->
-    ok = meck:new(fabric, [passthrough]),
+    ok = meck:new(fabric2_db, [passthrough]),
     ok;
 mock(config) ->
     ok = meck:new(config, [passthrough]),
diff --git a/src/chttpd/test/eunit/chttpd_db_test.erl b/src/chttpd/test/eunit/chttpd_db_test.erl
index 204332d..b1d514a 100644
--- a/src/chttpd/test/eunit/chttpd_db_test.erl
+++ b/src/chttpd/test/eunit/chttpd_db_test.erl
@@ -73,8 +73,7 @@ all_test_() ->
                     fun should_return_update_seq_when_set_on_all_docs/1,
                     fun should_not_return_update_seq_when_unset_on_all_docs/1,
                     fun should_return_correct_id_on_doc_copy/1,
-                    fun should_return_400_for_bad_engine/1,
-                    fun should_not_change_db_proper_after_rewriting_shardmap/1,
+                    fun should_ignore_engine_parameter/1,
                     fun should_succeed_on_all_docs_with_queries_keys/1,
                     fun should_succeed_on_all_docs_with_queries_limit_skip/1,
                     fun should_succeed_on_all_docs_with_multiple_queries/1,
@@ -282,7 +281,7 @@ attachment_doc() ->
     ]}.
 
 
-should_return_400_for_bad_engine(_) ->
+should_ignore_engine_parameter(_) ->
     {timeout, ?TIMEOUT, ?_test(begin
         TmpDb = ?tempdb(),
         Addr = config:get("chttpd", "bind_address", "127.0.0.1"),
@@ -290,30 +289,7 @@ should_return_400_for_bad_engine(_) ->
         BaseUrl = lists:concat(["http://", Addr, ":", Port, "/", ?b2l(TmpDb)]),
         Url = BaseUrl ++ "?engine=cowabunga",
         {ok, Status, _, _} = test_request:put(Url, [?CONTENT_JSON, ?AUTH], "{}"),
-        ?assertEqual(400, Status)
-    end)}.
-
-
-should_not_change_db_proper_after_rewriting_shardmap(_) ->
-    {timeout, ?TIMEOUT, ?_test(begin
-        TmpDb = ?tempdb(),
-        Addr = config:get("chttpd", "bind_address", "127.0.0.1"),
-        Port = mochiweb_socket_server:get(chttpd, port),
-        AdmPort = mochiweb_socket_server:get(couch_httpd, port),
-
-        BaseUrl = lists:concat(["http://", Addr, ":", Port, "/", ?b2l(TmpDb)]),
-        Url = BaseUrl ++ "?partitioned=true&q=1",
-        {ok, 201, _, _} = test_request:put(Url, [?CONTENT_JSON, ?AUTH], "{}"),
-
-        ShardDbName = ?l2b(config:get("mem3", "shards_db", "_dbs")),
-        {ok, ShardDb} = mem3_util:ensure_exists(ShardDbName),
-        {ok, #doc{body = {Props}}} = couch_db:open_doc(
-            ShardDb, TmpDb, [ejson_body]),
-        Shards = mem3_util:build_shards(TmpDb, Props),
-
-        {Prop2} = ?JSON_DECODE(?JSON_ENCODE({Props})),
-        Shards2 = mem3_util:build_shards(TmpDb, Prop2),
-        ?assertEqual(Shards2, Shards)
+        ?assertEqual(201, Status)
     end)}.
 
 
@@ -341,7 +317,7 @@ should_succeed_on_all_docs_with_queries_limit_skip(Url) ->
         {ResultJson} = ?JSON_DECODE(RespBody),
         ResultJsonBody = couch_util:get_value(<<"results">>, ResultJson),
         {InnerJson} = lists:nth(1, ResultJsonBody),
-        ?assertEqual(2, couch_util:get_value(<<"offset">>, InnerJson)),
+        ?assertEqual(null, couch_util:get_value(<<"offset">>, InnerJson)),
         ?assertEqual(5, length(couch_util:get_value(<<"rows">>, InnerJson)))
     end)}.
 
@@ -359,7 +335,7 @@ should_succeed_on_all_docs_with_multiple_queries(Url) ->
         {InnerJson1} = lists:nth(1, ResultJsonBody),
         ?assertEqual(2, length(couch_util:get_value(<<"rows">>, InnerJson1))),
         {InnerJson2} = lists:nth(2, ResultJsonBody),
-        ?assertEqual(2, couch_util:get_value(<<"offset">>, InnerJson2)),
+        ?assertEqual(null, couch_util:get_value(<<"offset">>, InnerJson2)),
         ?assertEqual(5, length(couch_util:get_value(<<"rows">>, InnerJson2)))
     end)}.
 
@@ -389,7 +365,7 @@ should_succeed_on_design_docs_with_queries_limit_skip(Url) ->
         {ResultJson} = ?JSON_DECODE(RespBody),
         ResultJsonBody = couch_util:get_value(<<"results">>, ResultJson),
         {InnerJson} = lists:nth(1, ResultJsonBody),
-        ?assertEqual(2, couch_util:get_value(<<"offset">>, InnerJson)),
+        ?assertEqual(null, couch_util:get_value(<<"offset">>, InnerJson)),
         ?assertEqual(5, length(couch_util:get_value(<<"rows">>, InnerJson)))
     end)}.
 
@@ -407,7 +383,7 @@ should_succeed_on_design_docs_with_multiple_queries(Url) ->
         {InnerJson1} = lists:nth(1, ResultJsonBody),
         ?assertEqual(2, length(couch_util:get_value(<<"rows">>, InnerJson1))),
         {InnerJson2} = lists:nth(2, ResultJsonBody),
-        ?assertEqual(2, couch_util:get_value(<<"offset">>, InnerJson2)),
+        ?assertEqual(null, couch_util:get_value(<<"offset">>, InnerJson2)),
         ?assertEqual(5, length(couch_util:get_value(<<"rows">>, InnerJson2)))
     end)}.
 
diff --git a/src/chttpd/test/eunit/chttpd_dbs_info_test.erl b/src/chttpd/test/eunit/chttpd_dbs_info_test.erl
index 5b61d88..6e11f32 100644
--- a/src/chttpd/test/eunit/chttpd_dbs_info_test.erl
+++ b/src/chttpd/test/eunit/chttpd_dbs_info_test.erl
@@ -57,7 +57,7 @@ dbs_info_test_() ->
                 foreach,
                 fun setup/0, fun teardown/1,
                 [
-                    fun should_return_error_for_get_db_info/1,
+                    fun should_return_for_get_db_info/1,
                     fun should_return_dbs_info_for_single_db/1,
                     fun should_return_dbs_info_for_multiple_dbs/1,
                     fun should_return_error_for_exceeded_keys/1,
@@ -69,15 +69,14 @@ dbs_info_test_() ->
     }.
 
 
-should_return_error_for_get_db_info(Url) ->
+should_return_for_get_db_info(Url) ->
     ?_test(begin
         {ok, Code, _, ResultBody} = test_request:get(Url ++ "/_dbs_info?"
-            ++ "keys=[\"db1\"]", [?CONTENT_JSON, ?AUTH]),
-        {Body} = jiffy:decode(ResultBody),
+            ++ "start_key=\"db1\"&end_key=\"db1\"", [?CONTENT_JSON, ?AUTH]),
+        Body = jiffy:decode(ResultBody, [return_maps]),
         [
-            ?assertEqual(<<"method_not_allowed">>,
-                couch_util:get_value(<<"error">>, Body)),
-            ?assertEqual(405, Code)
+            ?assertEqual(200, Code),
+            ?assertMatch([#{<<"db_name">> := <<"db1">>}], Body)
         ]
     end).
 
diff --git a/src/chttpd/test/eunit/chttpd_open_revs_error_test.erl b/src/chttpd/test/eunit/chttpd_open_revs_error_test.erl
deleted file mode 100644
index d53d370..0000000
--- a/src/chttpd/test/eunit/chttpd_open_revs_error_test.erl
+++ /dev/null
@@ -1,112 +0,0 @@
-% Licensed under the Apache License, Version 2.0 (the "License"); you may not
-% use this file except in compliance with the License. You may obtain a copy of
-% the License at
-%
-%   http://www.apache.org/licenses/LICENSE-2.0
-%
-% Unless required by applicable law or agreed to in writing, software
-% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-% License for the specific language governing permissions and limitations under
-% the License.
-
--module(chttpd_open_revs_error_test).
-
--include_lib("couch/include/couch_eunit.hrl").
--include_lib("couch/include/couch_db.hrl").
-
--define(USER, "chttpd_db_test_admin").
--define(PASS, "pass").
--define(AUTH, {basic_auth, {?USER, ?PASS}}).
--define(CONTENT_JSON, {"Content-Type", "application/json"}).
--define(CONTENT_MULTI_FORM, {"Content-Type",
-    "multipart/form-data;boundary=\"bound\""}).
-
-setup() ->
-    Hashed = couch_passwords:hash_admin_password(?PASS),
-    ok = config:set("admins", ?USER, ?b2l(Hashed), _Persist=false),
-    TmpDb = ?tempdb(),
-    Addr = config:get("chttpd", "bind_address", "127.0.0.1"),
-    Port = mochiweb_socket_server:get(chttpd, port),
-    Url = lists:concat(["http://", Addr, ":", Port, "/", ?b2l(TmpDb)]),
-    mock(fabric),
-    create_db(Url),
-    Url.
-
-teardown(Url) ->
-    delete_db(Url),
-    (catch meck:unload(fabric)),
-    ok = config:delete("admins", ?USER, _Persist=false).
-
-create_db(Url) ->
-    {ok, Status, _, _} = test_request:put(Url, [?CONTENT_JSON, ?AUTH], "{}"),
-    ?assert(Status =:= 201 orelse Status =:= 202).
-
-
-create_doc(Url, Id) ->
-    test_request:put(Url ++ "/" ++ Id,
-        [?CONTENT_JSON, ?AUTH], "{\"mr\": \"rockoartischocko\"}").
-
-delete_db(Url) ->
-    {ok, 200, _, _} = test_request:delete(Url, [?AUTH]).
-
-open_revs_error_test_() ->
-    {
-        "open revs error tests",
-        {
-            setup,
-            fun chttpd_test_util:start_couch/0,
-            fun chttpd_test_util:stop_couch/1,
-            {
-                foreach,
-                fun setup/0, fun teardown/1,
-                [
-                    fun should_return_503_error_for_open_revs_get/1,
-                    fun should_return_503_error_for_open_revs_post_form/1
-                ]
-            }
-        }
-    }.
-
-should_return_503_error_for_open_revs_get(Url) ->
-    {ok, _, _, Body} = create_doc(Url, "testdoc"),
-    {Json} = ?JSON_DECODE(Body),
-    Ref = couch_util:get_value(<<"rev">>, Json, undefined),
-    mock_open_revs({error, all_workers_died}),
-    {ok, Code, _, _} = test_request:get(Url ++
-        "/testdoc?rev=" ++ ?b2l(Ref), [?AUTH]),
-    ?_assertEqual(503, Code).
-
-should_return_503_error_for_open_revs_post_form(Url) ->
-    Port = mochiweb_socket_server:get(chttpd, port),
-    Host = lists:concat([ "http://127.0.0.1:", Port]),
-    Referer = {"Referer", Host},
-    Body1 = "{\"body\":\"This is a body.\"}",
-    DocBeg = "--bound\r\nContent-Disposition: form-data; name=\"_doc\"\r\n\r\n",
-    DocRev = "--bound\r\nContent-Disposition: form-data; name=\"_rev\"\r\n\r\n",
-    DocRest = "\r\n--bound\r\nContent-Disposition:"
-        "form-data; name=\"_attachments\"; filename=\"file.txt\"\r\n"
-        "Content-Type: text/plain\r\n\r\ncontents of file.txt\r\n\r\n"
-        "--bound--",
-    Doc1 = lists:concat([DocBeg, Body1, DocRest]),
-    {ok, _, _, ResultBody} = test_request:post(Url ++ "/" ++ "RevDoc",
-        [?CONTENT_MULTI_FORM, ?AUTH, Referer], Doc1),
-    {Json} = ?JSON_DECODE(ResultBody),
-    Ref = couch_util:get_value(<<"rev">>, Json, undefined),
-    Doc2 = lists:concat([DocRev, ?b2l(Ref) , DocRest]),
-
-    mock_open_revs({error, all_workers_died}),
-    {ok, Code, _, ResultBody1} = test_request:post(Url ++ "/" ++ "RevDoc",
-        [?CONTENT_MULTI_FORM, ?AUTH, Referer], Doc2),
-    {Json1} = ?JSON_DECODE(ResultBody1),
-    ErrorMessage = couch_util:get_value(<<"error">>, Json1),
-    [
-        ?_assertEqual(503, Code),
-        ?_assertEqual(<<"service unvailable">>, ErrorMessage)
-    ].
-
-mock_open_revs(RevsResp) ->
-    ok = meck:expect(fabric, open_revs, fun(_, _, _, _) -> RevsResp end).
-
-mock(fabric) ->
-    ok = meck:new(fabric, [passthrough]).
diff --git a/src/chttpd/test/eunit/chttpd_purge_tests.erl b/src/chttpd/test/eunit/chttpd_purge_tests.erl
index ab43568..bc1fce0 100644
--- a/src/chttpd/test/eunit/chttpd_purge_tests.erl
+++ b/src/chttpd/test/eunit/chttpd_purge_tests.erl
@@ -13,6 +13,10 @@
 -module(chttpd_purge_tests).
 
 
+% Remove when purge is implemented
+-compile(nowarn_unused_function).
+
+
 -include_lib("couch/include/couch_eunit.hrl").
 -include_lib("couch/include/couch_db.hrl").
 
@@ -62,7 +66,7 @@ delete_db(Url) ->
     {ok, 200, _, _} = test_request:delete(Url, [?AUTH]).
 
 
-purge_test_() ->
+purge_test_disabled() ->
     {
         "chttpd db tests",
         {
diff --git a/src/chttpd/test/eunit/chttpd_security_tests.erl b/src/chttpd/test/eunit/chttpd_security_tests.erl
index 0bea9db..8085f82 100644
--- a/src/chttpd/test/eunit/chttpd_security_tests.erl
+++ b/src/chttpd/test/eunit/chttpd_security_tests.erl
@@ -12,6 +12,9 @@
 
 -module(chttpd_security_tests).
 
+% Remove when purge is implemented
+-compile(nowarn_unused_function).
+
 -include_lib("couch/include/couch_eunit.hrl").
 -include_lib("couch/include/couch_db.hrl").
 
@@ -38,14 +41,13 @@ setup() ->
     ok = config:set("admins", ?USER, ?b2l(Hashed), Persist),
     UserDb = ?tempdb(),
     TmpDb = ?tempdb(),
-    ok = config:set("chttpd_auth", "authentication_db", ?b2l(UserDb), Persist),
-
     Addr = config:get("chttpd", "bind_address", "127.0.0.1"),
     Port = mochiweb_socket_server:get(chttpd, port),
     BaseUrl = lists:concat(["http://", Addr, ":", Port, "/"]),
-    Url = lists:concat([BaseUrl, ?b2l(TmpDb)]),
     UsersUrl = lists:concat([BaseUrl, ?b2l(UserDb)]),
     create_db(UsersUrl),
+    ok = config:set("chttpd_auth", "authentication_db", ?b2l(UserDb), Persist),
+    Url = lists:concat([BaseUrl, ?b2l(TmpDb)]),
     create_db(Url),
     create_design_doc(Url),
     create_user(UsersUrl,?TEST_MEMBER,?TEST_MEMBER_PASS,[<<?TEST_MEMBER>>]),
@@ -56,6 +58,7 @@ setup() ->
 teardown([Url,UsersUrl]) ->
     delete_db(Url),
     delete_db(UsersUrl),
+    ok = config:delete("chttpd_auth", "authentication_db", _Persist=false),
     ok = config:delete("admins", ?USER, _Persist=false).
 
 create_db(Url) ->
@@ -108,15 +111,21 @@ all_test_() ->
                     fun should_disallow_db_member_db_compaction/1,
                     fun should_allow_db_admin_db_compaction/1,
                     fun should_allow_admin_view_compaction/1,
-                    fun should_disallow_anonymous_view_compaction/1,
-                    fun should_allow_admin_db_view_cleanup/1,
-                    fun should_disallow_anonymous_db_view_cleanup/1,
-                    fun should_allow_admin_purge/1,
-                    fun should_disallow_anonymous_purge/1,
-                    fun should_disallow_db_member_purge/1,
-                    fun should_allow_admin_purged_infos_limit/1,
-                    fun should_disallow_anonymous_purged_infos_limit/1,
-                    fun should_disallow_db_member_purged_infos_limit/1
+                    fun should_disallow_anonymous_view_compaction/1
+
+                    % Re-enable when _view_cleanup is implemented
+                    %
+                    %fun should_allow_admin_db_view_cleanup/1,
+                    %fun should_disallow_anonymous_db_view_cleanup/1,
+
+                    % Re-enable when purge is implemented
+                    %
+                    %fun should_allow_admin_purge/1,
+                    %fun should_disallow_anonymous_purge/1,
+                    %fun should_disallow_db_member_purge/1,
+                    %fun should_allow_admin_purged_infos_limit/1,
+                    %fun should_disallow_anonymous_purged_infos_limit/1,
+                    %fun should_disallow_db_member_purged_infos_limit/1
                 ]
             }
         }
@@ -337,13 +346,11 @@ should_return_error_for_sec_obj_with_incorrect_roles_and_names(
     Body = jiffy:encode({SecurityProperties}),
     {ok, Status, _, RespBody} = test_request:put(SecurityUrl,
         [?CONTENT_JSON, ?AUTH], Body),
-    ResultJson = ?JSON_DECODE(RespBody),
+    ResultJson = couch_util:json_decode(RespBody, [return_maps]),
+    ExpectReason = <<"names must be a JSON list of strings">>,
     [
         ?_assertEqual(500, Status),
-        ?_assertEqual({[
-            {<<"error">>,<<"error">>},
-            {<<"reason">>,<<"no_majority">>}
-        ]}, ResultJson)
+        ?_assertMatch(#{<<"reason">> := ExpectReason}, ResultJson)
     ].
 
 should_return_error_for_sec_obj_with_incorrect_roles([Url,_UsersUrl]) ->
@@ -356,13 +363,11 @@ should_return_error_for_sec_obj_with_incorrect_roles([Url,_UsersUrl]) ->
     Body = jiffy:encode({SecurityProperties}),
     {ok, Status, _, RespBody} = test_request:put(SecurityUrl,
         [?CONTENT_JSON, ?AUTH], Body),
-    ResultJson = ?JSON_DECODE(RespBody),
+    ResultJson = couch_util:json_decode(RespBody, [return_maps]),
+    ExpectReason = <<"roles must be a JSON list of strings">>,
     [
         ?_assertEqual(500, Status),
-        ?_assertEqual({[
-            {<<"error">>,<<"error">>},
-            {<<"reason">>,<<"no_majority">>}
-        ]}, ResultJson)
+        ?_assertMatch(#{<<"reason">> := ExpectReason}, ResultJson)
     ].
 
 should_return_error_for_sec_obj_with_incorrect_names([Url,_UsersUrl]) ->
@@ -375,13 +380,11 @@ should_return_error_for_sec_obj_with_incorrect_names([Url,_UsersUrl]) ->
     Body = jiffy:encode({SecurityProperties}),
     {ok, Status, _, RespBody} = test_request:put(SecurityUrl,
         [?CONTENT_JSON, ?AUTH], Body),
-    ResultJson = ?JSON_DECODE(RespBody),
+    ResultJson = couch_util:json_decode(RespBody, [return_maps]),
+    ExpectReason = <<"names must be a JSON list of strings">>,
     [
         ?_assertEqual(500, Status),
-        ?_assertEqual({[
-            {<<"error">>,<<"error">>},
-            {<<"reason">>,<<"no_majority">>}
-        ]}, ResultJson)
+        ?_assertMatch(#{<<"reason">> := ExpectReason}, ResultJson)
     ].
 
 should_return_error_for_sec_obj_in_user_db([_,_UsersUrl]) ->
diff --git a/src/chttpd/test/eunit/chttpd_view_test.erl b/src/chttpd/test/eunit/chttpd_view_test.erl
index 4c224bb..1744f97 100644
--- a/src/chttpd/test/eunit/chttpd_view_test.erl
+++ b/src/chttpd/test/eunit/chttpd_view_test.erl
@@ -99,7 +99,7 @@ should_succeed_on_view_with_queries_limit_skip(Url) ->
         {ResultJson} = ?JSON_DECODE(RespBody),
         ResultJsonBody = couch_util:get_value(<<"results">>, ResultJson),
         {InnerJson} = lists:nth(1, ResultJsonBody),
-        ?assertEqual(2, couch_util:get_value(<<"offset">>, InnerJson)),
+        ?assertEqual(null, couch_util:get_value(<<"offset">>, InnerJson)),
         ?assertEqual(5, length(couch_util:get_value(<<"rows">>, InnerJson)))
     end)}.
 
@@ -119,6 +119,6 @@ should_succeed_on_view_with_multiple_queries(Url) ->
         {InnerJson1} = lists:nth(1, ResultJsonBody),
         ?assertEqual(2, length(couch_util:get_value(<<"rows">>, InnerJson1))),
         {InnerJson2} = lists:nth(2, ResultJsonBody),
-        ?assertEqual(2, couch_util:get_value(<<"offset">>, InnerJson2)),
+        ?assertEqual(null, couch_util:get_value(<<"offset">>, InnerJson2)),
         ?assertEqual(5, length(couch_util:get_value(<<"rows">>, InnerJson2)))
     end)}.
diff --git a/src/couch/src/couch_db.erl b/src/couch/src/couch_db.erl
index e1d726d..8a7b218 100644
--- a/src/couch/src/couch_db.erl
+++ b/src/couch/src/couch_db.erl
@@ -212,6 +212,8 @@ is_db(_) ->
 is_system_db(#db{options = Options}) ->
     lists:member(sys_db, Options).
 
+is_clustered(#{}) ->
+    true;
 is_clustered(#db{main_pid = nil}) ->
     true;
 is_clustered(#db{}) ->


[couchdb] 01/04: Return better responses for endpoints which are not implemented

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

vatamane pushed a commit to branch prototype/fdb-layer
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 2ba98a89cda88ccc9be2b4e4fb481086d1364e42
Author: Nick Vatamaniuc <va...@apache.org>
AuthorDate: Mon Apr 6 17:39:22 2020 -0400

    Return better responses for endpoints which are not implemented
    
    Endpoints which are removed return a 410 response:
    
     - _show
     - _list
     - _rewrite
    
    Endpoints which will be implemented in CouchDB 4.x eventually now return a 510
    response:
    
     - _purge
     - _purge_infos_limit
    
    Endpoints which return a 2xx but are a no-op effectively:
    
     - _compact
     - _view_cleanup
---
 src/chttpd/src/chttpd_db.erl             | 21 +++++++--------------
 src/chttpd/src/chttpd_httpd_handlers.erl | 32 +++++++++++++++++++++++++++-----
 src/chttpd/src/chttpd_view.erl           |  5 +----
 3 files changed, 35 insertions(+), 23 deletions(-)

diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index e9b33f0..deaca48 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -252,21 +252,14 @@ maybe_flush_changes_feed(Acc0, Data, Len) ->
     },
     {ok, Acc}.
 
-handle_compact_req(#httpd{method='POST'}=Req, Db) ->
+
+% Return the same response as if a compaction succeeded even though _compaction
+% isn't a valid operation in CouchDB >= 4.x anymore. This is mostly to not
+% break existing user script which maybe periodically call this endpoint. In
+% the future this endpoint will return a 410 response then it will be removed.
+handle_compact_req(#httpd{method='POST'}=Req, _Db) ->
     chttpd:validate_ctype(Req, "application/json"),
-    case Req#httpd.path_parts of
-        [_DbName, <<"_compact">>] ->
-            ok = fabric:compact(Db),
-            send_json(Req, 202, {[{ok, true}]});
-        [DbName, <<"_compact">>, DesignName | _] ->
-            case ddoc_cache:open(DbName, <<"_design/", DesignName/binary>>) of
-                {ok, _DDoc} ->
-                    ok = fabric:compact(Db, DesignName),
-                    send_json(Req, 202, {[{ok, true}]});
-                Error ->
-                    throw(Error)
-            end
-    end;
+    send_json(Req, 202, {[{ok, true}]});
 
 handle_compact_req(Req, _Db) ->
     send_method_not_allowed(Req, "POST").
diff --git a/src/chttpd/src/chttpd_httpd_handlers.erl b/src/chttpd/src/chttpd_httpd_handlers.erl
index 831c014..be6c0a1 100644
--- a/src/chttpd/src/chttpd_httpd_handlers.erl
+++ b/src/chttpd/src/chttpd_httpd_handlers.erl
@@ -14,6 +14,13 @@
 
 -export([url_handler/1, db_handler/1, design_handler/1, handler_info/3]).
 
+-export([
+    not_supported/2,
+    not_supported/3,
+    not_implemented/2
+]).
+
+
 -include_lib("couch/include/couch_db.hrl").
 
 
@@ -32,20 +39,22 @@ url_handler(<<"_session">>)        -> fun chttpd_auth:handle_session_req/1;
 url_handler(<<"_up">>)             -> fun chttpd_misc:handle_up_req/1;
 url_handler(_) -> no_match.
 
-db_handler(<<"_view_cleanup">>) -> fun chttpd_db:handle_view_cleanup_req/2;
+db_handler(<<"_view_cleanup">>) -> fun ?MODULE:not_implemented/2;
 db_handler(<<"_compact">>)      -> fun chttpd_db:handle_compact_req/2;
 db_handler(<<"_design">>)       -> fun chttpd_db:handle_design_req/2;
 db_handler(<<"_partition">>)    -> fun chttpd_db:handle_partition_req/2;
-db_handler(<<"_temp_view">>)    -> fun chttpd_view:handle_temp_view_req/2;
+db_handler(<<"_temp_view">>)    -> fun ?MODULE:not_supported/2;
 db_handler(<<"_changes">>)      -> fun chttpd_db:handle_changes_req/2;
+db_handler(<<"_purge">>)        -> fun ?MODULE:not_implemented/2;
+db_handler(<<"_purged_infos_limit">>) -> fun ?MODULE:not_implemented/2;
 db_handler(_) -> no_match.
 
 design_handler(<<"_view">>)    -> fun chttpd_view:handle_view_req/3;
-design_handler(<<"_show">>)    -> fun chttpd_show:handle_doc_show_req/3;
-design_handler(<<"_list">>)    -> fun chttpd_show:handle_view_list_req/3;
+design_handler(<<"_show">>)    -> fun ?MODULE:not_supported/3;
+design_handler(<<"_list">>)    -> fun ?MODULE:not_supported/3;
 design_handler(<<"_update">>)  -> fun chttpd_show:handle_doc_update_req/3;
 design_handler(<<"_info">>)    -> fun chttpd_db:handle_design_info_req/3;
-design_handler(<<"_rewrite">>) -> fun chttpd_rewrite:handle_rewrite_req/3;
+design_handler(<<"_rewrite">>) -> fun ?MODULE:not_supported/3;
 design_handler(_) -> no_match.
 
 
@@ -484,3 +493,16 @@ get_copy_destination(Req) ->
         unknown
     end.
 
+
+not_supported(#httpd{} = Req, Db, _DDoc) ->
+    not_supported(Req, Db).
+
+
+not_supported(#httpd{} = Req, _Db) ->
+    Msg = <<"resource is not supported in CouchDB >= 4.x">>,
+    chttpd:send_error(Req, 410, gone, Msg).
+
+
+not_implemented(#httpd{} = Req, _Db) ->
+    Msg = <<"resouce is not implemented">>,
+    chttpd:send_error(Req, 501, not_implemented, Msg).
diff --git a/src/chttpd/src/chttpd_view.erl b/src/chttpd/src/chttpd_view.erl
index 49ca1a7..84997e5 100644
--- a/src/chttpd/src/chttpd_view.erl
+++ b/src/chttpd/src/chttpd_view.erl
@@ -14,7 +14,7 @@
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("couch_mrview/include/couch_mrview.hrl").
 
--export([handle_view_req/3, handle_temp_view_req/2]).
+-export([handle_view_req/3]).
 
 multi_query_view(Req, Db, DDoc, ViewName, Queries) ->
     Args0 = couch_mrview_http:parse_params(Req, undefined),
@@ -101,9 +101,6 @@ handle_view_req(#httpd{method='POST',
 handle_view_req(Req, _Db, _DDoc) ->
     chttpd:send_method_not_allowed(Req, "GET,POST,HEAD").
 
-handle_temp_view_req(Req, _Db) ->
-    Msg = <<"Temporary views are not supported in CouchDB">>,
-    chttpd:send_error(Req, 410, gone, Msg).
 
 % See https://github.com/apache/couchdb/issues/2168
 assert_no_queries_param(undefined) ->


[couchdb] 03/04: Do not allow editing _security in _user database

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

vatamane pushed a commit to branch prototype/fdb-layer
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit e71a77d5c8bf9394a4130d98e59e8de2795ba4b3
Author: Nick Vatamaniuc <va...@apache.org>
AuthorDate: Mon Apr 6 17:48:59 2020 -0400

    Do not allow editing _security in _user database
    
    It should only be allowed if explicitly configured. Previously we did not
    propertly match on the database name and effectively always allowed it.
---
 src/chttpd/src/chttpd_db.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index 16cfbd0..730cf3e 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -1963,7 +1963,7 @@ extract_header_rev(Req, ExplicitRev) ->
     end.
 
 validate_security_can_be_edited(DbName) ->
-    UserDbName = config:get("chttpd_auth", "authentication_db", "_users"),
+    UserDbName = ?l2b(config:get("chttpd_auth", "authentication_db", "_users")),
     CanEditUserSecurityObject = config:get("couchdb","users_db_security_editable","false"),
     case {DbName,CanEditUserSecurityObject} of
         {UserDbName,"false"} ->


[couchdb] 02/04: Fix POST _all_docs/queries endpoint

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

vatamane pushed a commit to branch prototype/fdb-layer
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 1be2363b4dae31ab67d6bafd3f5a2620f5d784eb
Author: Nick Vatamaniuc <va...@apache.org>
AuthorDate: Mon Apr 6 17:46:45 2020 -0400

    Fix POST _all_docs/queries endpoint
    
    Call couch_views module instead of the old fabric:query_view also needed to
    call `view_cb(complete, ...)` when using keys similar to how `all_docs_view/4`
    does it.
---
 src/chttpd/src/chttpd_db.erl   | 4 +++-
 src/chttpd/src/chttpd_view.erl | 5 ++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index deaca48..16cfbd0 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -831,7 +831,9 @@ multi_all_docs_view(Req, Db, OP, Queries) ->
         (#mrargs{keys = undefined} = Args, Acc0) ->
             send_all_docs(Db, Args, Acc0);
         (#mrargs{keys = Keys} = Args, Acc0) when is_list(Keys) ->
-            send_all_docs_keys(Db, Args, Acc0)
+            Acc1 = send_all_docs_keys(Db, Args, Acc0),
+            {ok, Acc2} = view_cb(complete, Acc1),
+            Acc2
     end, VAcc0, ArgQueries),
     {ok, Resp1} = chttpd:send_delayed_chunk(VAcc1#vacc.resp, "\r\n]}"),
     chttpd:end_delayed_json_response(Resp1).
diff --git a/src/chttpd/src/chttpd_view.erl b/src/chttpd/src/chttpd_view.erl
index 84997e5..3ef9c24 100644
--- a/src/chttpd/src/chttpd_view.erl
+++ b/src/chttpd/src/chttpd_view.erl
@@ -26,14 +26,13 @@ multi_query_view(Req, Db, DDoc, ViewName, Queries) ->
         QueryArg1 = couch_mrview_util:set_view_type(QueryArg, ViewName, Views),
         fabric_util:validate_args(Db, DDoc, QueryArg1)
     end, Queries),
-    Options = [{user_ctx, Req#httpd.user_ctx}],
     VAcc0 = #vacc{db=Db, req=Req, prepend="\r\n"},
     FirstChunk = "{\"results\":[",
     {ok, Resp0} = chttpd:start_delayed_json_response(VAcc0#vacc.req, 200, [], FirstChunk),
     VAcc1 = VAcc0#vacc{resp=Resp0},
     VAcc2 = lists:foldl(fun(Args, Acc0) ->
-        {ok, Acc1} = fabric:query_view(Db, Options, DDoc, ViewName,
-            fun view_cb/2, Acc0, Args),
+        Fun = fun view_cb/2,
+        {ok, Acc1} = couch_views:query(Db, DDoc, ViewName, Fun, Acc0, Args),
         Acc1
     end, VAcc1, ArgQueries),
     {ok, Resp1} = chttpd:send_delayed_chunk(VAcc2#vacc.resp, "\r\n]}"),