You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@couchdb.apache.org by GitBox <gi...@apache.org> on 2022/10/17 17:03:24 UTC
[GitHub] [couchdb] jaydoane commented on a diff in pull request #4209: Add bulk_get tests
jaydoane commented on code in PR #4209:
URL: https://github.com/apache/couchdb/pull/4209#discussion_r997291823
##########
src/chttpd/test/eunit/chttpd_bulk_get_test.erl:
##########
@@ -0,0 +1,785 @@
+% 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_bulk_get_test).
+
+-include_lib("couch/include/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+
+-define(USER, "chttpd_bulk_get_test_admin").
+-define(PASS, "pass").
+-define(AUTH, {basic_auth, {?USER, ?PASS}}).
+-define(JSON, {"Content-Type", "application/json"}).
+
+-define(DOC, <<"doc">>).
+-define(REVA, <<"reva">>).
+-define(REVB, <<"revb">>).
+-define(REVC, <<"revc">>).
+-define(ATT, <<"att">>).
+-define(ATT_DATA, <<"dGhlZGF0YQ==">>).
+
+-define(DOC_COUNT, 2000).
+
+test_docs_revs() ->
+ [
+ {?DOC, [?REVA]},
+ {?DOC, [?REVB, ?REVA]},
+ {?DOC, [?REVC, ?REVA]}
+ ].
+
+bulk_get_test_() ->
+ {
+ setup,
+ fun setup_basic/0,
+ fun teardown/1,
+ with([
+ ?TDEF(t_empty_request),
+ ?TDEF(t_no_docs),
+ ?TDEF(t_invalid_doc),
+ ?TDEF(t_doc_no_id),
+ ?TDEF(t_missing_doc),
+ ?TDEF(t_invalid_rev),
+ ?TDEF(t_missing_rev),
+ ?TDEF(t_doc_all_revs),
+ ?TDEF(t_specific_rev),
+ ?TDEF(t_specific_rev_latest),
+ ?TDEF(t_ancestor_rev_latest),
+ ?TDEF(t_revs_true),
+ ?TDEF(t_attachments_true),
+ ?TDEF(t_atts_since),
+ ?TDEF(t_atts_since_returns_attachment),
+ ?TDEF(t_atts_since_attachments_true),
+ ?TDEF(t_atts_since_multiple),
+ ?TDEF(t_atts_since_multiple_attachments_true),
+ ?TDEF(t_missing_rev_latest)
+ ])
+ }.
+
+bulk_get_multiple_docs_test_() ->
+ {
+ foreach,
+ fun setup_multiple/0,
+ fun teardown/1,
+ [
+ ?TDEF_FE(t_multiple_docs, 10)
+ ]
+ }.
+
+t_empty_request({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, []),
+ ?assertEqual(200, Code),
+ ?assertEqual([], Res).
+
+t_no_docs({_, DbUrl}) ->
+ {Code, #{}} = req(post, DbUrl ++ "/_bulk_get", #{}),
+ ?assertEqual(400, Code).
+
+t_invalid_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [<<"foo">>]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_doc_no_id({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"rev">> => <<"1-foo">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_missing_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => <<"missing">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := <<"missing">>,
+ <<"rev">> := <<"undefined">>
+ }
+ }
+ ],
+ <<"id">> := <<"missing">>
+ }
+ ],
+ Res
+ ).
+
+t_invalid_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => 42},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"bad_request">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := 42
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_missing_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-x">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := <<"1-x">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_doc_all_revs({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => ?DOC}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ },
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revc">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_ancestor_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-reva">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ },
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revc">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_revs_true({_, DbUrl}) ->
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"1-reva">>
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?revs=true"),
Review Comment:
Also not seeing docs for bulk_get `revs=true`.
##########
src/chttpd/test/eunit/chttpd_bulk_get_test.erl:
##########
@@ -0,0 +1,785 @@
+% 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_bulk_get_test).
+
+-include_lib("couch/include/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+
+-define(USER, "chttpd_bulk_get_test_admin").
+-define(PASS, "pass").
+-define(AUTH, {basic_auth, {?USER, ?PASS}}).
+-define(JSON, {"Content-Type", "application/json"}).
+
+-define(DOC, <<"doc">>).
+-define(REVA, <<"reva">>).
+-define(REVB, <<"revb">>).
+-define(REVC, <<"revc">>).
+-define(ATT, <<"att">>).
+-define(ATT_DATA, <<"dGhlZGF0YQ==">>).
+
+-define(DOC_COUNT, 2000).
+
+test_docs_revs() ->
+ [
+ {?DOC, [?REVA]},
+ {?DOC, [?REVB, ?REVA]},
+ {?DOC, [?REVC, ?REVA]}
+ ].
+
+bulk_get_test_() ->
+ {
+ setup,
+ fun setup_basic/0,
+ fun teardown/1,
+ with([
+ ?TDEF(t_empty_request),
+ ?TDEF(t_no_docs),
+ ?TDEF(t_invalid_doc),
+ ?TDEF(t_doc_no_id),
+ ?TDEF(t_missing_doc),
+ ?TDEF(t_invalid_rev),
+ ?TDEF(t_missing_rev),
+ ?TDEF(t_doc_all_revs),
+ ?TDEF(t_specific_rev),
+ ?TDEF(t_specific_rev_latest),
+ ?TDEF(t_ancestor_rev_latest),
+ ?TDEF(t_revs_true),
+ ?TDEF(t_attachments_true),
+ ?TDEF(t_atts_since),
+ ?TDEF(t_atts_since_returns_attachment),
+ ?TDEF(t_atts_since_attachments_true),
+ ?TDEF(t_atts_since_multiple),
+ ?TDEF(t_atts_since_multiple_attachments_true),
+ ?TDEF(t_missing_rev_latest)
+ ])
+ }.
+
+bulk_get_multiple_docs_test_() ->
+ {
+ foreach,
+ fun setup_multiple/0,
+ fun teardown/1,
+ [
+ ?TDEF_FE(t_multiple_docs, 10)
+ ]
+ }.
+
+t_empty_request({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, []),
+ ?assertEqual(200, Code),
+ ?assertEqual([], Res).
+
+t_no_docs({_, DbUrl}) ->
+ {Code, #{}} = req(post, DbUrl ++ "/_bulk_get", #{}),
+ ?assertEqual(400, Code).
+
+t_invalid_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [<<"foo">>]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_doc_no_id({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"rev">> => <<"1-foo">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_missing_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => <<"missing">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := <<"missing">>,
+ <<"rev">> := <<"undefined">>
+ }
+ }
+ ],
+ <<"id">> := <<"missing">>
+ }
+ ],
+ Res
+ ).
+
+t_invalid_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => 42},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"bad_request">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := 42
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_missing_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-x">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := <<"1-x">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_doc_all_revs({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => ?DOC}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ },
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revc">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_ancestor_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-reva">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
Review Comment:
I looked for docs on `latest=true` [here](https://docs.couchdb.org/en/3.2.2-docs/api/database/bulk-api.html#db-bulk-get) but didn't see anything. Should we improve the docs, or is this an undocumented parameter?
##########
src/chttpd/test/eunit/chttpd_bulk_get_test.erl:
##########
@@ -0,0 +1,785 @@
+% 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_bulk_get_test).
+
+-include_lib("couch/include/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+
+-define(USER, "chttpd_bulk_get_test_admin").
+-define(PASS, "pass").
+-define(AUTH, {basic_auth, {?USER, ?PASS}}).
+-define(JSON, {"Content-Type", "application/json"}).
+
+-define(DOC, <<"doc">>).
+-define(REVA, <<"reva">>).
+-define(REVB, <<"revb">>).
+-define(REVC, <<"revc">>).
+-define(ATT, <<"att">>).
+-define(ATT_DATA, <<"dGhlZGF0YQ==">>).
+
+-define(DOC_COUNT, 2000).
+
+test_docs_revs() ->
+ [
+ {?DOC, [?REVA]},
+ {?DOC, [?REVB, ?REVA]},
+ {?DOC, [?REVC, ?REVA]}
+ ].
+
+bulk_get_test_() ->
+ {
+ setup,
+ fun setup_basic/0,
+ fun teardown/1,
+ with([
+ ?TDEF(t_empty_request),
+ ?TDEF(t_no_docs),
+ ?TDEF(t_invalid_doc),
+ ?TDEF(t_doc_no_id),
+ ?TDEF(t_missing_doc),
+ ?TDEF(t_invalid_rev),
+ ?TDEF(t_missing_rev),
+ ?TDEF(t_doc_all_revs),
+ ?TDEF(t_specific_rev),
+ ?TDEF(t_specific_rev_latest),
+ ?TDEF(t_ancestor_rev_latest),
+ ?TDEF(t_revs_true),
+ ?TDEF(t_attachments_true),
+ ?TDEF(t_atts_since),
+ ?TDEF(t_atts_since_returns_attachment),
+ ?TDEF(t_atts_since_attachments_true),
+ ?TDEF(t_atts_since_multiple),
+ ?TDEF(t_atts_since_multiple_attachments_true),
+ ?TDEF(t_missing_rev_latest)
+ ])
+ }.
+
+bulk_get_multiple_docs_test_() ->
+ {
+ foreach,
+ fun setup_multiple/0,
+ fun teardown/1,
+ [
+ ?TDEF_FE(t_multiple_docs, 10)
+ ]
+ }.
+
+t_empty_request({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, []),
+ ?assertEqual(200, Code),
+ ?assertEqual([], Res).
+
+t_no_docs({_, DbUrl}) ->
+ {Code, #{}} = req(post, DbUrl ++ "/_bulk_get", #{}),
+ ?assertEqual(400, Code).
+
+t_invalid_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [<<"foo">>]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_doc_no_id({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"rev">> => <<"1-foo">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_missing_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => <<"missing">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := <<"missing">>,
+ <<"rev">> := <<"undefined">>
+ }
+ }
+ ],
+ <<"id">> := <<"missing">>
+ }
+ ],
+ Res
+ ).
+
+t_invalid_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => 42},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"bad_request">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := 42
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_missing_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-x">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := <<"1-x">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_doc_all_revs({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => ?DOC}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ },
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revc">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_ancestor_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-reva">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ },
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revc">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_revs_true({_, DbUrl}) ->
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"1-reva">>
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?revs=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"1-reva">>,
+ <<"_revisions">> :=
+ #{<<"ids">> := [<<"reva">>], <<"start">> := 1},
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_attachments_true({_, DbUrl}) ->
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"1-reva">>
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?attachments=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"1-reva">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since({_, DbUrl}) ->
+ % Attachment should not be returned as 2 from 2-revb is not stricly greater
+ % than 1 from our attachment's revpos
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"2-revb">>]
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_returns_attachment({_, DbUrl}) ->
+ % 0-baz revpos 0 is less than revpos 1 of our attachment
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"0-baz">>]
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_attachments_true({_, DbUrl}) ->
+ % Check that atts_since overrides attachments=true
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"2-revb">>]
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?attachments=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{
+ <<"stub">> := true
+ }
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_multiple({_, DbUrl}) ->
+ % Attachment revpos is 1 so we do not expect this attachment body
+ Docs = [
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"2-revb">>]
+ },
+ % Should get the attachment revpos=1 is greater than 0-foo
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"0-foo">>]
+ },
+ % Empty atts_since. Do not expect to get the attachment
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => []
+ },
+ % Add a document without atts_since to ensure atts_since applies only to
+ % individual requests
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>
+ }
+ ],
+ {Code, Res} = bulk_get(DbUrl, Docs),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ },
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ },
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ },
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ },
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ },
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ },
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> :=
+ #{?ATT := #{<<"stub">> := true}},
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_multiple_attachments_true({_, DbUrl}) ->
+ % Since attachments=true, expect to always get the attachments, unless
+ % there is an atts_since present and atts_since would prevent the
+ % attachment from being returned.
+ Docs = [
+ % Attachment revpos is 1 so we do not expect this attachment body
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"2-revb">>]
+ },
+ % Should get the attachment revpos=1 is greater than 0-foo
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"0-foo">>]
+ },
+ % Should get the attachment as it is set as a default option
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => []
+ },
+ % Check a doc without atts_since to ensure atts_since applies only to
+ % individual requests, otherwise default options apply
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>
+ }
+ ],
+ {Code, Res} = bulk_get(DbUrl, Docs, "?attachments=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ },
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ },
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ },
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ },
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ },
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ },
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> :=
+ #{?ATT := #{<<"data">> := ?ATT_DATA}},
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_missing_rev_latest({_, DbUrl}) ->
+ % Check the case of latest and a missing
Review Comment:
should this be "and a missing _rev_"?
##########
src/chttpd/test/eunit/chttpd_bulk_get_test.erl:
##########
@@ -0,0 +1,785 @@
+% 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_bulk_get_test).
+
+-include_lib("couch/include/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+
+-define(USER, "chttpd_bulk_get_test_admin").
+-define(PASS, "pass").
+-define(AUTH, {basic_auth, {?USER, ?PASS}}).
+-define(JSON, {"Content-Type", "application/json"}).
+
+-define(DOC, <<"doc">>).
+-define(REVA, <<"reva">>).
+-define(REVB, <<"revb">>).
+-define(REVC, <<"revc">>).
+-define(ATT, <<"att">>).
+-define(ATT_DATA, <<"dGhlZGF0YQ==">>).
+
+-define(DOC_COUNT, 2000).
+
+test_docs_revs() ->
+ [
+ {?DOC, [?REVA]},
+ {?DOC, [?REVB, ?REVA]},
+ {?DOC, [?REVC, ?REVA]}
+ ].
+
+bulk_get_test_() ->
+ {
+ setup,
+ fun setup_basic/0,
+ fun teardown/1,
+ with([
+ ?TDEF(t_empty_request),
+ ?TDEF(t_no_docs),
+ ?TDEF(t_invalid_doc),
+ ?TDEF(t_doc_no_id),
+ ?TDEF(t_missing_doc),
+ ?TDEF(t_invalid_rev),
+ ?TDEF(t_missing_rev),
+ ?TDEF(t_doc_all_revs),
+ ?TDEF(t_specific_rev),
+ ?TDEF(t_specific_rev_latest),
+ ?TDEF(t_ancestor_rev_latest),
+ ?TDEF(t_revs_true),
+ ?TDEF(t_attachments_true),
+ ?TDEF(t_atts_since),
+ ?TDEF(t_atts_since_returns_attachment),
+ ?TDEF(t_atts_since_attachments_true),
+ ?TDEF(t_atts_since_multiple),
+ ?TDEF(t_atts_since_multiple_attachments_true),
+ ?TDEF(t_missing_rev_latest)
+ ])
+ }.
+
+bulk_get_multiple_docs_test_() ->
+ {
+ foreach,
+ fun setup_multiple/0,
+ fun teardown/1,
+ [
+ ?TDEF_FE(t_multiple_docs, 10)
+ ]
+ }.
+
+t_empty_request({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, []),
+ ?assertEqual(200, Code),
+ ?assertEqual([], Res).
+
+t_no_docs({_, DbUrl}) ->
+ {Code, #{}} = req(post, DbUrl ++ "/_bulk_get", #{}),
+ ?assertEqual(400, Code).
+
+t_invalid_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [<<"foo">>]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_doc_no_id({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"rev">> => <<"1-foo">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_missing_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => <<"missing">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := <<"missing">>,
+ <<"rev">> := <<"undefined">>
+ }
+ }
+ ],
+ <<"id">> := <<"missing">>
+ }
+ ],
+ Res
+ ).
+
+t_invalid_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => 42},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"bad_request">>,
Review Comment:
Seems like it would be nice to say _why_ it's a bad request (invalid rev in this case), but I guess that ship has sailed?
##########
src/chttpd/test/eunit/chttpd_bulk_get_test.erl:
##########
@@ -0,0 +1,785 @@
+% 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_bulk_get_test).
+
+-include_lib("couch/include/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+
+-define(USER, "chttpd_bulk_get_test_admin").
+-define(PASS, "pass").
+-define(AUTH, {basic_auth, {?USER, ?PASS}}).
+-define(JSON, {"Content-Type", "application/json"}).
+
+-define(DOC, <<"doc">>).
+-define(REVA, <<"reva">>).
+-define(REVB, <<"revb">>).
+-define(REVC, <<"revc">>).
+-define(ATT, <<"att">>).
+-define(ATT_DATA, <<"dGhlZGF0YQ==">>).
+
+-define(DOC_COUNT, 2000).
+
+test_docs_revs() ->
+ [
+ {?DOC, [?REVA]},
+ {?DOC, [?REVB, ?REVA]},
+ {?DOC, [?REVC, ?REVA]}
+ ].
+
+bulk_get_test_() ->
+ {
+ setup,
+ fun setup_basic/0,
+ fun teardown/1,
+ with([
+ ?TDEF(t_empty_request),
+ ?TDEF(t_no_docs),
+ ?TDEF(t_invalid_doc),
+ ?TDEF(t_doc_no_id),
+ ?TDEF(t_missing_doc),
+ ?TDEF(t_invalid_rev),
+ ?TDEF(t_missing_rev),
+ ?TDEF(t_doc_all_revs),
+ ?TDEF(t_specific_rev),
+ ?TDEF(t_specific_rev_latest),
+ ?TDEF(t_ancestor_rev_latest),
+ ?TDEF(t_revs_true),
+ ?TDEF(t_attachments_true),
+ ?TDEF(t_atts_since),
+ ?TDEF(t_atts_since_returns_attachment),
+ ?TDEF(t_atts_since_attachments_true),
+ ?TDEF(t_atts_since_multiple),
+ ?TDEF(t_atts_since_multiple_attachments_true),
+ ?TDEF(t_missing_rev_latest)
+ ])
+ }.
+
+bulk_get_multiple_docs_test_() ->
+ {
+ foreach,
+ fun setup_multiple/0,
+ fun teardown/1,
+ [
+ ?TDEF_FE(t_multiple_docs, 10)
+ ]
+ }.
+
+t_empty_request({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, []),
+ ?assertEqual(200, Code),
+ ?assertEqual([], Res).
+
+t_no_docs({_, DbUrl}) ->
+ {Code, #{}} = req(post, DbUrl ++ "/_bulk_get", #{}),
+ ?assertEqual(400, Code).
+
+t_invalid_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [<<"foo">>]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_doc_no_id({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"rev">> => <<"1-foo">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_missing_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => <<"missing">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := <<"missing">>,
+ <<"rev">> := <<"undefined">>
+ }
+ }
+ ],
+ <<"id">> := <<"missing">>
+ }
+ ],
+ Res
+ ).
+
+t_invalid_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => 42},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"bad_request">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := 42
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_missing_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-x">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := <<"1-x">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_doc_all_revs({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => ?DOC}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ },
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revc">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_ancestor_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-reva">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ },
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revc">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_revs_true({_, DbUrl}) ->
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"1-reva">>
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?revs=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"1-reva">>,
+ <<"_revisions">> :=
+ #{<<"ids">> := [<<"reva">>], <<"start">> := 1},
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_attachments_true({_, DbUrl}) ->
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"1-reva">>
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?attachments=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"1-reva">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since({_, DbUrl}) ->
+ % Attachment should not be returned as 2 from 2-revb is not stricly greater
+ % than 1 from our attachment's revpos
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"2-revb">>]
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_returns_attachment({_, DbUrl}) ->
+ % 0-baz revpos 0 is less than revpos 1 of our attachment
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"0-baz">>]
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_attachments_true({_, DbUrl}) ->
+ % Check that atts_since overrides attachments=true
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"2-revb">>]
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?attachments=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{
+ <<"stub">> := true
+ }
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_multiple({_, DbUrl}) ->
+ % Attachment revpos is 1 so we do not expect this attachment body
+ Docs = [
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"2-revb">>]
+ },
+ % Should get the attachment revpos=1 is greater than 0-foo
Review Comment:
missing "since" between attachment and revpos=1?
##########
src/chttpd/test/eunit/chttpd_bulk_get_test.erl:
##########
@@ -0,0 +1,785 @@
+% 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_bulk_get_test).
+
+-include_lib("couch/include/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+
+-define(USER, "chttpd_bulk_get_test_admin").
+-define(PASS, "pass").
+-define(AUTH, {basic_auth, {?USER, ?PASS}}).
+-define(JSON, {"Content-Type", "application/json"}).
+
+-define(DOC, <<"doc">>).
+-define(REVA, <<"reva">>).
+-define(REVB, <<"revb">>).
+-define(REVC, <<"revc">>).
+-define(ATT, <<"att">>).
+-define(ATT_DATA, <<"dGhlZGF0YQ==">>).
+
+-define(DOC_COUNT, 2000).
+
+test_docs_revs() ->
+ [
+ {?DOC, [?REVA]},
+ {?DOC, [?REVB, ?REVA]},
+ {?DOC, [?REVC, ?REVA]}
+ ].
+
+bulk_get_test_() ->
+ {
+ setup,
+ fun setup_basic/0,
+ fun teardown/1,
+ with([
+ ?TDEF(t_empty_request),
+ ?TDEF(t_no_docs),
+ ?TDEF(t_invalid_doc),
+ ?TDEF(t_doc_no_id),
+ ?TDEF(t_missing_doc),
+ ?TDEF(t_invalid_rev),
+ ?TDEF(t_missing_rev),
+ ?TDEF(t_doc_all_revs),
+ ?TDEF(t_specific_rev),
+ ?TDEF(t_specific_rev_latest),
+ ?TDEF(t_ancestor_rev_latest),
+ ?TDEF(t_revs_true),
+ ?TDEF(t_attachments_true),
+ ?TDEF(t_atts_since),
+ ?TDEF(t_atts_since_returns_attachment),
+ ?TDEF(t_atts_since_attachments_true),
+ ?TDEF(t_atts_since_multiple),
+ ?TDEF(t_atts_since_multiple_attachments_true),
+ ?TDEF(t_missing_rev_latest)
+ ])
+ }.
+
+bulk_get_multiple_docs_test_() ->
+ {
+ foreach,
+ fun setup_multiple/0,
+ fun teardown/1,
+ [
+ ?TDEF_FE(t_multiple_docs, 10)
+ ]
+ }.
+
+t_empty_request({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, []),
+ ?assertEqual(200, Code),
+ ?assertEqual([], Res).
+
+t_no_docs({_, DbUrl}) ->
+ {Code, #{}} = req(post, DbUrl ++ "/_bulk_get", #{}),
+ ?assertEqual(400, Code).
+
+t_invalid_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [<<"foo">>]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_doc_no_id({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"rev">> => <<"1-foo">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_missing_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => <<"missing">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := <<"missing">>,
+ <<"rev">> := <<"undefined">>
+ }
+ }
+ ],
+ <<"id">> := <<"missing">>
+ }
+ ],
+ Res
+ ).
+
+t_invalid_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => 42},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"bad_request">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := 42
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_missing_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-x">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := <<"1-x">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_doc_all_revs({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => ?DOC}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ },
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revc">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_ancestor_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-reva">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ },
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revc">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_revs_true({_, DbUrl}) ->
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"1-reva">>
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?revs=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"1-reva">>,
+ <<"_revisions">> :=
+ #{<<"ids">> := [<<"reva">>], <<"start">> := 1},
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_attachments_true({_, DbUrl}) ->
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"1-reva">>
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?attachments=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"1-reva">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since({_, DbUrl}) ->
+ % Attachment should not be returned as 2 from 2-revb is not stricly greater
+ % than 1 from our attachment's revpos
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"2-revb">>]
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_returns_attachment({_, DbUrl}) ->
+ % 0-baz revpos 0 is less than revpos 1 of our attachment
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"0-baz">>]
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_attachments_true({_, DbUrl}) ->
+ % Check that atts_since overrides attachments=true
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"2-revb">>]
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?attachments=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{
+ <<"stub">> := true
+ }
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_multiple({_, DbUrl}) ->
+ % Attachment revpos is 1 so we do not expect this attachment body
+ Docs = [
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"2-revb">>]
+ },
+ % Should get the attachment revpos=1 is greater than 0-foo
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"0-foo">>]
+ },
+ % Empty atts_since. Do not expect to get the attachment
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => []
+ },
+ % Add a document without atts_since to ensure atts_since applies only to
+ % individual requests
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>
+ }
+ ],
+ {Code, Res} = bulk_get(DbUrl, Docs),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ },
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ },
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ },
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ },
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ },
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ },
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> :=
+ #{?ATT := #{<<"stub">> := true}},
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_multiple_attachments_true({_, DbUrl}) ->
+ % Since attachments=true, expect to always get the attachments, unless
+ % there is an atts_since present and atts_since would prevent the
+ % attachment from being returned.
+ Docs = [
+ % Attachment revpos is 1 so we do not expect this attachment body
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"2-revb">>]
+ },
+ % Should get the attachment revpos=1 is greater than 0-foo
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"0-foo">>]
+ },
+ % Should get the attachment as it is set as a default option
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => []
+ },
+ % Check a doc without atts_since to ensure atts_since applies only to
+ % individual requests, otherwise default options apply
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>
+ }
+ ],
+ {Code, Res} = bulk_get(DbUrl, Docs, "?attachments=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ },
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ },
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ },
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ },
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ },
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ },
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_attachments">> :=
+ #{?ATT := #{<<"data">> := ?ATT_DATA}},
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_missing_rev_latest({_, DbUrl}) ->
+ % Check the case of latest and a missing
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-x">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := <<"1-x">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_multiple_docs({_, DbUrl}) ->
+ Reqs = [#{<<"id">> => integer_to_binary(I)} || I <- lists:seq(1, ?DOC_COUNT)],
+ {Code, Res} = bulk_get(DbUrl, Reqs),
+ ?assertEqual(200, Code),
+ ?assertMatch([#{<<"docs">> := _} | _], Res),
+ ?assertEqual(?DOC_COUNT, length(Res)),
+ lists:foreach(
+ fun({I, Docs}) ->
+ Id = integer_to_binary(I),
+ ?assertMatch(
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := Id,
+ <<"_rev">> := <<"1-reva">>
+ }
+ }
+ ],
+ <<"id">> := Id
+ },
+ Docs
+ )
+ end,
+ lists:zip(lists:seq(1, ?DOC_COUNT), Res)
+ ).
+
+% Utility functions
+
+setup_ctx() ->
+ Ctx = test_util:start_couch([chttpd]),
+ Hashed = couch_passwords:hash_admin_password(?PASS),
+ ok = config:set("admins", ?USER, ?b2l(Hashed), _Persist = false),
+ Addr = config:get("chttpd", "bind_address", "127.0.0.1"),
+ Db = binary_to_list(?tempdb()),
Review Comment:
Maybe use either `?b2l` or `binary_to_list` rather than both? I prefer the latter personally.
##########
src/chttpd/test/eunit/chttpd_bulk_get_test.erl:
##########
@@ -0,0 +1,785 @@
+% 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_bulk_get_test).
+
+-include_lib("couch/include/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+
+-define(USER, "chttpd_bulk_get_test_admin").
+-define(PASS, "pass").
+-define(AUTH, {basic_auth, {?USER, ?PASS}}).
+-define(JSON, {"Content-Type", "application/json"}).
+
+-define(DOC, <<"doc">>).
+-define(REVA, <<"reva">>).
+-define(REVB, <<"revb">>).
+-define(REVC, <<"revc">>).
+-define(ATT, <<"att">>).
+-define(ATT_DATA, <<"dGhlZGF0YQ==">>).
+
+-define(DOC_COUNT, 2000).
+
+test_docs_revs() ->
+ [
+ {?DOC, [?REVA]},
+ {?DOC, [?REVB, ?REVA]},
+ {?DOC, [?REVC, ?REVA]}
+ ].
+
+bulk_get_test_() ->
+ {
+ setup,
+ fun setup_basic/0,
+ fun teardown/1,
+ with([
+ ?TDEF(t_empty_request),
+ ?TDEF(t_no_docs),
+ ?TDEF(t_invalid_doc),
+ ?TDEF(t_doc_no_id),
+ ?TDEF(t_missing_doc),
+ ?TDEF(t_invalid_rev),
+ ?TDEF(t_missing_rev),
+ ?TDEF(t_doc_all_revs),
+ ?TDEF(t_specific_rev),
+ ?TDEF(t_specific_rev_latest),
+ ?TDEF(t_ancestor_rev_latest),
+ ?TDEF(t_revs_true),
+ ?TDEF(t_attachments_true),
+ ?TDEF(t_atts_since),
+ ?TDEF(t_atts_since_returns_attachment),
+ ?TDEF(t_atts_since_attachments_true),
+ ?TDEF(t_atts_since_multiple),
+ ?TDEF(t_atts_since_multiple_attachments_true),
+ ?TDEF(t_missing_rev_latest)
+ ])
+ }.
+
+bulk_get_multiple_docs_test_() ->
+ {
+ foreach,
+ fun setup_multiple/0,
+ fun teardown/1,
+ [
+ ?TDEF_FE(t_multiple_docs, 10)
+ ]
+ }.
+
+t_empty_request({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, []),
+ ?assertEqual(200, Code),
+ ?assertEqual([], Res).
+
+t_no_docs({_, DbUrl}) ->
+ {Code, #{}} = req(post, DbUrl ++ "/_bulk_get", #{}),
+ ?assertEqual(400, Code).
+
+t_invalid_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [<<"foo">>]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_doc_no_id({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"rev">> => <<"1-foo">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_missing_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => <<"missing">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := <<"missing">>,
+ <<"rev">> := <<"undefined">>
+ }
+ }
+ ],
+ <<"id">> := <<"missing">>
+ }
+ ],
+ Res
+ ).
+
+t_invalid_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => 42},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"bad_request">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := 42
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_missing_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-x">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := <<"1-x">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_doc_all_revs({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => ?DOC}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ },
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revc">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_ancestor_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-reva">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ },
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revc">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_revs_true({_, DbUrl}) ->
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"1-reva">>
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?revs=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"1-reva">>,
+ <<"_revisions">> :=
+ #{<<"ids">> := [<<"reva">>], <<"start">> := 1},
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_attachments_true({_, DbUrl}) ->
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"1-reva">>
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?attachments=true"),
Review Comment:
ditto
##########
src/chttpd/test/eunit/chttpd_bulk_get_test.erl:
##########
@@ -0,0 +1,785 @@
+% 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_bulk_get_test).
+
+-include_lib("couch/include/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+
+-define(USER, "chttpd_bulk_get_test_admin").
+-define(PASS, "pass").
+-define(AUTH, {basic_auth, {?USER, ?PASS}}).
+-define(JSON, {"Content-Type", "application/json"}).
+
+-define(DOC, <<"doc">>).
+-define(REVA, <<"reva">>).
+-define(REVB, <<"revb">>).
+-define(REVC, <<"revc">>).
+-define(ATT, <<"att">>).
+-define(ATT_DATA, <<"dGhlZGF0YQ==">>).
+
+-define(DOC_COUNT, 2000).
+
+test_docs_revs() ->
+ [
+ {?DOC, [?REVA]},
+ {?DOC, [?REVB, ?REVA]},
+ {?DOC, [?REVC, ?REVA]}
+ ].
+
+bulk_get_test_() ->
+ {
+ setup,
+ fun setup_basic/0,
+ fun teardown/1,
+ with([
+ ?TDEF(t_empty_request),
+ ?TDEF(t_no_docs),
+ ?TDEF(t_invalid_doc),
+ ?TDEF(t_doc_no_id),
+ ?TDEF(t_missing_doc),
+ ?TDEF(t_invalid_rev),
+ ?TDEF(t_missing_rev),
+ ?TDEF(t_doc_all_revs),
+ ?TDEF(t_specific_rev),
+ ?TDEF(t_specific_rev_latest),
+ ?TDEF(t_ancestor_rev_latest),
+ ?TDEF(t_revs_true),
+ ?TDEF(t_attachments_true),
+ ?TDEF(t_atts_since),
+ ?TDEF(t_atts_since_returns_attachment),
+ ?TDEF(t_atts_since_attachments_true),
+ ?TDEF(t_atts_since_multiple),
+ ?TDEF(t_atts_since_multiple_attachments_true),
+ ?TDEF(t_missing_rev_latest)
+ ])
+ }.
+
+bulk_get_multiple_docs_test_() ->
+ {
+ foreach,
+ fun setup_multiple/0,
+ fun teardown/1,
+ [
+ ?TDEF_FE(t_multiple_docs, 10)
+ ]
+ }.
+
+t_empty_request({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, []),
+ ?assertEqual(200, Code),
+ ?assertEqual([], Res).
+
+t_no_docs({_, DbUrl}) ->
+ {Code, #{}} = req(post, DbUrl ++ "/_bulk_get", #{}),
+ ?assertEqual(400, Code).
+
+t_invalid_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [<<"foo">>]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_doc_no_id({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"rev">> => <<"1-foo">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_missing_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => <<"missing">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := <<"missing">>,
+ <<"rev">> := <<"undefined">>
+ }
+ }
+ ],
+ <<"id">> := <<"missing">>
+ }
+ ],
+ Res
+ ).
+
+t_invalid_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => 42},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"bad_request">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := 42
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_missing_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-x">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
Review Comment:
As a perplexed user, I might think it's the doc id that's not found rather than the rev. I guess we'd need to change existing behavior to enhance this to become e.g. `rev_not_found`?
##########
src/chttpd/test/eunit/chttpd_bulk_get_test.erl:
##########
@@ -0,0 +1,785 @@
+% 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_bulk_get_test).
+
+-include_lib("couch/include/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+
+-define(USER, "chttpd_bulk_get_test_admin").
+-define(PASS, "pass").
+-define(AUTH, {basic_auth, {?USER, ?PASS}}).
+-define(JSON, {"Content-Type", "application/json"}).
+
+-define(DOC, <<"doc">>).
+-define(REVA, <<"reva">>).
+-define(REVB, <<"revb">>).
+-define(REVC, <<"revc">>).
+-define(ATT, <<"att">>).
+-define(ATT_DATA, <<"dGhlZGF0YQ==">>).
+
+-define(DOC_COUNT, 2000).
+
+test_docs_revs() ->
+ [
+ {?DOC, [?REVA]},
+ {?DOC, [?REVB, ?REVA]},
+ {?DOC, [?REVC, ?REVA]}
+ ].
+
+bulk_get_test_() ->
+ {
+ setup,
+ fun setup_basic/0,
+ fun teardown/1,
+ with([
+ ?TDEF(t_empty_request),
+ ?TDEF(t_no_docs),
+ ?TDEF(t_invalid_doc),
+ ?TDEF(t_doc_no_id),
+ ?TDEF(t_missing_doc),
+ ?TDEF(t_invalid_rev),
+ ?TDEF(t_missing_rev),
+ ?TDEF(t_doc_all_revs),
+ ?TDEF(t_specific_rev),
+ ?TDEF(t_specific_rev_latest),
+ ?TDEF(t_ancestor_rev_latest),
+ ?TDEF(t_revs_true),
+ ?TDEF(t_attachments_true),
+ ?TDEF(t_atts_since),
+ ?TDEF(t_atts_since_returns_attachment),
+ ?TDEF(t_atts_since_attachments_true),
+ ?TDEF(t_atts_since_multiple),
+ ?TDEF(t_atts_since_multiple_attachments_true),
+ ?TDEF(t_missing_rev_latest)
+ ])
+ }.
+
+bulk_get_multiple_docs_test_() ->
+ {
+ foreach,
+ fun setup_multiple/0,
+ fun teardown/1,
+ [
+ ?TDEF_FE(t_multiple_docs, 10)
+ ]
+ }.
+
+t_empty_request({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, []),
+ ?assertEqual(200, Code),
+ ?assertEqual([], Res).
+
+t_no_docs({_, DbUrl}) ->
+ {Code, #{}} = req(post, DbUrl ++ "/_bulk_get", #{}),
+ ?assertEqual(400, Code).
+
+t_invalid_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [<<"foo">>]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_doc_no_id({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"rev">> => <<"1-foo">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_missing_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => <<"missing">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := <<"missing">>,
+ <<"rev">> := <<"undefined">>
+ }
+ }
+ ],
+ <<"id">> := <<"missing">>
+ }
+ ],
+ Res
+ ).
+
+t_invalid_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => 42},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"bad_request">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := 42
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_missing_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-x">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := <<"1-x">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_doc_all_revs({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => ?DOC}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ },
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revc">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_ancestor_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-reva">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ },
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revc">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_revs_true({_, DbUrl}) ->
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"1-reva">>
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?revs=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"1-reva">>,
+ <<"_revisions">> :=
+ #{<<"ids">> := [<<"reva">>], <<"start">> := 1},
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_attachments_true({_, DbUrl}) ->
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"1-reva">>
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?attachments=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"1-reva">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since({_, DbUrl}) ->
+ % Attachment should not be returned as 2 from 2-revb is not stricly greater
+ % than 1 from our attachment's revpos
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"2-revb">>]
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_returns_attachment({_, DbUrl}) ->
+ % 0-baz revpos 0 is less than revpos 1 of our attachment
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"0-baz">>]
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_attachments_true({_, DbUrl}) ->
+ % Check that atts_since overrides attachments=true
Review Comment:
You could alternately change the name to e.g. `t_atts_since_overrides_attachments_true` and possibly avoid the comment?
##########
src/chttpd/test/eunit/chttpd_bulk_get_test.erl:
##########
@@ -0,0 +1,785 @@
+% 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_bulk_get_test).
+
+-include_lib("couch/include/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+
+-define(USER, "chttpd_bulk_get_test_admin").
+-define(PASS, "pass").
+-define(AUTH, {basic_auth, {?USER, ?PASS}}).
+-define(JSON, {"Content-Type", "application/json"}).
+
+-define(DOC, <<"doc">>).
+-define(REVA, <<"reva">>).
+-define(REVB, <<"revb">>).
+-define(REVC, <<"revc">>).
+-define(ATT, <<"att">>).
+-define(ATT_DATA, <<"dGhlZGF0YQ==">>).
+
+-define(DOC_COUNT, 2000).
+
+test_docs_revs() ->
+ [
+ {?DOC, [?REVA]},
+ {?DOC, [?REVB, ?REVA]},
+ {?DOC, [?REVC, ?REVA]}
+ ].
+
+bulk_get_test_() ->
+ {
+ setup,
+ fun setup_basic/0,
+ fun teardown/1,
+ with([
+ ?TDEF(t_empty_request),
+ ?TDEF(t_no_docs),
+ ?TDEF(t_invalid_doc),
+ ?TDEF(t_doc_no_id),
+ ?TDEF(t_missing_doc),
+ ?TDEF(t_invalid_rev),
+ ?TDEF(t_missing_rev),
+ ?TDEF(t_doc_all_revs),
+ ?TDEF(t_specific_rev),
+ ?TDEF(t_specific_rev_latest),
+ ?TDEF(t_ancestor_rev_latest),
+ ?TDEF(t_revs_true),
+ ?TDEF(t_attachments_true),
+ ?TDEF(t_atts_since),
+ ?TDEF(t_atts_since_returns_attachment),
+ ?TDEF(t_atts_since_attachments_true),
+ ?TDEF(t_atts_since_multiple),
+ ?TDEF(t_atts_since_multiple_attachments_true),
+ ?TDEF(t_missing_rev_latest)
+ ])
+ }.
+
+bulk_get_multiple_docs_test_() ->
+ {
+ foreach,
+ fun setup_multiple/0,
+ fun teardown/1,
+ [
+ ?TDEF_FE(t_multiple_docs, 10)
+ ]
+ }.
+
+t_empty_request({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, []),
+ ?assertEqual(200, Code),
+ ?assertEqual([], Res).
+
+t_no_docs({_, DbUrl}) ->
+ {Code, #{}} = req(post, DbUrl ++ "/_bulk_get", #{}),
+ ?assertEqual(400, Code).
+
+t_invalid_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [<<"foo">>]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_doc_no_id({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"rev">> => <<"1-foo">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"id">> := null,
+ <<"rev">> := null,
+ <<"error">> := <<"bad_request">>
+ }
+ }
+ ],
+ <<"id">> := null
+ }
+ ],
+ Res
+ ).
+
+t_missing_doc({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => <<"missing">>}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := <<"missing">>,
+ <<"rev">> := <<"undefined">>
+ }
+ }
+ ],
+ <<"id">> := <<"missing">>
+ }
+ ],
+ Res
+ ).
+
+t_invalid_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => 42},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"bad_request">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := 42
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_missing_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-x">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"error">> := #{
+ <<"error">> := <<"not_found">>,
+ <<"id">> := ?DOC,
+ <<"rev">> := <<"1-x">>
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_doc_all_revs({_, DbUrl}) ->
+ {Code, Res} = bulk_get(DbUrl, [#{<<"id">> => ?DOC}]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ },
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revc">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_specific_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"2-revb">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_ancestor_rev_latest({_, DbUrl}) ->
+ Doc = #{<<"id">> => ?DOC, <<"rev">> => <<"1-reva">>},
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?latest=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ },
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revc">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_revs_true({_, DbUrl}) ->
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"1-reva">>
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?revs=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"1-reva">>,
+ <<"_revisions">> :=
+ #{<<"ids">> := [<<"reva">>], <<"start">> := 1},
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_attachments_true({_, DbUrl}) ->
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"1-reva">>
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?attachments=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"1-reva">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since({_, DbUrl}) ->
+ % Attachment should not be returned as 2 from 2-revb is not stricly greater
+ % than 1 from our attachment's revpos
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"2-revb">>]
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"stub">> := true}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_returns_attachment({_, DbUrl}) ->
+ % 0-baz revpos 0 is less than revpos 1 of our attachment
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"0-baz">>]
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc]),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{<<"data">> := ?ATT_DATA}
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_attachments_true({_, DbUrl}) ->
+ % Check that atts_since overrides attachments=true
+ Doc = #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"2-revb">>]
+ },
+ {Code, Res} = bulk_get(DbUrl, [Doc], "?attachments=true"),
+ ?assertEqual(200, Code),
+ ?assertMatch(
+ [
+ #{
+ <<"docs">> := [
+ #{
+ <<"ok">> := #{
+ <<"_id">> := ?DOC,
+ <<"_rev">> := <<"2-revb">>,
+ <<"_attachments">> := #{
+ ?ATT := #{
+ <<"stub">> := true
+ }
+ }
+ }
+ }
+ ],
+ <<"id">> := ?DOC
+ }
+ ],
+ Res
+ ).
+
+t_atts_since_multiple({_, DbUrl}) ->
+ % Attachment revpos is 1 so we do not expect this attachment body
+ Docs = [
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"2-revb">>]
+ },
+ % Should get the attachment revpos=1 is greater than 0-foo
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => [<<"0-foo">>]
+ },
+ % Empty atts_since. Do not expect to get the attachment
+ #{
+ <<"id">> => ?DOC,
+ <<"rev">> => <<"2-revb">>,
+ <<"atts_since">> => []
+ },
+ % Add a document without atts_since to ensure atts_since applies only to
Review Comment:
maybe s/Add/Include/ ?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@couchdb.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org