diff options
author | Alexander Shorin <kxepal@apache.org> | 2014-06-09 20:15:37 +0400 |
---|---|---|
committer | Alexander Shorin <kxepal@apache.org> | 2014-06-17 01:41:45 +0400 |
commit | 4b01190b7864aec0df0d3d977e08179624fd3ebb (patch) | |
tree | 886ada1f12c991f0aaac9e7914d6090ddbb0e021 | |
parent | bde290a2ab2a87042421f8038e137665f9ab9e12 (diff) | |
download | couchdb-4b01190b7864aec0df0d3d977e08179624fd3ebb.tar.gz |
Port 220-compaction-daemon.t etap test suite to eunit
-rw-r--r-- | test/couchdb/Makefile.am | 1 | ||||
-rw-r--r-- | test/couchdb/couchdb_compaction_daemon.erl | 231 | ||||
-rwxr-xr-x | test/etap/220-compaction-daemon.t | 225 | ||||
-rw-r--r-- | test/etap/Makefile.am | 1 |
4 files changed, 232 insertions, 226 deletions
diff --git a/test/couchdb/Makefile.am b/test/couchdb/Makefile.am index f1728bb8c..0403559f9 100644 --- a/test/couchdb/Makefile.am +++ b/test/couchdb/Makefile.am @@ -39,6 +39,7 @@ eunit_files = \ couch_uuids_tests.erl \ couch_work_queue_tests.erl \ couchdb_attachments_tests.erl \ + couchdb_compaction_daemon.erl \ couchdb_file_compression_tests.erl \ couchdb_http_proxy_tests.erl \ couchdb_modules_load_tests.erl \ diff --git a/test/couchdb/couchdb_compaction_daemon.erl b/test/couchdb/couchdb_compaction_daemon.erl new file mode 100644 index 000000000..725a97b45 --- /dev/null +++ b/test/couchdb/couchdb_compaction_daemon.erl @@ -0,0 +1,231 @@ +% 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(couchdb_compaction_daemon). + +-include("couch_eunit.hrl"). +-include_lib("couchdb/couch_db.hrl"). + +-define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}). +-define(DELAY, 100). +-define(TIMEOUT, 30000). +-define(TIMEOUT_S, ?TIMEOUT div 1000). + + +start() -> + {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN), + couch_config:set("compaction_daemon", "check_interval", "3", false), + couch_config:set("compaction_daemon", "min_file_size", "100000", false), + 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} = couch_db:create(DbName, [?ADMIN_USER]), + create_design_doc(Db), + ok = couch_db:close(Db), + DbName. + +teardown(DbName) -> + Configs = couch_config:get("compactions"), + lists:foreach( + fun({Key, _}) -> + ok = couch_config:delete("compactions", Key, false) + end, + Configs), + couch_server:delete(DbName, [?ADMIN_USER]), + ok. + + +compaction_daemon_test_() -> + { + "Compaction daemon tests", + { + setup, + fun start/0, fun stop/1, + { + foreach, + fun setup/0, fun teardown/1, + [ + fun should_compact_by_default_rule/1, + fun should_compact_by_dbname_rule/1 + ] + } + } + }. + + +should_compact_by_default_rule(DbName) -> + {timeout, ?TIMEOUT_S, ?_test(begin + {ok, Db} = couch_db:open_int(DbName, []), + populate(DbName, 70, 70, 200 * 1024), + + {_, DbFileSize} = get_db_frag(DbName), + {_, ViewFileSize} = get_view_frag(DbName), + + ok = couch_config:set("compactions", "_default", + "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]", + false), + + ok = timer:sleep(4000), % something >= check_interval + wait_compaction_finished(DbName), + ok = couch_config:delete("compactions", "_default", false), + + {DbFrag2, DbFileSize2} = get_db_frag(DbName), + {ViewFrag2, ViewFileSize2} = get_view_frag(DbName), + + ?assert(DbFrag2 < 70), + ?assert(ViewFrag2 < 70), + + ?assert(DbFileSize > DbFileSize2), + ?assert(ViewFileSize > ViewFileSize2), + + ?assert(couch_db:is_idle(Db)), + ok = couch_db:close(Db) + end)}. + +should_compact_by_dbname_rule(DbName) -> + {timeout, ?TIMEOUT_S, ?_test(begin + {ok, Db} = couch_db:open_int(DbName, []), + populate(DbName, 70, 70, 200 * 1024), + + {_, DbFileSize} = get_db_frag(DbName), + {_, ViewFileSize} = get_view_frag(DbName), + + ok = couch_config:set("compactions", ?b2l(DbName), + "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]", + false), + + ok = timer:sleep(4000), % something >= check_interval + wait_compaction_finished(DbName), + ok = couch_config:delete("compactions", ?b2l(DbName), false), + + {DbFrag2, DbFileSize2} = get_db_frag(DbName), + {ViewFrag2, ViewFileSize2} = get_view_frag(DbName), + + ?assert(DbFrag2 < 70), + ?assert(ViewFrag2 < 70), + + ?assert(DbFileSize > DbFileSize2), + ?assert(ViewFileSize > ViewFileSize2), + + ?assert(couch_db:is_idle(Db)), + ok = couch_db:close(Db) + end)}. + + +create_design_doc(Db) -> + DDoc = couch_doc:from_json_obj({[ + {<<"_id">>, <<"_design/foo">>}, + {<<"language">>, <<"javascript">>}, + {<<"views">>, {[ + {<<"foo">>, {[ + {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>} + ]}}, + {<<"foo2">>, {[ + {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>} + ]}}, + {<<"foo3">>, {[ + {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>} + ]}} + ]}} + ]}), + {ok, _} = couch_db:update_docs(Db, [DDoc]), + {ok, _} = couch_db:ensure_full_commit(Db), + ok. + +populate(DbName, DbFrag, ViewFrag, MinFileSize) -> + {CurDbFrag, DbFileSize} = get_db_frag(DbName), + {CurViewFrag, ViewFileSize} = get_view_frag(DbName), + populate(DbName, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag, + lists:min([DbFileSize, ViewFileSize])). + +populate(_Db, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag, FileSize) + when CurDbFrag >= DbFrag, CurViewFrag >= ViewFrag, FileSize >= MinFileSize -> + ok; +populate(DbName, DbFrag, ViewFrag, MinFileSize, _, _, _) -> + update(DbName), + {CurDbFrag, DbFileSize} = get_db_frag(DbName), + {CurViewFrag, ViewFileSize} = get_view_frag(DbName), + populate(DbName, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag, + lists:min([DbFileSize, ViewFileSize])). + +update(DbName) -> + {ok, Db} = couch_db:open_int(DbName, []), + lists:foreach(fun(_) -> + Doc = couch_doc:from_json_obj({[{<<"_id">>, couch_uuids:new()}]}), + {ok, _} = couch_db:update_docs(Db, [Doc]), + query_view(Db#db.name) + end, lists:seq(1, 200)), + couch_db:close(Db). + +db_url(DbName) -> + Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"), + Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)), + "http://" ++ Addr ++ ":" ++ Port ++ "/" ++ ?b2l(DbName). + +query_view(DbName) -> + {ok, Code, _Headers, _Body} = test_request:get( + db_url(DbName) ++ "/_design/foo/_view/foo"), + ?assertEqual(200, Code). + +get_db_frag(DbName) -> + {ok, Db} = couch_db:open_int(DbName, []), + {ok, Info} = couch_db:get_db_info(Db), + couch_db:close(Db), + FileSize = couch_util:get_value(disk_size, Info), + DataSize = couch_util:get_value(data_size, Info), + {round((FileSize - DataSize) / FileSize * 100), FileSize}. + +get_view_frag(DbName) -> + {ok, Db} = couch_db:open_int(DbName, []), + {ok, Info} = couch_mrview:get_info(Db, <<"_design/foo">>), + couch_db:close(Db), + FileSize = couch_util:get_value(disk_size, Info), + DataSize = couch_util:get_value(data_size, Info), + {round((FileSize - DataSize) / FileSize * 100), FileSize}. + +wait_compaction_finished(DbName) -> + Parent = self(), + Loop = spawn_link(fun() -> wait_loop(DbName, Parent) end), + receive + {done, Loop} -> + ok + after ?TIMEOUT -> + erlang:error( + {assertion_failed, + [{module, ?MODULE}, {line, ?LINE}, + {reason, "Compaction timeout"}]}) + end. + +wait_loop(DbName, Parent) -> + {ok, Db} = couch_db:open_int(DbName, []), + {ok, DbInfo} = couch_db:get_db_info(Db), + {ok, ViewInfo} = couch_mrview:get_info(Db, <<"_design/foo">>), + couch_db:close(Db), + case (couch_util:get_value(compact_running, ViewInfo) =:= true) orelse + (couch_util:get_value(compact_running, DbInfo) =:= true) of + false -> + Parent ! {done, self()}; + true -> + ok = timer:sleep(?DELAY), + wait_loop(DbName, Parent) + end. diff --git a/test/etap/220-compaction-daemon.t b/test/etap/220-compaction-daemon.t deleted file mode 100755 index 4c63b66b4..000000000 --- a/test/etap/220-compaction-daemon.t +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env escript -%% -*- erlang -*- - -% 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. - --record(user_ctx, { - name = null, - roles = [], - handler -}). - -test_db_name() -> - <<"couch_test_compaction_daemon">>. - -main(_) -> - test_util:init_code_path(), - - etap:plan(10), - case (catch test()) of - ok -> - etap:end_tests(); - Other -> - etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), - etap:bail(Other) - end, - ok. - -test() -> - couch_server_sup:start_link(test_util:config_files()), - timer:sleep(1000), - put(addr, couch_config:get("httpd", "bind_address", "127.0.0.1")), - put(port, integer_to_list(mochiweb_socket_server:get(couch_httpd, port))), - - disable_compact_daemon(), - - delete_db(), - {ok, Db} = create_db(), - - add_design_doc(Db), - couch_db:close(Db), - populate(70, 70, 200 * 1024), - - {_, DbFileSize} = get_db_frag(), - {_, ViewFileSize} = get_view_frag(), - - % enable automatic compaction - ok = couch_config:set("compaction_daemon", "check_interval", "3", false), - ok = couch_config:set("compaction_daemon", "min_file_size", "100000", false), - ok = couch_config:set( - "compactions", - binary_to_list(test_db_name()), - "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]", - false), - - ok = timer:sleep(4000), % something >= check_interval - wait_compaction_finished(), - - {DbFrag2, DbFileSize2} = get_db_frag(), - {ViewFrag2, ViewFileSize2} = get_view_frag(), - - etap:is(true, (DbFrag2 < 70), "Database fragmentation is < 70% after compaction"), - etap:is(true, (ViewFrag2 < 70), "View fragmentation is < 70% after compaction"), - etap:is(true, (DbFileSize2 < DbFileSize), "Database file size decreased"), - etap:is(true, (ViewFileSize2 < ViewFileSize), "View file size decreased"), - - disable_compact_daemon(), - ok = timer:sleep(6000), % 2 times check_interval - etap:is(couch_db:is_idle(Db), true, "Database is idle"), - populate(70, 70, 200 * 1024), - {_, DbFileSize3} = get_db_frag(), - {_, ViewFileSize3} = get_view_frag(), - - % enable automatic compaction - ok = couch_config:set( - "compactions", - "_default", - "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]", - false), - - ok = timer:sleep(4000), % something >= check_interval - wait_compaction_finished(), - - {DbFrag4, DbFileSize4} = get_db_frag(), - {ViewFrag4, ViewFileSize4} = get_view_frag(), - - etap:is(true, (DbFrag4 < 70), "Database fragmentation is < 70% after compaction"), - etap:is(true, (ViewFrag4 < 70), "View fragmentation is < 70% after compaction"), - etap:is(true, (DbFileSize4 < DbFileSize3), "Database file size decreased again"), - etap:is(true, (ViewFileSize4 < ViewFileSize3), "View file size decreased again"), - - ok = timer:sleep(6000), % 2 times check_interval - etap:is(couch_db:is_idle(Db), true, "Database is idle"), - - delete_db(), - couch_server_sup:stop(), - ok. - -disable_compact_daemon() -> - Configs = couch_config:get("compactions"), - lists:foreach( - fun({DbName, _}) -> - ok = couch_config:delete("compactions", DbName, false) - end, - Configs). - -admin_user_ctx() -> - {user_ctx, #user_ctx{roles = [<<"_admin">>]}}. - -create_db() -> - {ok, _} = couch_db:create(test_db_name(), [admin_user_ctx()]). - -delete_db() -> - couch_server:delete(test_db_name(), [admin_user_ctx()]). - -add_design_doc(Db) -> - DDoc = couch_doc:from_json_obj({[ - {<<"_id">>, <<"_design/foo">>}, - {<<"language">>, <<"javascript">>}, - {<<"views">>, {[ - {<<"foo">>, {[ - {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>} - ]}}, - {<<"foo2">>, {[ - {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>} - ]}}, - {<<"foo3">>, {[ - {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>} - ]}} - ]}} - ]}), - {ok, _} = couch_db:update_docs(Db, [DDoc]), - {ok, _} = couch_db:ensure_full_commit(Db), - ok. - -populate(DbFrag, ViewFrag, MinFileSize) -> - {CurDbFrag, DbFileSize} = get_db_frag(), - {CurViewFrag, ViewFileSize} = get_view_frag(), - populate( - DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag, - lists:min([DbFileSize, ViewFileSize])). - -populate(DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag, FileSize) - when CurDbFrag >= DbFrag, CurViewFrag >= ViewFrag, FileSize >= MinFileSize -> - ok; -populate(DbFrag, ViewFrag, MinFileSize, _, _, _) -> - update(), - {CurDbFrag, DbFileSize} = get_db_frag(), - {CurViewFrag, ViewFileSize} = get_view_frag(), - populate( - DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag, - lists:min([DbFileSize, ViewFileSize])). - -update() -> - {ok, Db} = couch_db:open_int(test_db_name(), []), - lists:foreach(fun(_) -> - Doc = couch_doc:from_json_obj({[{<<"_id">>, couch_uuids:new()}]}), - {ok, _} = couch_db:update_docs(Db, [Doc]), - query_view() - end, lists:seq(1, 100)), - couch_db:close(Db). - -db_url() -> - "http://" ++ get(addr) ++ ":" ++ get(port) ++ "/" ++ - binary_to_list(test_db_name()). - -query_view() -> - {ok, Code, _Headers, _Body} = test_util:request( - db_url() ++ "/_design/foo/_view/foo", [], get), - case Code of - 200 -> - ok; - _ -> - etap:bail("error querying view") - end. - -get_db_frag() -> - {ok, Db} = couch_db:open_int(test_db_name(), []), - {ok, Info} = couch_db:get_db_info(Db), - couch_db:close(Db), - FileSize = couch_util:get_value(disk_size, Info), - DataSize = couch_util:get_value(data_size, Info), - {round((FileSize - DataSize) / FileSize * 100), FileSize}. - -get_view_frag() -> - {ok, Db} = couch_db:open_int(test_db_name(), []), - {ok, Info} = couch_mrview:get_info(Db, <<"_design/foo">>), - couch_db:close(Db), - FileSize = couch_util:get_value(disk_size, Info), - DataSize = couch_util:get_value(data_size, Info), - {round((FileSize - DataSize) / FileSize * 100), FileSize}. - - -wait_compaction_finished() -> - Parent = self(), - Loop = spawn_link(fun() -> wait_loop(Parent) end), - receive - {done, Loop} -> - etap:diag("Database and view compaction have finished") - after 60000 -> - etap:bail("Compaction not triggered") - end. - -wait_loop(Parent) -> - {ok, Db} = couch_db:open_int(test_db_name(), []), - {ok, DbInfo} = couch_db:get_db_info(Db), - {ok, ViewInfo} = couch_mrview:get_info(Db, <<"_design/foo">>), - couch_db:close(Db), - case (couch_util:get_value(compact_running, ViewInfo) =:= true) orelse - (couch_util:get_value(compact_running, DbInfo) =:= true) of - false -> - Parent ! {done, self()}; - true -> - ok = timer:sleep(500), - wait_loop(Parent) - end. diff --git a/test/etap/Makefile.am b/test/etap/Makefile.am index 28876d363..e05a0ad13 100644 --- a/test/etap/Makefile.am +++ b/test/etap/Makefile.am @@ -32,7 +32,6 @@ fixture_files = \ fixtures/test.couch tap_files = \ - 220-compaction-daemon.t \ 230-pbkfd2.t \ 231-cors.t \ 250-upgrade-legacy-view-files.t |