diff options
author | iilyak <iilyak@users.noreply.github.com> | 2022-02-04 09:41:48 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-04 09:41:48 -0800 |
commit | 073a2db2b2b1c4e8e1c2445c3e24341b26b1a753 (patch) | |
tree | 715a30dde12a4318d92d0cfd8df7c5cfbd6f2cf1 | |
parent | 50080a9b1baef6e3f9d25953ba7bae8dd73132fe (diff) | |
parent | 0b4fd938a1bae98d5c2c643da623206ae1eb1f87 (diff) | |
download | couchdb-073a2db2b2b1c4e8e1c2445c3e24341b26b1a753.tar.gz |
Merge pull request #3923 from jiahuili430/81-fixup-dbs-info
Execute chttpd_dbs_info_tests in clean database_dir
-rw-r--r-- | src/chttpd/test/eunit/chttpd_dbs_info_test.erl | 527 |
1 files changed, 216 insertions, 311 deletions
diff --git a/src/chttpd/test/eunit/chttpd_dbs_info_test.erl b/src/chttpd/test/eunit/chttpd_dbs_info_test.erl index 6c648b1b7..34670877f 100644 --- a/src/chttpd/test/eunit/chttpd_dbs_info_test.erl +++ b/src/chttpd/test/eunit/chttpd_dbs_info_test.erl @@ -14,358 +14,263 @@ -include_lib("couch/include/couch_eunit.hrl"). -include_lib("couch/include/couch_db.hrl"). +-include("chttpd_test.hrl"). -define(USER, "chttpd_db_test_admin"). -define(PASS, "pass"). -define(AUTH, {basic_auth, {?USER, ?PASS}}). -define(CONTENT_JSON, {"Content-Type", "application/json"}). +start() -> + Ctx = chttpd_test_util:start_couch(), + DbDir = config:get("couchdb", "database_dir"), + Suffix = ?b2l(couch_uuids:random()), + test_util:with_couch_server_restart(fun() -> + config:set("couchdb", "database_dir", DbDir ++ "/" ++ Suffix, false) + end), + mock([fabric_util, chttpd_util]), + Ctx. + +stop(Ctx) -> + config:delete("couchdb", "database_dir", false), + chttpd_test_util:stop_couch(Ctx). + setup() -> Hashed = couch_passwords:hash_admin_password(?PASS), ok = config:set("admins", ?USER, ?b2l(Hashed), _Persist = false), - Addr = config:get("chttpd", "bind_address", "127.0.0.1"), - Port = mochiweb_socket_server:get(chttpd, port), - Url = lists:concat(["http://", Addr, ":", Port, "/"]), - Db1Url = lists:concat([Url, "db1"]), - create_db(Db1Url), - Db2Url = lists:concat([Url, "db2"]), - create_db(Db2Url), - mock(fabric_util), - mock(chttpd_util), - Url. - -teardown(Url) -> + Suffix = ?b2l(couch_uuids:random()), + Db1 = testdb("db1", Suffix), + Db2 = testdb("db2", Suffix), + create_db(base_url(Db1)), + create_db(base_url(Db2)), + {Suffix, Db1, Db2}. + +teardown({_, Db1, Db2}) -> meck:unload(), - Db1Url = lists:concat([Url, "db1"]), - Db2Url = lists:concat([Url, "db2"]), - delete_db(Db1Url), - delete_db(Db2Url), + delete_db(base_url(Db1)), + delete_db(base_url(Db2)), ok = config:delete("admins", ?USER, _Persist = false). -create_db(Url) -> - {ok, Status, _, _} = test_request:put(Url, [?CONTENT_JSON, ?AUTH], "{}"), - ?assert(Status =:= 201 orelse Status =:= 202). - -delete_db(Url) -> - {ok, 200, _, _} = test_request:delete(Url, [?AUTH]). - -mock(Module) -> - meck:new(Module, [passthrough]). - -mock_timeout() -> - meck:expect(fabric_util, request_timeout, fun() -> 0 end). - -mock_db_not_exist() -> - meck:expect( - chttpd_util, - get_db_info, - fun(_) -> {error, database_does_not_exist} end - ). - dbs_info_test_() -> { "chttpd dbs info tests", { setup, - fun chttpd_test_util:start_couch/0, - fun chttpd_test_util:stop_couch/1, + fun start/0, + fun stop/1, { foreach, fun setup/0, fun teardown/1, [ - fun get_db_info_should_return_db_info/1, - fun get_db_info_should_return_error_when_db_not_exist/1, - fun get_db_info_should_return_error_when_time_out/1, - fun should_return_error_for_put_dbs_info/1, - fun should_return_dbs_info_for_get_dbs_info/1, - fun should_return_nothing_when_db_not_exist_for_get_dbs_info/1, - fun should_return_500_time_out_when_time_is_not_enough_for_get_dbs_info/1, - fun should_return_db2_for_get_dbs_info_with_descending/1, - fun should_return_db1_for_get_dbs_info_with_limit_1/1, - fun should_return_db2_for_get_dbs_info_with_skip_1/1, - fun should_return_dbs_info_with_correct_start_end_key/1, - fun should_return_empty_list_with_wrong_start_end_key/1, - fun should_return_dbs_info_for_single_db/1, - fun should_return_dbs_info_for_multiple_dbs/1, - fun should_return_error_for_exceeded_keys/1, - fun should_return_error_for_missing_keys/1, - fun should_return_dbs_info_for_dbs_with_mixed_state/1 + ?TDEF_FE(get_db_info_should_return_db_info), + ?TDEF_FE(get_db_info_should_return_error_when_db_not_exist), + ?TDEF_FE(get_db_info_should_return_error_when_time_out), + ?TDEF_FE(should_return_error_for_put_dbs_info), + ?TDEF_FE(should_return_dbs_info_for_get_dbs_info), + ?TDEF_FE(should_return_nothing_when_db_not_exist_for_get_dbs_info), + ?TDEF_FE(should_return_500_time_out_when_time_is_not_enough_for_get_dbs_info), + ?TDEF_FE(should_return_db2_for_get_dbs_info_with_descending), + ?TDEF_FE(should_return_db1_for_get_dbs_info_with_limit_1), + ?TDEF_FE(should_return_db2_for_get_dbs_info_with_skip_1), + ?TDEF_FE(should_return_dbs_info_with_correct_start_end_key), + ?TDEF_FE(should_return_empty_list_with_wrong_start_end_key), + ?TDEF_FE(should_return_dbs_info_for_single_db), + ?TDEF_FE(should_return_dbs_info_for_multiple_dbs), + ?TDEF_FE(should_return_error_for_exceeded_keys), + ?TDEF_FE(should_return_error_for_missing_keys), + ?TDEF_FE(should_return_dbs_info_for_dbs_with_mixed_state) ] } } }. -get_db_info_should_return_db_info(_) -> - DbInfo = fabric:get_db_info("db1"), - ?_assertEqual(DbInfo, chttpd_util:get_db_info("db1")). +get_db_info_should_return_db_info({_, Db1, _}) -> + DbInfo = fabric:get_db_info(Db1), + ?assertEqual(DbInfo, chttpd_util:get_db_info(Db1)). get_db_info_should_return_error_when_db_not_exist(_) -> - ?_assertEqual( + ?assertEqual( {error, database_does_not_exist}, chttpd_util:get_db_info("db_not_exist") ). -get_db_info_should_return_error_when_time_out(_) -> - ?_test( - begin - mock_timeout(), - ?assertEqual({error, timeout}, chttpd_util:get_db_info("db1")) - end - ). +get_db_info_should_return_error_when_time_out({_, Db1, _}) -> + mock_timeout(), + ?assertEqual({error, timeout}, chttpd_util:get_db_info(Db1)). -should_return_error_for_put_dbs_info(Url) -> - ?_test( - begin - {ok, Code, _, ResultBody} = test_request:put( - Url ++ - "_dbs_info", - [?CONTENT_JSON, ?AUTH], - "" - ), - {Body} = jiffy:decode(ResultBody), - ?assertEqual(405, Code), - ?assertEqual( - <<"method_not_allowed">>, - couch_util:get_value(<<"error">>, Body) - ) - end - ). +should_return_error_for_put_dbs_info(_) -> + {ok, Code, _, ResultBody} = test_request:put( + dbs_info_url(), [?CONTENT_JSON, ?AUTH], "" + ), + {Body} = jiffy:decode(ResultBody), + ?assertEqual( + <<"method_not_allowed">>, + couch_util:get_value(<<"error">>, Body) + ), + ?assertEqual(405, Code). -should_return_dbs_info_for_get_dbs_info(Url) -> - ?_test( - begin - {ok, _, _, ResultBody} = test_request:get( - Url ++ - "_dbs_info", - [?CONTENT_JSON, ?AUTH] - ), - BodyJson = jiffy:decode(ResultBody), - {Db1Data} = lists:nth(1, BodyJson), - {Db2Data} = lists:nth(2, BodyJson), - ?assertEqual(2, length(BodyJson)), - ?assertEqual(<<"db1">>, couch_util:get_value(<<"key">>, Db1Data)), - ?assertEqual(<<"db2">>, couch_util:get_value(<<"key">>, Db2Data)) - end - ). +should_return_dbs_info_for_get_dbs_info({Suffix, Db1, Db2}) -> + {ok, _, _, ResultBody} = test_request:get( + dbs_info_url(), [?CONTENT_JSON, ?AUTH] + ), + FilteredDbs = filter_dbs(Suffix, ResultBody), + ?assertEqual([Db1, Db2], FilteredDbs). -should_return_nothing_when_db_not_exist_for_get_dbs_info(Url) -> - ?_test( - begin - mock_db_not_exist(), - {ok, Code, _, ResultBody} = test_request:get( - Url ++ - "_dbs_info", - [?CONTENT_JSON, ?AUTH] - ), - BodyJson = jiffy:decode(ResultBody), - ?assertEqual(200, Code), - ?assertEqual([], BodyJson) - end - ). +should_return_nothing_when_db_not_exist_for_get_dbs_info(_) -> + mock_db_not_exist(), + {ok, Code, _, ResultBody} = test_request:get( + dbs_info_url(), [?CONTENT_JSON, ?AUTH] + ), + Info = jiffy:decode(ResultBody), + ?assertEqual([], Info), + ?assertEqual(200, Code). -should_return_500_time_out_when_time_is_not_enough_for_get_dbs_info(Url) -> - ?_test( - begin - mock_timeout(), - {ok, Code, _, ResultBody} = test_request:get( - Url ++ "_dbs_info" ++ - "?buffer_response=true", - [?CONTENT_JSON, ?AUTH] - ), - {Body} = jiffy:decode(ResultBody), - ?assertEqual(500, Code), - ?assertEqual(<<"timeout">>, couch_util:get_value(<<"error">>, Body)) - end - ). +should_return_500_time_out_when_time_is_not_enough_for_get_dbs_info(_) -> + mock_timeout(), + {ok, Code, _, ResultBody} = test_request:get( + dbs_info_url("buffer_response=true"), [?CONTENT_JSON, ?AUTH] + ), + {Body} = jiffy:decode(ResultBody), + ?assertEqual(<<"timeout">>, couch_util:get_value(<<"error">>, Body)), + ?assertEqual(500, Code). -should_return_db2_for_get_dbs_info_with_descending(Url) -> - ?_test( - begin - {ok, _, _, ResultBody} = test_request:get( - Url ++ "_dbs_info" ++ - "?descending=true", - [?CONTENT_JSON, ?AUTH] - ), - BodyJson = jiffy:decode(ResultBody), - {Db1Data} = lists:nth(1, BodyJson), - {Db2Data} = lists:nth(2, BodyJson), - ?assertEqual(2, length(BodyJson)), - ?assertEqual(<<"db2">>, couch_util:get_value(<<"key">>, Db1Data)), - ?assertEqual(<<"db1">>, couch_util:get_value(<<"key">>, Db2Data)) - end - ). +should_return_db2_for_get_dbs_info_with_descending({Suffix, Db1, Db2}) -> + {ok, _, _, ResultBody} = test_request:get( + dbs_info_url("descending=true"), [?CONTENT_JSON, ?AUTH] + ), + FilteredDbs = filter_dbs(Suffix, ResultBody), + ?assertEqual([Db2, Db1], FilteredDbs). -should_return_db1_for_get_dbs_info_with_limit_1(Url) -> - ?_test( - begin - {ok, _, _, ResultBody} = test_request:get( - Url ++ "_dbs_info" ++ - "?limit=1", - [?CONTENT_JSON, ?AUTH] - ), - BodyJson = jiffy:decode(ResultBody), - {DbData} = lists:nth(1, BodyJson), - ?assertEqual(1, length(BodyJson)), - ?assertEqual(<<"db1">>, couch_util:get_value(<<"key">>, DbData)) - end - ). +should_return_db1_for_get_dbs_info_with_limit_1({Suffix, Db1, _}) -> + {ok, _, _, ResultBody} = test_request:get( + dbs_info_url("limit=1"), [?CONTENT_JSON, ?AUTH] + ), + FilteredDbs = filter_dbs(Suffix, ResultBody), + ?assertEqual([Db1], FilteredDbs). -should_return_db2_for_get_dbs_info_with_skip_1(Url) -> - ?_test( - begin - {ok, _, _, ResultBody} = test_request:get( - Url ++ "_dbs_info" ++ - "?skip=1", - [?CONTENT_JSON, ?AUTH] - ), - BodyJson = jiffy:decode(ResultBody), - {DbData} = lists:nth(1, BodyJson), - ?assertEqual(1, length(BodyJson)), - ?assertEqual(<<"db2">>, couch_util:get_value(<<"key">>, DbData)) - end - ). +should_return_db2_for_get_dbs_info_with_skip_1({Suffix, _, Db2}) -> + {ok, _, _, ResultBody} = test_request:get( + dbs_info_url("skip=1"), [?CONTENT_JSON, ?AUTH] + ), + FilteredDbs = filter_dbs(Suffix, ResultBody), + ?assertEqual([Db2], FilteredDbs). -should_return_dbs_info_with_correct_start_end_key(Url) -> - ?_test( - begin - {ok, _, _, ResultBody} = test_request:get( - Url ++ "_dbs_info" ++ - "?startkey=\"db1\"&endkey=\"db2\"", - [?CONTENT_JSON, ?AUTH] - ), - BodyJson = jiffy:decode(ResultBody), - {DbData} = lists:nth(1, BodyJson), - ?assertEqual(2, length(BodyJson)), - ?assertEqual(<<"db1">>, couch_util:get_value(<<"key">>, DbData)) - end - ). +should_return_dbs_info_with_correct_start_end_key({Suffix, Db1, _}) -> + {ok, _, _, ResultBody} = test_request:get( + dbs_info_url("startkey=\"db1\"&endkey=\"db2\""), [?CONTENT_JSON, ?AUTH] + ), + FilteredDbs = filter_dbs(Suffix, ResultBody), + ?assertEqual([Db1], FilteredDbs). + +should_return_empty_list_with_wrong_start_end_key(_) -> + {ok, _, _, ResultBody} = test_request:get( + dbs_info_url("startkey=\"db3\"&endkey=\"db4\""), [?CONTENT_JSON, ?AUTH] + ), + ?assertEqual([], jiffy:decode(ResultBody)). + +should_return_dbs_info_for_single_db({_, Db1, _}) -> + NewDoc = "{\"keys\": [\"" ++ Db1 ++ "\"]}", + {ok, _, _, ResultBody} = test_request:post( + dbs_info_url(), [?CONTENT_JSON, ?AUTH], NewDoc + ), + BodyJson = jiffy:decode(ResultBody), + {Db1Data} = lists:nth(1, BodyJson), + ?assertEqual(?l2b(Db1), couch_util:get_value(<<"key">>, Db1Data)), + ?assertNotEqual(undefined, couch_util:get_value(<<"info">>, Db1Data)). + +should_return_dbs_info_for_multiple_dbs({_, Db1, Db2}) -> + NewDoc = "{\"keys\": [\"" ++ Db1 ++ "\", \"" ++ Db2 ++ "\"]}", + {ok, _, _, ResultBody} = test_request:post( + dbs_info_url(), [?CONTENT_JSON, ?AUTH], NewDoc + ), + BodyJson = jiffy:decode(ResultBody), + {Db1Data} = lists:nth(1, BodyJson), + {Db2Data} = lists:nth(2, BodyJson), + ?assertEqual(?l2b(Db1), couch_util:get_value(<<"key">>, Db1Data)), + ?assertNotEqual(undefined, couch_util:get_value(<<"info">>, Db1Data)), + ?assertEqual(?l2b(Db2), couch_util:get_value(<<"key">>, Db2Data)), + ?assertNotEqual(undefined, couch_util:get_value(<<"info">>, Db2Data)). + +should_return_error_for_exceeded_keys({_, Db1, Db2}) -> + NewDoc = "{\"keys\": [\"" ++ Db1 ++ "\", \"" ++ Db2 ++ "\"]}", + ok = config:set("chttpd", "max_db_number_for_dbs_info_req", "1"), + {ok, Code, _, ResultBody} = test_request:post( + dbs_info_url(), [?CONTENT_JSON, ?AUTH], NewDoc + ), + {Body} = jiffy:decode(ResultBody), + ok = config:delete("chttpd", "max_db_number_for_dbs_info_req"), + ?assertEqual(<<"bad_request">>, couch_util:get_value(<<"error">>, Body)), + ?assertEqual(400, Code). + +should_return_error_for_missing_keys({_, Db1, Db2}) -> + NewDoc = "{\"missingkeys\": [\"" ++ Db1 ++ "\", \"" ++ Db2 ++ "\"]}", + {ok, Code, _, ResultBody} = test_request:post( + dbs_info_url(), [?CONTENT_JSON, ?AUTH], NewDoc + ), + {Body} = jiffy:decode(ResultBody), + ?assertEqual(<<"bad_request">>, couch_util:get_value(<<"error">>, Body)), + ?assertEqual(400, Code). + +should_return_dbs_info_for_dbs_with_mixed_state({_, Db1, _}) -> + NewDoc = "{\"keys\": [\"" ++ Db1 ++ "\", \"noexisteddb\"]}", + {ok, _, _, ResultBody} = test_request:post( + dbs_info_url(), [?CONTENT_JSON, ?AUTH], NewDoc + ), + Json = jiffy:decode(ResultBody), + {Db1Data} = lists:nth(1, Json), + {Db2Data} = lists:nth(2, Json), + ?assertEqual(?l2b(Db1), couch_util:get_value(<<"key">>, Db1Data)), + ?assertNotEqual(undefined, couch_util:get_value(<<"info">>, Db1Data)), + ?assertEqual(<<"noexisteddb">>, couch_util:get_value(<<"key">>, Db2Data)), + ?assertEqual(undefined, couch_util:get_value(<<"info">>, Db2Data)). + +%% Utility functions +testdb(Name, Suffix) -> + Name ++ "-" ++ Suffix. + +base_url() -> + Addr = config:get("chttpd", "bind_address", "127.0.0.1"), + Port = mochiweb_socket_server:get(chttpd, port), + lists:concat(["http://", Addr, ":", Port, "/"]). + +base_url(Path) -> + base_url() ++ Path. + +dbs_info_url() -> + base_url() ++ "_dbs_info". + +dbs_info_url(Option) -> + dbs_info_url() ++ "?" ++ Option. + +create_db(Url) -> + {ok, Status, _, _} = test_request:put(Url, [?CONTENT_JSON, ?AUTH], "{}"), + ?assert(Status =:= 201 orelse Status =:= 202). + +delete_db(Url) -> + {ok, 200, _, _} = test_request:delete(Url, [?AUTH]). -should_return_empty_list_with_wrong_start_end_key(Url) -> - ?_test( - begin - {ok, _, _, ResultBody} = test_request:get( - Url ++ "_dbs_info" ++ - "?startkey=\"db3\"&endkey=\"db4\"", - [?CONTENT_JSON, ?AUTH] - ), - ?assertEqual([], jiffy:decode(ResultBody)) - end +mock(Modules) -> + lists:foreach(fun(Mod) -> meck:new(Mod, [passthrough]) end, Modules). + +mock_timeout() -> + meck:expect(fabric_util, request_timeout, fun() -> 0 end). + +mock_db_not_exist() -> + meck:expect( + chttpd_util, + get_db_info, + fun(_) -> {error, database_does_not_exist} end ). -should_return_dbs_info_for_single_db(Url) -> - ?_test(begin - NewDoc = "{\"keys\": [\"db1\"]}", - {ok, _, _, ResultBody} = test_request:post( - Url ++ "/_dbs_info/", - [?CONTENT_JSON, ?AUTH], - NewDoc - ), - BodyJson = jiffy:decode(ResultBody), - {Db1Data} = lists:nth(1, BodyJson), - [ - ?assertEqual( - <<"db1">>, - couch_util:get_value(<<"key">>, Db1Data) - ), - ?assertNotEqual( - undefined, - couch_util:get_value(<<"info">>, Db1Data) - ) - ] - end). - -should_return_dbs_info_for_multiple_dbs(Url) -> - ?_test(begin - NewDoc = "{\"keys\": [\"db1\", \"db2\"]}", - {ok, _, _, ResultBody} = test_request:post( - Url ++ "/_dbs_info/", - [?CONTENT_JSON, ?AUTH], - NewDoc - ), - BodyJson = jiffy:decode(ResultBody), - {Db1Data} = lists:nth(1, BodyJson), - {Db2Data} = lists:nth(2, BodyJson), - [ - ?assertEqual( - <<"db1">>, - couch_util:get_value(<<"key">>, Db1Data) - ), - ?assertNotEqual( - undefined, - couch_util:get_value(<<"info">>, Db1Data) - ), - ?assertEqual( - <<"db2">>, - couch_util:get_value(<<"key">>, Db2Data) - ), - ?assertNotEqual( - undefined, - couch_util:get_value(<<"info">>, Db2Data) - ) - ] - end). - -should_return_error_for_exceeded_keys(Url) -> - ?_test(begin - NewDoc = "{\"keys\": [\"db1\", \"db2\"]}", - ok = config:set("chttpd", "max_db_number_for_dbs_info_req", "1"), - {ok, Code, _, ResultBody} = test_request:post( - Url ++ "/_dbs_info/", - [?CONTENT_JSON, ?AUTH], - NewDoc - ), - {Body} = jiffy:decode(ResultBody), - ok = config:delete("chttpd", "max_db_number_for_dbs_info_req"), - [ - ?assertEqual( - <<"bad_request">>, - couch_util:get_value(<<"error">>, Body) - ), - ?assertEqual(400, Code) - ] - end). - -should_return_error_for_missing_keys(Url) -> - ?_test(begin - NewDoc = "{\"missingkeys\": [\"db1\", \"db2\"]}", - {ok, Code, _, ResultBody} = test_request:post( - Url ++ "/_dbs_info/", - [?CONTENT_JSON, ?AUTH], - NewDoc - ), - {Body} = jiffy:decode(ResultBody), - [ - ?assertEqual( - <<"bad_request">>, - couch_util:get_value(<<"error">>, Body) - ), - ?assertEqual(400, Code) - ] - end). - -should_return_dbs_info_for_dbs_with_mixed_state(Url) -> - ?_test(begin - NewDoc = "{\"keys\": [\"db1\", \"noexisteddb\"]}", - {ok, _, _, ResultBody} = test_request:post( - Url ++ "/_dbs_info/", - [?CONTENT_JSON, ?AUTH], - NewDoc - ), - Json = jiffy:decode(ResultBody), - {Db1Data} = lists:nth(1, Json), - {Db2Data} = lists:nth(2, Json), - [ - ?assertEqual( - <<"db1">>, couch_util:get_value(<<"key">>, Db1Data) - ), - ?assertNotEqual( - undefined, - couch_util:get_value(<<"info">>, Db1Data) - ), - ?assertEqual( - <<"noexisteddb">>, couch_util:get_value(<<"key">>, Db2Data) - ), - ?assertEqual(undefined, couch_util:get_value(<<"info">>, Db2Data)) - ] - end). +filter_dbs(Suffix, ResultBody) -> + Dbs = jiffy:decode(ResultBody, [return_maps]), + SuffixBin = ?l2b(Suffix), + SuffixSize = size(SuffixBin), + FilterFun = + fun(Db) -> + Name = maps:get(<<"key">>, Db), + size(Name) > SuffixSize andalso + binary:part(Name, size(Name), -SuffixSize) =:= SuffixBin + end, + [?b2l(maps:get(<<"key">>, Db)) || Db <- Dbs, FilterFun(Db)]. |