http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/68453039/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/68453039/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/68453039/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/68453039/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/68453039/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/68453039/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).
