You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ch...@apache.org on 2014/08/15 22:25:03 UTC
[36/50] [abbrv] Move files out of test/couchdb into top level test/
folder
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_auth_cache_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_auth_cache_tests.erl b/test/couchdb/couch_auth_cache_tests.erl
deleted file mode 100644
index 3b2321c..0000000
--- a/test/couchdb/couch_auth_cache_tests.erl
+++ /dev/null
@@ -1,238 +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(couch_auth_cache_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
--define(SALT, <<"SALT">>).
--define(TIMEOUT, 1000).
-
-
-start() ->
- {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
- Pid.
-
-stop(Pid) ->
- erlang:monitor(process, Pid),
- couch_server_sup:stop(),
- receive
- {'DOWN', _, _, Pid, _} ->
- ok
- after ?TIMEOUT ->
- throw({timeout, server_stop})
- end.
-
-setup() ->
- DbName = ?tempdb(),
- couch_config:set("couch_httpd_auth", "authentication_db",
- ?b2l(DbName), false),
- DbName.
-
-teardown(DbName) ->
- ok = couch_server:delete(DbName, [?ADMIN_USER]),
- ok.
-
-
-couch_auth_cache_test_() ->
- {
- "CouchDB auth cache tests",
- {
- setup,
- fun start/0, fun stop/1,
- {
- foreach,
- fun setup/0, fun teardown/1,
- [
- fun should_get_nil_on_missed_cache/1,
- fun should_get_right_password_hash/1,
- fun should_ensure_doc_hash_equals_cached_one/1,
- fun should_update_password/1,
- fun should_cleanup_cache_after_userdoc_deletion/1,
- fun should_restore_cache_after_userdoc_recreation/1,
- fun should_drop_cache_on_auth_db_change/1,
- fun should_restore_cache_on_auth_db_change/1,
- fun should_recover_cache_after_shutdown/1
- ]
- }
- }
- }.
-
-
-should_get_nil_on_missed_cache(_) ->
- ?_assertEqual(nil, couch_auth_cache:get_user_creds("joe")).
-
-should_get_right_password_hash(DbName) ->
- ?_test(begin
- PasswordHash = hash_password("pass1"),
- {ok, _} = update_user_doc(DbName, "joe", "pass1"),
- Creds = couch_auth_cache:get_user_creds("joe"),
- ?assertEqual(PasswordHash,
- couch_util:get_value(<<"password_sha">>, Creds))
- end).
-
-should_ensure_doc_hash_equals_cached_one(DbName) ->
- ?_test(begin
- {ok, _} = update_user_doc(DbName, "joe", "pass1"),
- Creds = couch_auth_cache:get_user_creds("joe"),
-
- CachedHash = couch_util:get_value(<<"password_sha">>, Creds),
- StoredHash = get_user_doc_password_sha(DbName, "joe"),
- ?assertEqual(StoredHash, CachedHash)
- end).
-
-should_update_password(DbName) ->
- ?_test(begin
- PasswordHash = hash_password("pass2"),
- {ok, Rev} = update_user_doc(DbName, "joe", "pass1"),
- {ok, _} = update_user_doc(DbName, "joe", "pass2", Rev),
- Creds = couch_auth_cache:get_user_creds("joe"),
- ?assertEqual(PasswordHash,
- couch_util:get_value(<<"password_sha">>, Creds))
- end).
-
-should_cleanup_cache_after_userdoc_deletion(DbName) ->
- ?_test(begin
- {ok, _} = update_user_doc(DbName, "joe", "pass1"),
- delete_user_doc(DbName, "joe"),
- ?assertEqual(nil, couch_auth_cache:get_user_creds("joe"))
- end).
-
-should_restore_cache_after_userdoc_recreation(DbName) ->
- ?_test(begin
- PasswordHash = hash_password("pass5"),
- {ok, _} = update_user_doc(DbName, "joe", "pass1"),
- delete_user_doc(DbName, "joe"),
- ?assertEqual(nil, couch_auth_cache:get_user_creds("joe")),
-
- {ok, _} = update_user_doc(DbName, "joe", "pass5"),
- Creds = couch_auth_cache:get_user_creds("joe"),
-
- ?assertEqual(PasswordHash,
- couch_util:get_value(<<"password_sha">>, Creds))
- end).
-
-should_drop_cache_on_auth_db_change(DbName) ->
- ?_test(begin
- {ok, _} = update_user_doc(DbName, "joe", "pass1"),
- full_commit(DbName),
- couch_config:set("couch_httpd_auth", "authentication_db",
- ?b2l(?tempdb()), false),
- ?assertEqual(nil, couch_auth_cache:get_user_creds("joe"))
- end).
-
-should_restore_cache_on_auth_db_change(DbName) ->
- ?_test(begin
- PasswordHash = hash_password("pass1"),
- {ok, _} = update_user_doc(DbName, "joe", "pass1"),
- Creds = couch_auth_cache:get_user_creds("joe"),
- full_commit(DbName),
-
- DbName1 = ?tempdb(),
- couch_config:set("couch_httpd_auth", "authentication_db",
- ?b2l(DbName1), false),
-
- {ok, _} = update_user_doc(DbName1, "joe", "pass5"),
- full_commit(DbName1),
-
- couch_config:set("couch_httpd_auth", "authentication_db",
- ?b2l(DbName), false),
-
- Creds = couch_auth_cache:get_user_creds("joe"),
- ?assertEqual(PasswordHash,
- couch_util:get_value(<<"password_sha">>, Creds))
- end).
-
-should_recover_cache_after_shutdown(DbName) ->
- ?_test(begin
- PasswordHash = hash_password("pass2"),
- {ok, Rev0} = update_user_doc(DbName, "joe", "pass1"),
- {ok, Rev1} = update_user_doc(DbName, "joe", "pass2", Rev0),
- full_commit(DbName),
- shutdown_db(DbName),
- {ok, Rev1} = get_doc_rev(DbName, "joe"),
- ?assertEqual(PasswordHash, get_user_doc_password_sha(DbName, "joe"))
- end).
-
-
-update_user_doc(DbName, UserName, Password) ->
- update_user_doc(DbName, UserName, Password, nil).
-
-update_user_doc(DbName, UserName, Password, Rev) ->
- User = iolist_to_binary(UserName),
- Doc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"org.couchdb.user:", User/binary>>},
- {<<"name">>, User},
- {<<"type">>, <<"user">>},
- {<<"salt">>, ?SALT},
- {<<"password_sha">>, hash_password(Password)},
- {<<"roles">>, []}
- ] ++ case Rev of
- nil -> [];
- _ -> [{<<"_rev">>, Rev}]
- end
- }),
- {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
- {ok, NewRev} = couch_db:update_doc(AuthDb, Doc, []),
- ok = couch_db:close(AuthDb),
- {ok, couch_doc:rev_to_str(NewRev)}.
-
-hash_password(Password) ->
- ?l2b(couch_util:to_hex(crypto:sha(iolist_to_binary([Password, ?SALT])))).
-
-shutdown_db(DbName) ->
- {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
- ok = couch_db:close(AuthDb),
- couch_util:shutdown_sync(AuthDb#db.main_pid),
- ok = timer:sleep(1000).
-
-get_doc_rev(DbName, UserName) ->
- DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
- {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
- UpdateRev =
- case couch_db:open_doc(AuthDb, DocId, []) of
- {ok, Doc} ->
- {Props} = couch_doc:to_json_obj(Doc, []),
- couch_util:get_value(<<"_rev">>, Props);
- {not_found, missing} ->
- nil
- end,
- ok = couch_db:close(AuthDb),
- {ok, UpdateRev}.
-
-get_user_doc_password_sha(DbName, UserName) ->
- DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
- {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
- {ok, Doc} = couch_db:open_doc(AuthDb, DocId, []),
- ok = couch_db:close(AuthDb),
- {Props} = couch_doc:to_json_obj(Doc, []),
- couch_util:get_value(<<"password_sha">>, Props).
-
-delete_user_doc(DbName, UserName) ->
- DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
- {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
- {ok, Doc} = couch_db:open_doc(AuthDb, DocId, []),
- {Props} = couch_doc:to_json_obj(Doc, []),
- DeletedDoc = couch_doc:from_json_obj({[
- {<<"_id">>, DocId},
- {<<"_rev">>, couch_util:get_value(<<"_rev">>, Props)},
- {<<"_deleted">>, true}
- ]}),
- {ok, _} = couch_db:update_doc(AuthDb, DeletedDoc, []),
- ok = couch_db:close(AuthDb).
-
-full_commit(DbName) ->
- {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
- {ok, _} = couch_db:ensure_full_commit(AuthDb),
- ok = couch_db:close(AuthDb).
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_btree_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_btree_tests.erl b/test/couchdb/couch_btree_tests.erl
deleted file mode 100644
index 911640f..0000000
--- a/test/couchdb/couch_btree_tests.erl
+++ /dev/null
@@ -1,551 +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(couch_btree_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(ROWS, 1000).
-
-
-setup() ->
- {ok, Fd} = couch_file:open(?tempfile(), [create, overwrite]),
- {ok, Btree} = couch_btree:open(nil, Fd, [{compression, none},
- {reduce, fun reduce_fun/2}]),
- {Fd, Btree}.
-
-setup_kvs(_) ->
- setup().
-
-setup_red() ->
- {_, EvenOddKVs} = lists:foldl(
- fun(Idx, {Key, Acc}) ->
- case Key of
- "even" -> {"odd", [{{Key, Idx}, 1} | Acc]};
- _ -> {"even", [{{Key, Idx}, 1} | Acc]}
- end
- end, {"odd", []}, lists:seq(1, ?ROWS)),
- {Fd, Btree} = setup(),
- {ok, Btree1} = couch_btree:add_remove(Btree, EvenOddKVs, []),
- {Fd, Btree1}.
-setup_red(_) ->
- setup_red().
-
-teardown(Fd) when is_pid(Fd) ->
- ok = couch_file:close(Fd);
-teardown({Fd, _}) ->
- teardown(Fd).
-teardown(_, {Fd, _}) ->
- teardown(Fd).
-
-
-kvs_test_funs() ->
- [
- fun should_set_fd_correctly/2,
- fun should_set_root_correctly/2,
- fun should_create_zero_sized_btree/2,
- fun should_set_reduce_option/2,
- fun should_fold_over_empty_btree/2,
- fun should_add_all_keys/2,
- fun should_continuously_add_new_kv/2,
- fun should_continuously_remove_keys/2,
- fun should_insert_keys_in_reversed_order/2,
- fun should_add_every_odd_key_remove_every_even/2,
- fun should_add_every_even_key_remove_every_old/2
- ].
-
-red_test_funs() ->
- [
- fun should_reduce_whole_range/2,
- fun should_reduce_first_half/2,
- fun should_reduce_second_half/2
- ].
-
-
-btree_open_test_() ->
- {ok, Fd} = couch_file:open(?tempfile(), [create, overwrite]),
- {ok, Btree} = couch_btree:open(nil, Fd, [{compression, none}]),
- {
- "Ensure that created btree is really a btree record",
- ?_assert(is_record(Btree, btree))
- }.
-
-sorted_kvs_test_() ->
- Funs = kvs_test_funs(),
- Sorted = [{Seq, random:uniform()} || Seq <- lists:seq(1, ?ROWS)],
- {
- "BTree with sorted keys",
- {
- foreachx,
- fun setup_kvs/1, fun teardown/2,
- [{Sorted, Fun} || Fun <- Funs]
- }
- }.
-
-rsorted_kvs_test_() ->
- Sorted = [{Seq, random:uniform()} || Seq <- lists:seq(1, ?ROWS)],
- Funs = kvs_test_funs(),
- Reversed = Sorted,
- {
- "BTree with backward sorted keys",
- {
- foreachx,
- fun setup_kvs/1, fun teardown/2,
- [{Reversed, Fun} || Fun <- Funs]
- }
- }.
-
-shuffled_kvs_test_() ->
- Funs = kvs_test_funs(),
- Sorted = [{Seq, random:uniform()} || Seq <- lists:seq(1, ?ROWS)],
- Shuffled = shuffle(Sorted),
- {
- "BTree with shuffled keys",
- {
- foreachx,
- fun setup_kvs/1, fun teardown/2,
- [{Shuffled, Fun} || Fun <- Funs]
- }
- }.
-
-reductions_test_() ->
- {
- "BTree reductions",
- [
- {
- "Common tests",
- {
- foreach,
- fun setup_red/0, fun teardown/1,
- [
- fun should_reduce_without_specified_direction/1,
- fun should_reduce_forward/1,
- fun should_reduce_backward/1
- ]
- }
- },
- {
- "Range requests",
- [
- {
- "Forward direction",
- {
- foreachx,
- fun setup_red/1, fun teardown/2,
- [{fwd, F} || F <- red_test_funs()]
- }
- },
- {
- "Backward direction",
- {
- foreachx,
- fun setup_red/1, fun teardown/2,
- [{rev, F} || F <- red_test_funs()]
- }
- }
- ]
- }
- ]
- }.
-
-
-should_set_fd_correctly(_, {Fd, Btree}) ->
- ?_assertMatch(Fd, Btree#btree.fd).
-
-should_set_root_correctly(_, {_, Btree}) ->
- ?_assertMatch(nil, Btree#btree.root).
-
-should_create_zero_sized_btree(_, {_, Btree}) ->
- ?_assertMatch(0, couch_btree:size(Btree)).
-
-should_set_reduce_option(_, {_, Btree}) ->
- ReduceFun = fun reduce_fun/2,
- Btree1 = couch_btree:set_options(Btree, [{reduce, ReduceFun}]),
- ?_assertMatch(ReduceFun, Btree1#btree.reduce).
-
-should_fold_over_empty_btree(_, {_, Btree}) ->
- {ok, _, EmptyRes} = couch_btree:foldl(Btree, fun(_, X) -> {ok, X+1} end, 0),
- ?_assertEqual(EmptyRes, 0).
-
-should_add_all_keys(KeyValues, {Fd, Btree}) ->
- {ok, Btree1} = couch_btree:add_remove(Btree, KeyValues, []),
- [
- should_return_complete_btree_on_adding_all_keys(KeyValues, Btree1),
- should_have_non_zero_size(Btree1),
- should_have_lesser_size_than_file(Fd, Btree1),
- should_keep_root_pointer_to_kp_node(Fd, Btree1),
- should_remove_all_keys(KeyValues, Btree1)
- ].
-
-should_return_complete_btree_on_adding_all_keys(KeyValues, Btree) ->
- ?_assert(test_btree(Btree, KeyValues)).
-
-should_have_non_zero_size(Btree) ->
- ?_assert(couch_btree:size(Btree) > 0).
-
-should_have_lesser_size_than_file(Fd, Btree) ->
- ?_assert((couch_btree:size(Btree) =< couch_file:bytes(Fd))).
-
-should_keep_root_pointer_to_kp_node(Fd, Btree) ->
- ?_assertMatch({ok, {kp_node, _}},
- couch_file:pread_term(Fd, element(1, Btree#btree.root))).
-
-should_remove_all_keys(KeyValues, Btree) ->
- Keys = keys(KeyValues),
- {ok, Btree1} = couch_btree:add_remove(Btree, [], Keys),
- {
- "Should remove all the keys",
- [
- should_produce_valid_btree(Btree1, []),
- should_be_empty(Btree1)
- ]
- }.
-
-should_continuously_add_new_kv(KeyValues, {_, Btree}) ->
- {Btree1, _} = lists:foldl(
- fun(KV, {BtAcc, PrevSize}) ->
- {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [KV], []),
- ?assert(couch_btree:size(BtAcc2) > PrevSize),
- {BtAcc2, couch_btree:size(BtAcc2)}
- end, {Btree, couch_btree:size(Btree)}, KeyValues),
- {
- "Should continuously add key-values to btree",
- [
- should_produce_valid_btree(Btree1, KeyValues),
- should_not_be_empty(Btree1)
- ]
- }.
-
-should_continuously_remove_keys(KeyValues, {_, Btree}) ->
- {ok, Btree1} = couch_btree:add_remove(Btree, KeyValues, []),
- {Btree2, _} = lists:foldl(
- fun({K, _}, {BtAcc, PrevSize}) ->
- {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [], [K]),
- ?assert(couch_btree:size(BtAcc2) < PrevSize),
- {BtAcc2, couch_btree:size(BtAcc2)}
- end, {Btree1, couch_btree:size(Btree1)}, KeyValues),
- {
- "Should continuously remove keys from btree",
- [
- should_produce_valid_btree(Btree2, []),
- should_be_empty(Btree2)
- ]
- }.
-
-should_insert_keys_in_reversed_order(KeyValues, {_, Btree}) ->
- KeyValuesRev = lists:reverse(KeyValues),
- {Btree1, _} = lists:foldl(
- fun(KV, {BtAcc, PrevSize}) ->
- {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [KV], []),
- ?assert(couch_btree:size(BtAcc2) > PrevSize),
- {BtAcc2, couch_btree:size(BtAcc2)}
- end, {Btree, couch_btree:size(Btree)}, KeyValuesRev),
- should_produce_valid_btree(Btree1, KeyValues).
-
-should_add_every_odd_key_remove_every_even(KeyValues, {_, Btree}) ->
- {ok, Btree1} = couch_btree:add_remove(Btree, KeyValues, []),
- {_, Rem2Keys0, Rem2Keys1} = lists:foldl(fun(X, {Count, Left, Right}) ->
- case Count rem 2 == 0 of
- true -> {Count + 1, [X | Left], Right};
- false -> {Count + 1, Left, [X | Right]}
- end
- end, {0, [], []}, KeyValues),
- ?_assert(test_add_remove(Btree1, Rem2Keys0, Rem2Keys1)).
-
-should_add_every_even_key_remove_every_old(KeyValues, {_, Btree}) ->
- {ok, Btree1} = couch_btree:add_remove(Btree, KeyValues, []),
- {_, Rem2Keys0, Rem2Keys1} = lists:foldl(fun(X, {Count, Left, Right}) ->
- case Count rem 2 == 0 of
- true -> {Count + 1, [X | Left], Right};
- false -> {Count + 1, Left, [X | Right]}
- end
- end, {0, [], []}, KeyValues),
- ?_assert(test_add_remove(Btree1, Rem2Keys1, Rem2Keys0)).
-
-
-should_reduce_without_specified_direction({_, Btree}) ->
- ?_assertMatch(
- {ok, [{{"odd", _}, ?ROWS div 2}, {{"even", _}, ?ROWS div 2}]},
- fold_reduce(Btree, [])).
-
-should_reduce_forward({_, Btree}) ->
- ?_assertMatch(
- {ok, [{{"odd", _}, ?ROWS div 2}, {{"even", _}, ?ROWS div 2}]},
- fold_reduce(Btree, [{dir, fwd}])).
-
-should_reduce_backward({_, Btree}) ->
- ?_assertMatch(
- {ok, [{{"even", _}, ?ROWS div 2}, {{"odd", _}, ?ROWS div 2}]},
- fold_reduce(Btree, [{dir, rev}])).
-
-should_reduce_whole_range(fwd, {_, Btree}) ->
- {SK, EK} = {{"even", 0}, {"odd", ?ROWS - 1}},
- [
- {
- "include endkey",
- ?_assertMatch(
- {ok, [{{"odd", 1}, ?ROWS div 2},
- {{"even", 2}, ?ROWS div 2}]},
- fold_reduce(Btree, [{dir, fwd},
- {start_key, SK},
- {end_key, EK}]))
- },
- {
- "exclude endkey",
- ?_assertMatch(
- {ok, [{{"odd", 1}, (?ROWS div 2) - 1},
- {{"even", 2}, ?ROWS div 2}]},
- fold_reduce(Btree, [{dir, fwd},
- {start_key, SK},
- {end_key_gt, EK}]))
- }
- ];
-should_reduce_whole_range(rev, {_, Btree}) ->
- {SK, EK} = {{"odd", ?ROWS - 1}, {"even", 2}},
- [
- {
- "include endkey",
- ?_assertMatch(
- {ok, [{{"even", ?ROWS}, ?ROWS div 2},
- {{"odd", ?ROWS - 1}, ?ROWS div 2}]},
- fold_reduce(Btree, [{dir, rev},
- {start_key, SK},
- {end_key, EK}]))
- },
- {
- "exclude endkey",
- ?_assertMatch(
- {ok, [{{"even", ?ROWS}, (?ROWS div 2) - 1},
- {{"odd", ?ROWS - 1}, ?ROWS div 2}]},
- fold_reduce(Btree, [{dir, rev},
- {start_key, SK},
- {end_key_gt, EK}]))
- }
- ].
-
-should_reduce_first_half(fwd, {_, Btree}) ->
- {SK, EK} = {{"even", 0}, {"odd", (?ROWS div 2) - 1}},
- [
- {
- "include endkey",
- ?_assertMatch(
- {ok, [{{"odd", 1}, ?ROWS div 4},
- {{"even", 2}, ?ROWS div 2}]},
- fold_reduce(Btree, [{dir, fwd},
- {start_key, SK}, {end_key, EK}]))
- },
- {
- "exclude endkey",
- ?_assertMatch(
- {ok, [{{"odd", 1}, (?ROWS div 4) - 1},
- {{"even", 2}, ?ROWS div 2}]},
- fold_reduce(Btree, [{dir, fwd},
- {start_key, SK},
- {end_key_gt, EK}]))
- }
- ];
-should_reduce_first_half(rev, {_, Btree}) ->
- {SK, EK} = {{"odd", ?ROWS - 1}, {"even", ?ROWS div 2}},
- [
- {
- "include endkey",
- ?_assertMatch(
- {ok, [{{"even", ?ROWS}, (?ROWS div 4) + 1},
- {{"odd", ?ROWS - 1}, ?ROWS div 2}]},
- fold_reduce(Btree, [{dir, rev},
- {start_key, SK},
- {end_key, EK}]))
- },
- {
- "exclude endkey",
- ?_assertMatch(
- {ok, [{{"even", ?ROWS}, ?ROWS div 4},
- {{"odd", ?ROWS - 1}, ?ROWS div 2}]},
- fold_reduce(Btree, [{dir, rev},
- {start_key, SK},
- {end_key_gt, EK}]))
- }
- ].
-
-should_reduce_second_half(fwd, {_, Btree}) ->
- {SK, EK} = {{"even", ?ROWS div 2}, {"odd", ?ROWS - 1}},
- [
- {
- "include endkey",
- ?_assertMatch(
- {ok, [{{"odd", 1}, ?ROWS div 2},
- {{"even", ?ROWS div 2}, (?ROWS div 4) + 1}]},
- fold_reduce(Btree, [{dir, fwd},
- {start_key, SK},
- {end_key, EK}]))
- },
- {
- "exclude endkey",
- ?_assertMatch(
- {ok, [{{"odd", 1}, (?ROWS div 2) - 1},
- {{"even", ?ROWS div 2}, (?ROWS div 4) + 1}]},
- fold_reduce(Btree, [{dir, fwd},
- {start_key, SK},
- {end_key_gt, EK}]))
- }
- ];
-should_reduce_second_half(rev, {_, Btree}) ->
- {SK, EK} = {{"odd", (?ROWS div 2) + 1}, {"even", 2}},
- [
- {
- "include endkey",
- ?_assertMatch(
- {ok, [{{"even", ?ROWS}, ?ROWS div 2},
- {{"odd", (?ROWS div 2) + 1}, (?ROWS div 4) + 1}]},
- fold_reduce(Btree, [{dir, rev},
- {start_key, SK},
- {end_key, EK}]))
- },
- {
- "exclude endkey",
- ?_assertMatch(
- {ok, [{{"even", ?ROWS}, (?ROWS div 2) - 1},
- {{"odd", (?ROWS div 2) + 1}, (?ROWS div 4) + 1}]},
- fold_reduce(Btree, [{dir, rev},
- {start_key, SK},
- {end_key_gt, EK}]))
- }
- ].
-
-should_produce_valid_btree(Btree, KeyValues) ->
- ?_assert(test_btree(Btree, KeyValues)).
-
-should_be_empty(Btree) ->
- ?_assertEqual(couch_btree:size(Btree), 0).
-
-should_not_be_empty(Btree) ->
- ?_assert(couch_btree:size(Btree) > 0).
-
-fold_reduce(Btree, Opts) ->
- GroupFun = fun({K1, _}, {K2, _}) ->
- K1 == K2
- end,
- FoldFun = fun(GroupedKey, Unreduced, Acc) ->
- {ok, [{GroupedKey, couch_btree:final_reduce(Btree, Unreduced)} | Acc]}
- end,
- couch_btree:fold_reduce(Btree, FoldFun, [],
- [{key_group_fun, GroupFun}] ++ Opts).
-
-
-keys(KVs) ->
- [K || {K, _} <- KVs].
-
-reduce_fun(reduce, KVs) ->
- length(KVs);
-reduce_fun(rereduce, Reds) ->
- lists:sum(Reds).
-
-
-shuffle(List) ->
- randomize(round(math:log(length(List)) + 0.5), List).
-
-randomize(1, List) ->
- randomize(List);
-randomize(T, List) ->
- lists:foldl(
- fun(_E, Acc) ->
- randomize(Acc)
- end, randomize(List), lists:seq(1, (T - 1))).
-
-randomize(List) ->
- D = lists:map(fun(A) -> {random:uniform(), A} end, List),
- {_, D1} = lists:unzip(lists:keysort(1, D)),
- D1.
-
-test_btree(Btree, KeyValues) ->
- ok = test_key_access(Btree, KeyValues),
- ok = test_lookup_access(Btree, KeyValues),
- ok = test_final_reductions(Btree, KeyValues),
- ok = test_traversal_callbacks(Btree, KeyValues),
- true.
-
-test_add_remove(Btree, OutKeyValues, RemainingKeyValues) ->
- Btree2 = lists:foldl(
- fun({K, _}, BtAcc) ->
- {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [], [K]),
- BtAcc2
- end, Btree, OutKeyValues),
- true = test_btree(Btree2, RemainingKeyValues),
-
- Btree3 = lists:foldl(
- fun(KV, BtAcc) ->
- {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [KV], []),
- BtAcc2
- end, Btree2, OutKeyValues),
- true = test_btree(Btree3, OutKeyValues ++ RemainingKeyValues).
-
-test_key_access(Btree, List) ->
- FoldFun = fun(Element, {[HAcc|TAcc], Count}) ->
- case Element == HAcc of
- true -> {ok, {TAcc, Count + 1}};
- _ -> {ok, {TAcc, Count + 1}}
- end
- end,
- Length = length(List),
- Sorted = lists:sort(List),
- {ok, _, {[], Length}} = couch_btree:foldl(Btree, FoldFun, {Sorted, 0}),
- {ok, _, {[], Length}} = couch_btree:fold(Btree, FoldFun,
- {Sorted, 0}, [{dir, rev}]),
- ok.
-
-test_lookup_access(Btree, KeyValues) ->
- FoldFun = fun({Key, Value}, {Key, Value}) -> {stop, true} end,
- lists:foreach(
- fun({Key, Value}) ->
- [{ok, {Key, Value}}] = couch_btree:lookup(Btree, [Key]),
- {ok, _, true} = couch_btree:foldl(Btree, FoldFun,
- {Key, Value}, [{start_key, Key}])
- end, KeyValues).
-
-test_final_reductions(Btree, KeyValues) ->
- KVLen = length(KeyValues),
- FoldLFun = fun(_X, LeadingReds, Acc) ->
- CountToStart = KVLen div 3 + Acc,
- CountToStart = couch_btree:final_reduce(Btree, LeadingReds),
- {ok, Acc + 1}
- end,
- FoldRFun = fun(_X, LeadingReds, Acc) ->
- CountToEnd = KVLen - KVLen div 3 + Acc,
- CountToEnd = couch_btree:final_reduce(Btree, LeadingReds),
- {ok, Acc + 1}
- end,
- {LStartKey, _} = case KVLen of
- 0 -> {nil, nil};
- _ -> lists:nth(KVLen div 3 + 1, lists:sort(KeyValues))
- end,
- {RStartKey, _} = case KVLen of
- 0 -> {nil, nil};
- _ -> lists:nth(KVLen div 3, lists:sort(KeyValues))
- end,
- {ok, _, FoldLRed} = couch_btree:foldl(Btree, FoldLFun, 0,
- [{start_key, LStartKey}]),
- {ok, _, FoldRRed} = couch_btree:fold(Btree, FoldRFun, 0,
- [{dir, rev}, {start_key, RStartKey}]),
- KVLen = FoldLRed + FoldRRed,
- ok.
-
-test_traversal_callbacks(Btree, _KeyValues) ->
- FoldFun = fun
- (visit, _GroupedKey, _Unreduced, Acc) ->
- {ok, Acc andalso false};
- (traverse, _LK, _Red, Acc) ->
- {skip, Acc andalso true}
- end,
- % With 250 items the root is a kp. Always skipping should reduce to true.
- {ok, _, true} = couch_btree:fold(Btree, FoldFun, true, [{dir, fwd}]),
- ok.
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_changes_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_changes_tests.erl b/test/couchdb/couch_changes_tests.erl
deleted file mode 100644
index a129ba2..0000000
--- a/test/couchdb/couch_changes_tests.erl
+++ /dev/null
@@ -1,612 +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(couch_changes_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(ADMIN_USER, {user_ctx, #user_ctx{roles = [<<"_admin">>]}}).
--define(TIMEOUT, 3000).
--define(TEST_TIMEOUT, 10000).
-
--record(row, {
- id,
- seq,
- deleted = false
-}).
-
-
-start() ->
- {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
- Pid.
-
-stop(Pid) ->
- erlang:monitor(process, Pid),
- couch_server_sup:stop(),
- receive
- {'DOWN', _, _, Pid, _} ->
- ok
- after ?TIMEOUT ->
- throw({timeout, server_stop})
- end.
-
-setup() ->
- DbName = ?tempdb(),
- {ok, Db} = create_db(DbName),
- Revs = [R || {ok, R} <- [
- save_doc(Db, {[{<<"_id">>, <<"doc1">>}]}),
- save_doc(Db, {[{<<"_id">>, <<"doc2">>}]}),
- save_doc(Db, {[{<<"_id">>, <<"doc3">>}]}),
- save_doc(Db, {[{<<"_id">>, <<"doc4">>}]}),
- save_doc(Db, {[{<<"_id">>, <<"doc5">>}]})
- ]],
- Rev = lists:nth(3, Revs),
- {ok, Rev1} = save_doc(Db, {[{<<"_id">>, <<"doc3">>}, {<<"_rev">>, Rev}]}),
- Revs1 = Revs ++ [Rev1],
- Revs2 = Revs1 ++ [R || {ok, R} <- [
- save_doc(Db, {[{<<"_id">>, <<"doc6">>}]}),
- save_doc(Db, {[{<<"_id">>, <<"_design/foo">>}]}),
- save_doc(Db, {[{<<"_id">>, <<"doc7">>}]}),
- save_doc(Db, {[{<<"_id">>, <<"doc8">>}]})
- ]],
- {DbName, list_to_tuple(Revs2)}.
-
-teardown({DbName, _}) ->
- delete_db(DbName),
- ok.
-
-
-changes_test_() ->
- {
- "Changes feeed",
- {
- setup,
- fun start/0, fun stop/1,
- [
- filter_by_doc_id(),
- filter_by_design(),
- continuous_feed(),
- filter_by_custom_function()
- ]
- }
- }.
-
-filter_by_doc_id() ->
- {
- "Filter _doc_id",
- {
- foreach,
- fun setup/0, fun teardown/1,
- [
- fun should_filter_by_specific_doc_ids/1,
- fun should_filter_by_specific_doc_ids_descending/1,
- fun should_filter_by_specific_doc_ids_with_since/1,
- fun should_filter_by_specific_doc_ids_no_result/1,
- fun should_handle_deleted_docs/1
- ]
- }
- }.
-
-filter_by_design() ->
- {
- "Filter _design",
- {
- foreach,
- fun setup/0, fun teardown/1,
- [
- fun should_emit_only_design_documents/1
- ]
- }
- }.
-
-filter_by_custom_function() ->
- {
- "Filter function",
- {
- foreach,
- fun setup/0, fun teardown/1,
- [
- fun should_receive_heartbeats/1
- ]
- }
- }.
-
-continuous_feed() ->
- {
- "Continuous Feed",
- {
- foreach,
- fun setup/0, fun teardown/1,
- [
- fun should_filter_continuous_feed_by_specific_doc_ids/1
- ]
- }
- }.
-
-
-should_filter_by_specific_doc_ids({DbName, _}) ->
- ?_test(
- begin
- ChangesArgs = #changes_args{
- filter = "_doc_ids"
- },
- DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
- Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
- Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-
- {Rows, LastSeq} = wait_finished(Consumer),
- {ok, Db} = couch_db:open_int(DbName, []),
- UpSeq = couch_db:get_update_seq(Db),
- couch_db:close(Db),
- stop_consumer(Consumer),
-
- ?assertEqual(2, length(Rows)),
- [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
- ?assertEqual(<<"doc4">>, Id1),
- ?assertEqual(4, Seq1),
- ?assertEqual(<<"doc3">>, Id2),
- ?assertEqual(6, Seq2),
- ?assertEqual(UpSeq, LastSeq)
- end).
-
-should_filter_by_specific_doc_ids_descending({DbName, _}) ->
- ?_test(
- begin
- ChangesArgs = #changes_args{
- filter = "_doc_ids",
- dir = rev
- },
- DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
- Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
- Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-
- {Rows, LastSeq} = wait_finished(Consumer),
- {ok, Db} = couch_db:open_int(DbName, []),
- couch_db:close(Db),
- stop_consumer(Consumer),
-
- ?assertEqual(2, length(Rows)),
- [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
- ?assertEqual(<<"doc3">>, Id1),
- ?assertEqual(6, Seq1),
- ?assertEqual(<<"doc4">>, Id2),
- ?assertEqual(4, Seq2),
- ?assertEqual(4, LastSeq)
- end).
-
-should_filter_by_specific_doc_ids_with_since({DbName, _}) ->
- ?_test(
- begin
- ChangesArgs = #changes_args{
- filter = "_doc_ids",
- since = 5
- },
- DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
- Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
- Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-
- {Rows, LastSeq} = wait_finished(Consumer),
- {ok, Db} = couch_db:open_int(DbName, []),
- UpSeq = couch_db:get_update_seq(Db),
- couch_db:close(Db),
- stop_consumer(Consumer),
-
- ?assertEqual(1, length(Rows)),
- [#row{seq = Seq1, id = Id1}] = Rows,
- ?assertEqual(<<"doc3">>, Id1),
- ?assertEqual(6, Seq1),
- ?assertEqual(UpSeq, LastSeq)
- end).
-
-should_filter_by_specific_doc_ids_no_result({DbName, _}) ->
- ?_test(
- begin
- ChangesArgs = #changes_args{
- filter = "_doc_ids",
- since = 6
- },
- DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
- Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
- Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-
- {Rows, LastSeq} = wait_finished(Consumer),
- {ok, Db} = couch_db:open_int(DbName, []),
- UpSeq = couch_db:get_update_seq(Db),
- couch_db:close(Db),
- stop_consumer(Consumer),
-
- ?assertEqual(0, length(Rows)),
- ?assertEqual(UpSeq, LastSeq)
- end).
-
-should_handle_deleted_docs({DbName, Revs}) ->
- ?_test(
- begin
- Rev3_2 = element(6, Revs),
- {ok, Db} = couch_db:open_int(DbName, []),
- {ok, _} = save_doc(
- Db,
- {[{<<"_id">>, <<"doc3">>},
- {<<"_deleted">>, true},
- {<<"_rev">>, Rev3_2}]}),
-
- ChangesArgs = #changes_args{
- filter = "_doc_ids",
- since = 9
- },
- DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
- Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
- Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-
- {Rows, LastSeq} = wait_finished(Consumer),
- couch_db:close(Db),
- stop_consumer(Consumer),
-
- ?assertEqual(1, length(Rows)),
- ?assertMatch(
- [#row{seq = LastSeq, id = <<"doc3">>, deleted = true}],
- Rows
- ),
- ?assertEqual(11, LastSeq)
- end).
-
-should_filter_continuous_feed_by_specific_doc_ids({DbName, Revs}) ->
- ?_test(
- begin
- {ok, Db} = couch_db:open_int(DbName, []),
- ChangesArgs = #changes_args{
- filter = "_doc_ids",
- feed = "continuous"
- },
- DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
- Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
- Consumer = spawn_consumer(DbName, ChangesArgs, Req),
- pause(Consumer),
-
- Rows = get_rows(Consumer),
- ?assertEqual(2, length(Rows)),
- [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
- ?assertEqual(<<"doc4">>, Id1),
- ?assertEqual(4, Seq1),
- ?assertEqual(<<"doc3">>, Id2),
- ?assertEqual(6, Seq2),
-
- clear_rows(Consumer),
- {ok, _Rev9} = save_doc(Db, {[{<<"_id">>, <<"doc9">>}]}),
- {ok, _Rev10} = save_doc(Db, {[{<<"_id">>, <<"doc10">>}]}),
- unpause(Consumer),
- pause(Consumer),
- ?assertEqual([], get_rows(Consumer)),
-
- Rev4 = element(4, Revs),
- Rev3_2 = element(6, Revs),
- {ok, Rev4_2} = save_doc(Db, {[{<<"_id">>, <<"doc4">>},
- {<<"_rev">>, Rev4}]}),
- {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc11">>}]}),
- {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc4">>},
- {<<"_rev">>, Rev4_2}]}),
- {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc12">>}]}),
- {ok, Rev3_3} = save_doc(Db, {[{<<"_id">>, <<"doc3">>},
- {<<"_rev">>, Rev3_2}]}),
- unpause(Consumer),
- pause(Consumer),
-
- NewRows = get_rows(Consumer),
- ?assertEqual(2, length(NewRows)),
- [Row14, Row16] = NewRows,
- ?assertEqual(<<"doc4">>, Row14#row.id),
- ?assertEqual(15, Row14#row.seq),
- ?assertEqual(<<"doc3">>, Row16#row.id),
- ?assertEqual(17, Row16#row.seq),
-
- clear_rows(Consumer),
- {ok, _Rev3_4} = save_doc(Db, {[{<<"_id">>, <<"doc3">>},
- {<<"_rev">>, Rev3_3}]}),
- unpause(Consumer),
- pause(Consumer),
-
- FinalRows = get_rows(Consumer),
-
- unpause(Consumer),
- stop_consumer(Consumer),
-
- ?assertMatch([#row{seq = 18, id = <<"doc3">>}], FinalRows)
- end).
-
-should_emit_only_design_documents({DbName, Revs}) ->
- ?_test(
- begin
- ChangesArgs = #changes_args{
- filter = "_design"
- },
- Consumer = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
-
- {Rows, LastSeq} = wait_finished(Consumer),
- {ok, Db} = couch_db:open_int(DbName, []),
- UpSeq = couch_db:get_update_seq(Db),
- couch_db:close(Db),
-
- ?assertEqual(1, length(Rows)),
- ?assertEqual(UpSeq, LastSeq),
- ?assertEqual([#row{seq = 8, id = <<"_design/foo">>}], Rows),
-
- stop_consumer(Consumer),
-
- {ok, Db2} = couch_db:open_int(DbName, [?ADMIN_USER]),
- {ok, _} = save_doc(Db2, {[{<<"_id">>, <<"_design/foo">>},
- {<<"_rev">>, element(8, Revs)},
- {<<"_deleted">>, true}]}),
-
- Consumer2 = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
-
- {Rows2, LastSeq2} = wait_finished(Consumer2),
- UpSeq2 = UpSeq + 1,
- couch_db:close(Db2),
-
- ?assertEqual(1, length(Rows2)),
- ?assertEqual(UpSeq2, LastSeq2),
- ?assertEqual([#row{seq = 11,
- id = <<"_design/foo">>,
- deleted = true}],
- Rows2)
- end).
-
-should_receive_heartbeats(_) ->
- {timeout, ?TEST_TIMEOUT div 1000,
- ?_test(
- begin
- DbName = ?tempdb(),
- Timeout = 100,
- {ok, Db} = create_db(DbName),
-
- {ok, _} = save_doc(Db, {[
- {<<"_id">>, <<"_design/filtered">>},
- {<<"language">>, <<"javascript">>},
- {<<"filters">>, {[
- {<<"foo">>, <<"function(doc) {
- return ['doc10', 'doc11', 'doc12'].indexOf(doc._id) != -1;}">>
- }]}}
- ]}),
-
- ChangesArgs = #changes_args{
- filter = "filtered/foo",
- feed = "continuous",
- timeout = 10000,
- heartbeat = 1000
- },
- Consumer = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
-
- {ok, _Rev1} = save_doc(Db, {[{<<"_id">>, <<"doc1">>}]}),
- timer:sleep(Timeout),
- {ok, _Rev2} = save_doc(Db, {[{<<"_id">>, <<"doc2">>}]}),
- timer:sleep(Timeout),
- {ok, _Rev3} = save_doc(Db, {[{<<"_id">>, <<"doc3">>}]}),
- timer:sleep(Timeout),
- {ok, _Rev4} = save_doc(Db, {[{<<"_id">>, <<"doc4">>}]}),
- timer:sleep(Timeout),
- {ok, _Rev5} = save_doc(Db, {[{<<"_id">>, <<"doc5">>}]}),
- timer:sleep(Timeout),
- {ok, _Rev6} = save_doc(Db, {[{<<"_id">>, <<"doc6">>}]}),
- timer:sleep(Timeout),
- {ok, _Rev7} = save_doc(Db, {[{<<"_id">>, <<"doc7">>}]}),
- timer:sleep(Timeout),
- {ok, _Rev8} = save_doc(Db, {[{<<"_id">>, <<"doc8">>}]}),
- timer:sleep(Timeout),
- {ok, _Rev9} = save_doc(Db, {[{<<"_id">>, <<"doc9">>}]}),
-
- Heartbeats = get_heartbeats(Consumer),
- ?assert(Heartbeats > 0),
-
- {ok, _Rev10} = save_doc(Db, {[{<<"_id">>, <<"doc10">>}]}),
- timer:sleep(Timeout),
- {ok, _Rev11} = save_doc(Db, {[{<<"_id">>, <<"doc11">>}]}),
- timer:sleep(Timeout),
- {ok, _Rev12} = save_doc(Db, {[{<<"_id">>, <<"doc12">>}]}),
-
- Heartbeats2 = get_heartbeats(Consumer),
- ?assert(Heartbeats2 > Heartbeats),
-
- Rows = get_rows(Consumer),
- ?assertEqual(3, length(Rows)),
-
- {ok, _Rev13} = save_doc(Db, {[{<<"_id">>, <<"doc13">>}]}),
- timer:sleep(Timeout),
- {ok, _Rev14} = save_doc(Db, {[{<<"_id">>, <<"doc14">>}]}),
- timer:sleep(Timeout),
-
- Heartbeats3 = get_heartbeats(Consumer),
- ?assert(Heartbeats3 > Heartbeats2)
- end)}.
-
-
-save_doc(Db, Json) ->
- Doc = couch_doc:from_json_obj(Json),
- {ok, Rev} = couch_db:update_doc(Db, Doc, []),
- {ok, couch_doc:rev_to_str(Rev)}.
-
-get_rows(Consumer) ->
- Ref = make_ref(),
- Consumer ! {get_rows, Ref},
- Resp = receive
- {rows, Ref, Rows} ->
- Rows
- after ?TIMEOUT ->
- timeout
- end,
- ?assertNotEqual(timeout, Resp),
- Resp.
-
-get_heartbeats(Consumer) ->
- Ref = make_ref(),
- Consumer ! {get_heartbeats, Ref},
- Resp = receive
- {hearthbeats, Ref, HeartBeats} ->
- HeartBeats
- after ?TIMEOUT ->
- timeout
- end,
- ?assertNotEqual(timeout, Resp),
- Resp.
-
-clear_rows(Consumer) ->
- Ref = make_ref(),
- Consumer ! {reset, Ref},
- Resp = receive
- {ok, Ref} ->
- ok
- after ?TIMEOUT ->
- timeout
- end,
- ?assertNotEqual(timeout, Resp),
- Resp.
-
-stop_consumer(Consumer) ->
- Ref = make_ref(),
- Consumer ! {stop, Ref},
- Resp = receive
- {ok, Ref} ->
- ok
- after ?TIMEOUT ->
- timeout
- end,
- ?assertNotEqual(timeout, Resp),
- Resp.
-
-pause(Consumer) ->
- Ref = make_ref(),
- Consumer ! {pause, Ref},
- Resp = receive
- {paused, Ref} ->
- ok
- after ?TIMEOUT ->
- timeout
- end,
- ?assertNotEqual(timeout, Resp),
- Resp.
-
-unpause(Consumer) ->
- Ref = make_ref(),
- Consumer ! {continue, Ref},
- Resp = receive
- {ok, Ref} ->
- ok
- after ?TIMEOUT ->
- timeout
- end,
- ?assertNotEqual(timeout, Resp),
- Resp.
-
-wait_finished(_Consumer) ->
- Resp = receive
- {consumer_finished, Rows, LastSeq} ->
- {Rows, LastSeq}
- after ?TIMEOUT ->
- timeout
- end,
- ?assertNotEqual(timeout, Resp),
- Resp.
-
-spawn_consumer(DbName, ChangesArgs0, Req) ->
- Parent = self(),
- spawn(fun() ->
- put(heartbeat_count, 0),
- Callback = fun
- ({change, {Change}, _}, _, Acc) ->
- Id = couch_util:get_value(<<"id">>, Change),
- Seq = couch_util:get_value(<<"seq">>, Change),
- Del = couch_util:get_value(<<"deleted">>, Change, false),
- [#row{id = Id, seq = Seq, deleted = Del} | Acc];
- ({stop, LastSeq}, _, Acc) ->
- Parent ! {consumer_finished, lists:reverse(Acc), LastSeq},
- stop_loop(Parent, Acc);
- (timeout, _, Acc) ->
- put(heartbeat_count, get(heartbeat_count) + 1),
- maybe_pause(Parent, Acc);
- (_, _, Acc) ->
- maybe_pause(Parent, Acc)
- end,
- {ok, Db} = couch_db:open_int(DbName, []),
- ChangesArgs = case (ChangesArgs0#changes_args.timeout =:= undefined)
- andalso (ChangesArgs0#changes_args.heartbeat =:= undefined) of
- true ->
- ChangesArgs0#changes_args{timeout = 10, heartbeat = 10};
- false ->
- ChangesArgs0
- end,
- FeedFun = couch_changes:handle_changes(ChangesArgs, Req, Db),
- try
- FeedFun({Callback, []})
- catch throw:{stop, _} ->
- ok
- end,
- catch couch_db:close(Db)
- end).
-
-maybe_pause(Parent, Acc) ->
- receive
- {get_rows, Ref} ->
- Parent ! {rows, Ref, lists:reverse(Acc)},
- maybe_pause(Parent, Acc);
- {get_heartbeats, Ref} ->
- Parent ! {hearthbeats, Ref, get(heartbeat_count)},
- maybe_pause(Parent, Acc);
- {reset, Ref} ->
- Parent ! {ok, Ref},
- maybe_pause(Parent, []);
- {pause, Ref} ->
- Parent ! {paused, Ref},
- pause_loop(Parent, Acc);
- {stop, Ref} ->
- Parent ! {ok, Ref},
- throw({stop, Acc});
- V ->
- erlang:error({assertion_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {value, V},
- {reason, "Received unexpected message"}]})
- after 0 ->
- Acc
- end.
-
-pause_loop(Parent, Acc) ->
- receive
- {stop, Ref} ->
- Parent ! {ok, Ref},
- throw({stop, Acc});
- {reset, Ref} ->
- Parent ! {ok, Ref},
- pause_loop(Parent, []);
- {continue, Ref} ->
- Parent ! {ok, Ref},
- Acc;
- {get_rows, Ref} ->
- Parent ! {rows, Ref, lists:reverse(Acc)},
- pause_loop(Parent, Acc)
- end.
-
-stop_loop(Parent, Acc) ->
- receive
- {get_rows, Ref} ->
- Parent ! {rows, Ref, lists:reverse(Acc)},
- stop_loop(Parent, Acc);
- {stop, Ref} ->
- Parent ! {ok, Ref},
- Acc
- end.
-
-create_db(DbName) ->
- couch_db:create(DbName, [?ADMIN_USER, overwrite]).
-
-delete_db(DbName) ->
- ok = couch_server:delete(DbName, [?ADMIN_USER]).
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_config_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_config_tests.erl b/test/couchdb/couch_config_tests.erl
deleted file mode 100644
index 9e9dfe7..0000000
--- a/test/couchdb/couch_config_tests.erl
+++ /dev/null
@@ -1,463 +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(couch_config_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(SHORT_TIMEOUT, 100).
--define(TIMEOUT, 1000).
-
--define(CONFIG_DEFAULT,
- filename:join([?BUILDDIR, "etc", "couchdb", "default_dev.ini"])).
--define(CONFIG_FIXTURE_1,
- filename:join([?FIXTURESDIR, "couch_config_tests_1.ini"])).
--define(CONFIG_FIXTURE_2,
- filename:join([?FIXTURESDIR, "couch_config_tests_2.ini"])).
--define(CONFIG_FIXTURE_TEMP,
- begin
- FileName = filename:join([?TEMPDIR, "couch_config_temp.ini"]),
- {ok, Fd} = file:open(FileName, write),
- ok = file:truncate(Fd),
- ok = file:close(Fd),
- FileName
- end).
-
-
-setup() ->
- setup(?CONFIG_CHAIN).
-setup({temporary, Chain}) ->
- setup(Chain);
-setup({persistent, Chain}) ->
- setup(lists:append(Chain, [?CONFIG_FIXTURE_TEMP]));
-setup(Chain) ->
- {ok, Pid} = couch_config:start_link(Chain),
- Pid.
-
-setup_empty() ->
- setup([]).
-
-setup_register() ->
- ConfigPid = setup(),
- SentinelFunc = fun() ->
- % Ping/Pong to make sure we wait for this
- % process to die
- receive
- {ping, From} ->
- From ! pong
- end
- end,
- SentinelPid = spawn(SentinelFunc),
- {ConfigPid, SentinelPid}.
-
-teardown({ConfigPid, SentinelPid}) ->
- teardown(ConfigPid),
- case process_info(SentinelPid) of
- undefined -> ok;
- _ ->
- SentinelPid ! {ping, self()},
- receive
- pong ->
- ok
- after 100 ->
- throw({timeout_error, registered_pid})
- end
- end;
-teardown(Pid) ->
- couch_config:stop(),
- erlang:monitor(process, Pid),
- receive
- {'DOWN', _, _, Pid, _} ->
- ok
- after ?TIMEOUT ->
- throw({timeout_error, config_stop})
- end.
-teardown(_, Pid) ->
- teardown(Pid).
-
-
-couch_config_test_() ->
- {
- "CouchDB config tests",
- [
- couch_config_get_tests(),
- couch_config_set_tests(),
- couch_config_del_tests(),
- config_override_tests(),
- config_persistent_changes_tests(),
- config_register_tests(),
- config_no_files_tests()
- ]
- }.
-
-couch_config_get_tests() ->
- {
- "Config get tests",
- {
- foreach,
- fun setup/0, fun teardown/1,
- [
- should_load_all_configs(),
- should_locate_daemons_section(),
- should_locate_mrview_handler(),
- should_return_undefined_atom_on_missed_section(),
- should_return_undefined_atom_on_missed_option(),
- should_return_custom_default_value_on_missed_option(),
- should_only_return_default_on_missed_option(),
- should_get_binary_option()
- ]
- }
- }.
-
-couch_config_set_tests() ->
- {
- "Config set tests",
- {
- foreach,
- fun setup/0, fun teardown/1,
- [
- should_update_option(),
- should_create_new_section(),
- should_set_binary_option()
- ]
- }
- }.
-
-couch_config_del_tests() ->
- {
- "Config deletion tests",
- {
- foreach,
- fun setup/0, fun teardown/1,
- [
- should_return_undefined_atom_after_option_deletion(),
- should_be_ok_on_deleting_unknown_options(),
- should_delete_binary_option()
- ]
- }
- }.
-
-config_override_tests() ->
- {
- "Configs overide tests",
- {
- foreachx,
- fun setup/1, fun teardown/2,
- [
- {{temporary, [?CONFIG_DEFAULT]},
- fun should_ensure_in_defaults/2},
- {{temporary, [?CONFIG_DEFAULT, ?CONFIG_FIXTURE_1]},
- fun should_override_options/2},
- {{temporary, [?CONFIG_DEFAULT, ?CONFIG_FIXTURE_2]},
- fun should_create_new_sections_on_override/2},
- {{temporary, [?CONFIG_DEFAULT, ?CONFIG_FIXTURE_1,
- ?CONFIG_FIXTURE_2]},
- fun should_win_last_in_chain/2}
- ]
- }
- }.
-
-config_persistent_changes_tests() ->
- {
- "Config persistent changes",
- {
- foreachx,
- fun setup/1, fun teardown/2,
- [
- {{persistent, [?CONFIG_DEFAULT]},
- fun should_write_changes/2},
- {{temporary, [?CONFIG_DEFAULT]},
- fun should_ensure_that_default_wasnt_modified/2},
- {{temporary, [?CONFIG_FIXTURE_TEMP]},
- fun should_ensure_that_written_to_last_config_in_chain/2}
- ]
- }
- }.
-
-config_register_tests() ->
- {
- "Config changes subscriber",
- {
- foreach,
- fun setup_register/0, fun teardown/1,
- [
- fun should_handle_port_changes/1,
- fun should_pass_persistent_flag/1,
- fun should_not_trigger_handler_on_other_options_changes/1,
- fun should_not_trigger_handler_after_related_process_death/1
- ]
- }
- }.
-
-config_no_files_tests() ->
- {
- "Test couch_config with no files",
- {
- foreach,
- fun setup_empty/0, fun teardown/1,
- [
- should_ensure_that_no_ini_files_loaded(),
- should_create_non_persistent_option(),
- should_create_persistent_option()
- ]
- }
- }.
-
-
-should_load_all_configs() ->
- ?_assert(length(couch_config:all()) > 0).
-
-should_locate_daemons_section() ->
- ?_assert(length(couch_config:get("daemons")) > 0).
-
-should_locate_mrview_handler() ->
- ?_assertEqual("{couch_mrview_http, handle_view_req}",
- couch_config:get("httpd_design_handlers", "_view")).
-
-should_return_undefined_atom_on_missed_section() ->
- ?_assertEqual(undefined,
- couch_config:get("foo", "bar")).
-
-should_return_undefined_atom_on_missed_option() ->
- ?_assertEqual(undefined,
- couch_config:get("httpd", "foo")).
-
-should_return_custom_default_value_on_missed_option() ->
- ?_assertEqual("bar",
- couch_config:get("httpd", "foo", "bar")).
-
-should_only_return_default_on_missed_option() ->
- ?_assertEqual("0",
- couch_config:get("httpd", "port", "bar")).
-
-should_get_binary_option() ->
- ?_assertEqual(<<"baz">>,
- couch_config:get(<<"foo">>, <<"bar">>, <<"baz">>)).
-
-should_update_option() ->
- ?_assertEqual("severe",
- begin
- ok = couch_config:set("log", "level", "severe", false),
- couch_config:get("log", "level")
- end).
-
-should_create_new_section() ->
- ?_assertEqual("bang",
- begin
- undefined = couch_config:get("new_section", "bizzle"),
- ok = couch_config:set("new_section", "bizzle", "bang", false),
- couch_config:get("new_section", "bizzle")
- end).
-
-should_set_binary_option() ->
- ?_assertEqual(<<"baz">>,
- begin
- ok = couch_config:set(<<"foo">>, <<"bar">>, <<"baz">>, false),
- couch_config:get(<<"foo">>, <<"bar">>)
- end).
-
-should_return_undefined_atom_after_option_deletion() ->
- ?_assertEqual(undefined,
- begin
- ok = couch_config:delete("log", "level", false),
- couch_config:get("log", "level")
- end).
-
-should_be_ok_on_deleting_unknown_options() ->
- ?_assertEqual(ok, couch_config:delete("zoo", "boo", false)).
-
-should_delete_binary_option() ->
- ?_assertEqual(undefined,
- begin
- ok = couch_config:set(<<"foo">>, <<"bar">>, <<"baz">>, false),
- ok = couch_config:delete(<<"foo">>, <<"bar">>, false),
- couch_config:get(<<"foo">>, <<"bar">>)
- end).
-
-should_ensure_in_defaults(_, _) ->
- ?_test(begin
- ?assertEqual("100",
- couch_config:get("couchdb", "max_dbs_open")),
- ?assertEqual("5984",
- couch_config:get("httpd", "port")),
- ?assertEqual(undefined,
- couch_config:get("fizbang", "unicode"))
- end).
-
-should_override_options(_, _) ->
- ?_test(begin
- ?assertEqual("10",
- couch_config:get("couchdb", "max_dbs_open")),
- ?assertEqual("4895",
- couch_config:get("httpd", "port"))
- end).
-
-should_create_new_sections_on_override(_, _) ->
- ?_test(begin
- ?assertEqual("80",
- couch_config:get("httpd", "port")),
- ?assertEqual("normalized",
- couch_config:get("fizbang", "unicode"))
- end).
-
-should_win_last_in_chain(_, _) ->
- ?_assertEqual("80", couch_config:get("httpd", "port")).
-
-should_write_changes(_, _) ->
- ?_test(begin
- ?assertEqual("5984",
- couch_config:get("httpd", "port")),
- ?assertEqual(ok,
- couch_config:set("httpd", "port", "8080")),
- ?assertEqual("8080",
- couch_config:get("httpd", "port")),
- ?assertEqual(ok,
- couch_config:delete("httpd", "bind_address", "8080")),
- ?assertEqual(undefined,
- couch_config:get("httpd", "bind_address"))
- end).
-
-should_ensure_that_default_wasnt_modified(_, _) ->
- ?_test(begin
- ?assertEqual("5984",
- couch_config:get("httpd", "port")),
- ?assertEqual("127.0.0.1",
- couch_config:get("httpd", "bind_address"))
- end).
-
-should_ensure_that_written_to_last_config_in_chain(_, _) ->
- ?_test(begin
- ?assertEqual("8080",
- couch_config:get("httpd", "port")),
- ?assertEqual(undefined,
- couch_config:get("httpd", "bind_address"))
- end).
-
-should_handle_port_changes({_, SentinelPid}) ->
- ?_assert(begin
- MainProc = self(),
- Port = "8080",
-
- couch_config:register(
- fun("httpd", "port", Value) ->
- % couch_config catches every error raised from handler
- % so it's not possible to just assert on wrong value.
- % We have to return the result as message
- MainProc ! (Value =:= Port)
- end,
- SentinelPid
- ),
- ok = couch_config:set("httpd", "port", Port, false),
-
- receive
- R ->
- R
- after ?TIMEOUT ->
- erlang:error({assertion_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {reason, "Timeout"}]})
- end
- end).
-
-should_pass_persistent_flag({_, SentinelPid}) ->
- ?_assert(begin
- MainProc = self(),
-
- couch_config:register(
- fun("httpd", "port", _, Persist) ->
- % couch_config catches every error raised from handler
- % so it's not possible to just assert on wrong value.
- % We have to return the result as message
- MainProc ! Persist
- end,
- SentinelPid
- ),
- ok = couch_config:set("httpd", "port", "8080", false),
-
- receive
- false ->
- true
- after ?SHORT_TIMEOUT ->
- false
- end
- end).
-
-should_not_trigger_handler_on_other_options_changes({_, SentinelPid}) ->
- ?_assert(begin
- MainProc = self(),
-
- couch_config:register(
- fun("httpd", "port", _) ->
- MainProc ! ok
- end,
- SentinelPid
- ),
- ok = couch_config:set("httpd", "bind_address", "0.0.0.0", false),
-
- receive
- ok ->
- false
- after ?SHORT_TIMEOUT ->
- true
- end
- end).
-
-should_not_trigger_handler_after_related_process_death({_, SentinelPid}) ->
- ?_assert(begin
- MainProc = self(),
-
- couch_config:register(
- fun("httpd", "port", _) ->
- MainProc ! ok
- end,
- SentinelPid
- ),
-
- SentinelPid ! {ping, MainProc},
- receive
- pong ->
- ok
- after ?SHORT_TIMEOUT ->
- erlang:error({assertion_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {reason, "Timeout"}]})
- end,
-
- ok = couch_config:set("httpd", "port", "12345", false),
-
- receive
- ok ->
- false
- after ?SHORT_TIMEOUT ->
- true
- end
- end).
-
-should_ensure_that_no_ini_files_loaded() ->
- ?_assertEqual(0, length(couch_config:all())).
-
-should_create_non_persistent_option() ->
- ?_assertEqual("80",
- begin
- ok = couch_config:set("httpd", "port", "80", false),
- couch_config:get("httpd", "port")
- end).
-
-should_create_persistent_option() ->
- ?_assertEqual("127.0.0.1",
- begin
- ok = couch_config:set("httpd", "bind_address", "127.0.0.1"),
- couch_config:get("httpd", "bind_address")
- end).
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_db_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_db_tests.erl b/test/couchdb/couch_db_tests.erl
deleted file mode 100644
index 3089714..0000000
--- a/test/couchdb/couch_db_tests.erl
+++ /dev/null
@@ -1,114 +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(couch_db_tests).
-
--include("couch_eunit.hrl").
-
--define(TIMEOUT, 120).
-
-
-setup() ->
- {ok, _} = couch_server_sup:start_link(?CONFIG_CHAIN),
- couch_config:set("log", "include_sasl", "false", false),
- ok.
-
-teardown(_) ->
- couch_server_sup:stop().
-
-
-create_delete_db_test_()->
- {
- "Database create/delete tests",
- {
- setup,
- fun setup/0, fun teardown/1,
- fun(_) ->
- [should_create_db(),
- should_delete_db(),
- should_create_multiple_dbs(),
- should_delete_multiple_dbs(),
- should_create_delete_database_continuously()]
- end
- }
- }.
-
-
-should_create_db() ->
- DbName = ?tempdb(),
- {ok, Db} = couch_db:create(DbName, []),
- ok = couch_db:close(Db),
- {ok, AllDbs} = couch_server:all_databases(),
- ?_assert(lists:member(DbName, AllDbs)).
-
-should_delete_db() ->
- DbName = ?tempdb(),
- couch_db:create(DbName, []),
- couch_server:delete(DbName, []),
- {ok, AllDbs} = couch_server:all_databases(),
- ?_assertNot(lists:member(DbName, AllDbs)).
-
-should_create_multiple_dbs() ->
- gen_server:call(couch_server, {set_max_dbs_open, 3}),
-
- DbNames = [?tempdb() || _ <- lists:seq(1, 6)],
- lists:foreach(fun(DbName) ->
- {ok, Db} = couch_db:create(DbName, []),
- ok = couch_db:close(Db)
- end, DbNames),
-
- {ok, AllDbs} = couch_server:all_databases(),
- NumCreated = lists:foldl(fun(DbName, Acc) ->
- ?assert(lists:member(DbName, AllDbs)),
- Acc+1
- end, 0, DbNames),
-
- ?_assertEqual(NumCreated, 6).
-
-should_delete_multiple_dbs() ->
- DbNames = [?tempdb() || _ <- lists:seq(1, 6)],
- lists:foreach(fun(DbName) ->
- {ok, Db} = couch_db:create(DbName, []),
- ok = couch_db:close(Db)
- end, DbNames),
-
- lists:foreach(fun(DbName) ->
- ok = couch_server:delete(DbName, [])
- end, DbNames),
-
- {ok, AllDbs} = couch_server:all_databases(),
- NumDeleted = lists:foldl(fun(DbName, Acc) ->
- ?assertNot(lists:member(DbName, AllDbs)),
- Acc + 1
- end, 0, DbNames),
-
- ?_assertEqual(NumDeleted, 6).
-
-should_create_delete_database_continuously() ->
- DbName = ?tempdb(),
- {ok, Db} = couch_db:create(DbName, []),
- couch_db:close(Db),
- [{timeout, ?TIMEOUT, {integer_to_list(N) ++ " times",
- ?_assert(loop(DbName, N))}}
- || N <- [10, 100, 1000]].
-
-loop(_, 0) ->
- true;
-loop(DbName, N) ->
- ok = cycle(DbName),
- loop(DbName, N - 1).
-
-cycle(DbName) ->
- ok = couch_server:delete(DbName, []),
- {ok, Db} = couch_db:create(DbName, []),
- couch_db:close(Db),
- ok.
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_doc_json_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_doc_json_tests.erl b/test/couchdb/couch_doc_json_tests.erl
deleted file mode 100644
index 1592b6b..0000000
--- a/test/couchdb/couch_doc_json_tests.erl
+++ /dev/null
@@ -1,391 +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(couch_doc_json_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
-
-setup() ->
- couch_config:start_link(?CONFIG_CHAIN),
- couch_config:set("attachments", "compression_level", "0", false),
- ok.
-
-teardown(_) ->
- couch_config:stop().
-
-
-json_doc_test_() ->
- {
- setup,
- fun setup/0, fun teardown/1,
- [
- {
- "Document from JSON",
- [
- from_json_success_cases(),
- from_json_error_cases()
- ]
- },
- {
- "Document to JSON",
- [
- to_json_success_cases()
- ]
- }
- ]
- }.
-
-from_json_success_cases() ->
- Cases = [
- {
- {[]},
- #doc{},
- "Return an empty document for an empty JSON object."
- },
- {
- {[{<<"_id">>, <<"zing!">>}]},
- #doc{id = <<"zing!">>},
- "Parses document ids."
- },
- {
- {[{<<"_id">>, <<"_design/foo">>}]},
- #doc{id = <<"_design/foo">>},
- "_design/document ids."
- },
- {
- {[{<<"_id">>, <<"_local/bam">>}]},
- #doc{id = <<"_local/bam">>},
- "_local/document ids."
- },
- {
- {[{<<"_rev">>, <<"4-230234">>}]},
- #doc{revs = {4, [<<"230234">>]}},
- "_rev stored in revs."
- },
- {
- {[{<<"soap">>, 35}]},
- #doc{body = {[{<<"soap">>, 35}]}},
- "Non underscore prefixed fields stored in body."
- },
- {
- {[{<<"_attachments">>, {[
- {<<"my_attachment.fu">>, {[
- {<<"stub">>, true},
- {<<"content_type">>, <<"application/awesome">>},
- {<<"length">>, 45}
- ]}},
- {<<"noahs_private_key.gpg">>, {[
- {<<"data">>, <<"SSBoYXZlIGEgcGV0IGZpc2gh">>},
- {<<"content_type">>, <<"application/pgp-signature">>}
- ]}}
- ]}}]},
- #doc{atts = [
- #att{
- name = <<"my_attachment.fu">>,
- data = stub,
- type = <<"application/awesome">>,
- att_len = 45,
- disk_len = 45,
- revpos = nil
- },
- #att{
- name = <<"noahs_private_key.gpg">>,
- data = <<"I have a pet fish!">>,
- type = <<"application/pgp-signature">>,
- att_len = 18,
- disk_len = 18,
- revpos = 0
- }
- ]},
- "Attachments are parsed correctly."
- },
- {
- {[{<<"_deleted">>, true}]},
- #doc{deleted = true},
- "_deleted controls the deleted field."
- },
- {
- {[{<<"_deleted">>, false}]},
- #doc{},
- "{\"_deleted\": false} is ok."
- },
- {
- {[
- {<<"_revisions">>,
- {[{<<"start">>, 4},
- {<<"ids">>, [<<"foo1">>, <<"phi3">>, <<"omega">>]}]}},
- {<<"_rev">>, <<"6-something">>}
- ]},
- #doc{revs = {4, [<<"foo1">>, <<"phi3">>, <<"omega">>]}},
- "_revisions attribute are preferred to _rev."
- },
- {
- {[{<<"_revs_info">>, dropping}]},
- #doc{},
- "Drops _revs_info."
- },
- {
- {[{<<"_local_seq">>, dropping}]},
- #doc{},
- "Drops _local_seq."
- },
- {
- {[{<<"_conflicts">>, dropping}]},
- #doc{},
- "Drops _conflicts."
- },
- {
- {[{<<"_deleted_conflicts">>, dropping}]},
- #doc{},
- "Drops _deleted_conflicts."
- }
- ],
- lists:map(
- fun({EJson, Expect, Msg}) ->
- {Msg, ?_assertMatch(Expect, couch_doc:from_json_obj(EJson))}
- end,
- Cases).
-
-from_json_error_cases() ->
- Cases = [
- {
- [],
- {bad_request, "Document must be a JSON object"},
- "arrays are invalid"
- },
- {
- 4,
- {bad_request, "Document must be a JSON object"},
- "integers are invalid"
- },
- {
- true,
- {bad_request, "Document must be a JSON object"},
- "literals are invalid"
- },
- {
- {[{<<"_id">>, {[{<<"foo">>, 5}]}}]},
- {bad_request, <<"Document id must be a string">>},
- "Document id must be a string."
- },
- {
- {[{<<"_id">>, <<"_random">>}]},
- {bad_request,
- <<"Only reserved document ids may start with underscore.">>},
- "Disallow arbitrary underscore prefixed docids."
- },
- {
- {[{<<"_rev">>, 5}]},
- {bad_request, <<"Invalid rev format">>},
- "_rev must be a string"
- },
- {
- {[{<<"_rev">>, "foobar"}]},
- {bad_request, <<"Invalid rev format">>},
- "_rev must be %d-%s"
- },
- {
- {[{<<"_rev">>, "foo-bar"}]},
- "Error if _rev's integer expection is broken."
- },
- {
- {[{<<"_revisions">>, {[{<<"start">>, true}]}}]},
- {doc_validation, "_revisions.start isn't an integer."},
- "_revisions.start must be an integer."
- },
- {
- {[{<<"_revisions">>, {[{<<"start">>, 0}, {<<"ids">>, 5}]}}]},
- {doc_validation, "_revisions.ids isn't a array."},
- "_revions.ids must be a list."
- },
- {
- {[{<<"_revisions">>, {[{<<"start">>, 0}, {<<"ids">>, [5]}]}}]},
- {doc_validation, "RevId isn't a string"},
- "Revision ids must be strings."
- },
- {
- {[{<<"_something">>, 5}]},
- {doc_validation, <<"Bad special document member: _something">>},
- "Underscore prefix fields are reserved."
- }
- ],
-
- lists:map(fun
- ({EJson, Expect, Msg}) ->
- Error = (catch couch_doc:from_json_obj(EJson)),
- {Msg, ?_assertMatch(Expect, Error)};
- ({EJson, Msg}) ->
- try
- couch_doc:from_json_obj(EJson),
- {"Conversion failed to raise an exception", ?_assert(false)}
- catch
- _:_ -> {Msg, ?_assert(true)}
- end
- end, Cases).
-
-to_json_success_cases() ->
- Cases = [
- {
- #doc{},
- {[{<<"_id">>, <<"">>}]},
- "Empty docs are {\"_id\": \"\"}"
- },
- {
- #doc{id = <<"foo">>},
- {[{<<"_id">>, <<"foo">>}]},
- "_id is added."
- },
- {
- #doc{revs = {5, ["foo"]}},
- {[{<<"_id">>, <<>>}, {<<"_rev">>, <<"5-foo">>}]},
- "_rev is added."
- },
- {
- [revs],
- #doc{revs = {5, [<<"first">>, <<"second">>]}},
- {[
- {<<"_id">>, <<>>},
- {<<"_rev">>, <<"5-first">>},
- {<<"_revisions">>, {[
- {<<"start">>, 5},
- {<<"ids">>, [<<"first">>, <<"second">>]}
- ]}}
- ]},
- "_revisions include with revs option"
- },
- {
- #doc{body = {[{<<"foo">>, <<"bar">>}]}},
- {[{<<"_id">>, <<>>}, {<<"foo">>, <<"bar">>}]},
- "Arbitrary fields are added."
- },
- {
- #doc{deleted = true, body = {[{<<"foo">>, <<"bar">>}]}},
- {[{<<"_id">>, <<>>}, {<<"foo">>, <<"bar">>}, {<<"_deleted">>, true}]},
- "Deleted docs no longer drop body members."
- },
- {
- #doc{meta = [
- {revs_info, 4, [{<<"fin">>, deleted}, {<<"zim">>, missing}]}
- ]},
- {[
- {<<"_id">>, <<>>},
- {<<"_revs_info">>, [
- {[{<<"rev">>, <<"4-fin">>}, {<<"status">>, <<"deleted">>}]},
- {[{<<"rev">>, <<"3-zim">>}, {<<"status">>, <<"missing">>}]}
- ]}
- ]},
- "_revs_info field is added correctly."
- },
- {
- #doc{meta = [{local_seq, 5}]},
- {[{<<"_id">>, <<>>}, {<<"_local_seq">>, 5}]},
- "_local_seq is added as an integer."
- },
- {
- #doc{meta = [{conflicts, [{3, <<"yep">>}, {1, <<"snow">>}]}]},
- {[
- {<<"_id">>, <<>>},
- {<<"_conflicts">>, [<<"3-yep">>, <<"1-snow">>]}
- ]},
- "_conflicts is added as an array of strings."
- },
- {
- #doc{meta = [{deleted_conflicts, [{10923, <<"big_cowboy_hat">>}]}]},
- {[
- {<<"_id">>, <<>>},
- {<<"_deleted_conflicts">>, [<<"10923-big_cowboy_hat">>]}
- ]},
- "_deleted_conflicsts is added as an array of strings."
- },
- {
- #doc{atts = [
- #att{
- name = <<"big.xml">>,
- type = <<"xml/sucks">>,
- data = fun() -> ok end,
- revpos = 1,
- att_len = 400,
- disk_len = 400
- },
- #att{
- name = <<"fast.json">>,
- type = <<"json/ftw">>,
- data = <<"{\"so\": \"there!\"}">>,
- revpos = 1,
- att_len = 16,
- disk_len = 16
- }
- ]},
- {[
- {<<"_id">>, <<>>},
- {<<"_attachments">>, {[
- {<<"big.xml">>, {[
- {<<"content_type">>, <<"xml/sucks">>},
- {<<"revpos">>, 1},
- {<<"length">>, 400},
- {<<"stub">>, true}
- ]}},
- {<<"fast.json">>, {[
- {<<"content_type">>, <<"json/ftw">>},
- {<<"revpos">>, 1},
- {<<"length">>, 16},
- {<<"stub">>, true}
- ]}}
- ]}}
- ]},
- "Attachments attached as stubs only include a length."
- },
- {
- [attachments],
- #doc{atts = [
- #att{
- name = <<"stuff.txt">>,
- type = <<"text/plain">>,
- data = fun() -> <<"diet pepsi">> end,
- revpos = 1,
- att_len = 10,
- disk_len = 10
- },
- #att{
- name = <<"food.now">>,
- type = <<"application/food">>,
- revpos = 1,
- data = <<"sammich">>
- }
- ]},
- {[
- {<<"_id">>, <<>>},
- {<<"_attachments">>, {[
- {<<"stuff.txt">>, {[
- {<<"content_type">>, <<"text/plain">>},
- {<<"revpos">>, 1},
- {<<"data">>, <<"ZGlldCBwZXBzaQ==">>}
- ]}},
- {<<"food.now">>, {[
- {<<"content_type">>, <<"application/food">>},
- {<<"revpos">>, 1},
- {<<"data">>, <<"c2FtbWljaA==">>}
- ]}}
- ]}}
- ]},
- "Attachments included inline with attachments option."
- }
- ],
-
- lists:map(fun
- ({Doc, EJson, Msg}) ->
- {Msg, ?_assertMatch(EJson, couch_doc:to_json_obj(Doc, []))};
- ({Options, Doc, EJson, Msg}) ->
- {Msg, ?_assertMatch(EJson, couch_doc:to_json_obj(Doc, Options))}
- end, Cases).