From 1ac66234d0e1481b32701503be5f2da28c81fd8b Mon Sep 17 00:00:00 2001 From: Brad Anderson Date: Thu, 19 Aug 2010 17:51:06 -0400 Subject: Cloudant changes to etap tests --- apps/couch/test/etap/002-icu-driver.t | 2 +- apps/couch/test/etap/020-btree-basics.t | 1 + apps/couch/test/etap/021-btree-reductions.t | 3 +- apps/couch/test/etap/030-doc-from-json.t | 5 - apps/couch/test/etap/031-doc-to-json.t | 14 +- apps/couch/test/etap/041-uuid-gen.t | 24 +- apps/couch/test/etap/050-stream.t | 3 +- apps/couch/test/etap/070-couch-db.t | 75 --- apps/couch/test/etap/080-config-get-set.ini | 8 + apps/couch/test/etap/080-config-get-set.t | 3 +- apps/couch/test/etap/081-config-default.ini | 6 + apps/couch/test/etap/081-config-override.t | 7 +- apps/couch/test/etap/082-config-default.ini | 6 + apps/couch/test/etap/082-config-register.t | 3 +- apps/couch/test/etap/083-config-no-files.t | 3 +- apps/couch/test/etap/110-replication-httpc.t | 134 ---- .../couch/test/etap/111-replication-changes-feed.t | 254 -------- .../couch/test/etap/112-replication-missing-revs.t | 195 ------ .../test/etap/113-replication-attachment-comp.t | 273 -------- apps/couch/test/etap/120-stats-collect.inactive | 150 +++++ apps/couch/test/etap/120-stats-collect.t | 150 ----- apps/couch/test/etap/121-stats-aggregates.inactive | 171 +++++ apps/couch/test/etap/121-stats-aggregates.t | 171 ----- apps/couch/test/etap/130-attachments-md5.t | 252 -------- apps/couch/test/etap/140-attachment-comp.t | 711 --------------------- apps/couch/test/etap/150-invalid-view-seq.t | 192 ------ apps/couch/test/etap/160-vhosts.t | 131 ---- 27 files changed, 372 insertions(+), 2575 deletions(-) delete mode 100755 apps/couch/test/etap/070-couch-db.t create mode 100644 apps/couch/test/etap/080-config-get-set.ini create mode 100644 apps/couch/test/etap/081-config-default.ini create mode 100644 apps/couch/test/etap/082-config-default.ini delete mode 100755 apps/couch/test/etap/110-replication-httpc.t delete mode 100755 apps/couch/test/etap/111-replication-changes-feed.t delete mode 100755 apps/couch/test/etap/112-replication-missing-revs.t delete mode 100755 apps/couch/test/etap/113-replication-attachment-comp.t create mode 100755 apps/couch/test/etap/120-stats-collect.inactive delete mode 100755 apps/couch/test/etap/120-stats-collect.t create mode 100755 apps/couch/test/etap/121-stats-aggregates.inactive delete mode 100755 apps/couch/test/etap/121-stats-aggregates.t delete mode 100755 apps/couch/test/etap/130-attachments-md5.t delete mode 100755 apps/couch/test/etap/140-attachment-comp.t delete mode 100755 apps/couch/test/etap/150-invalid-view-seq.t delete mode 100755 apps/couch/test/etap/160-vhosts.t (limited to 'apps/couch/test') diff --git a/apps/couch/test/etap/002-icu-driver.t b/apps/couch/test/etap/002-icu-driver.t index d70f3303..4167aeeb 100644 --- a/apps/couch/test/etap/002-icu-driver.t +++ b/apps/couch/test/etap/002-icu-driver.t @@ -16,7 +16,7 @@ main(_) -> test_util:init_code_path(), etap:plan(3), etap:is( - couch_util:start_driver("src/couchdb/priv/.libs"), + erl_ddll:load(code:priv_dir(couch), "couch_icu_driver"), ok, "Started couch_icu_driver." ), diff --git a/apps/couch/test/etap/020-btree-basics.t b/apps/couch/test/etap/020-btree-basics.t index 18c4a836..996d240a 100755 --- a/apps/couch/test/etap/020-btree-basics.t +++ b/apps/couch/test/etap/020-btree-basics.t @@ -21,6 +21,7 @@ rows() -> 250. main(_) -> test_util:init_code_path(), + couch_config:start_link([]), etap:plan(48), case (catch test()) of ok -> diff --git a/apps/couch/test/etap/021-btree-reductions.t b/apps/couch/test/etap/021-btree-reductions.t index 3e19c767..30ffd530 100755 --- a/apps/couch/test/etap/021-btree-reductions.t +++ b/apps/couch/test/etap/021-btree-reductions.t @@ -14,11 +14,12 @@ % License for the specific language governing permissions and limitations under % the License. -filename() -> "./test/etap/temp.021". +filename() -> "./apps/couch/test/etap/temp.021". rows() -> 1000. main(_) -> test_util:init_code_path(), + couch_config:start_link([]), etap:plan(8), case (catch test()) of ok -> diff --git a/apps/couch/test/etap/030-doc-from-json.t b/apps/couch/test/etap/030-doc-from-json.t index c4ef649a..8dd5fa1e 100755 --- a/apps/couch/test/etap/030-doc-from-json.t +++ b/apps/couch/test/etap/030-doc-from-json.t @@ -20,9 +20,6 @@ -record(att, {name, type, att_len, disk_len, md5= <<>>, revpos=0, data, encoding=identity}). -default_config() -> - test_util:build_file("etc/couchdb/default_dev.ini"). - main(_) -> test_util:init_code_path(), etap:plan(26), @@ -36,8 +33,6 @@ main(_) -> ok. test() -> - couch_config:start_link([default_config()]), - couch_config:set("attachments", "compression_level", "0"), ok = test_from_json_success(), ok = test_from_json_errors(), ok. diff --git a/apps/couch/test/etap/031-doc-to-json.t b/apps/couch/test/etap/031-doc-to-json.t index 605a6d00..6f2ae7a2 100755 --- a/apps/couch/test/etap/031-doc-to-json.t +++ b/apps/couch/test/etap/031-doc-to-json.t @@ -20,9 +20,6 @@ -record(att, {name, type, att_len, disk_len, md5= <<>>, revpos=0, data, encoding=identity}). -default_config() -> - test_util:build_file("etc/couchdb/default_dev.ini"). - main(_) -> test_util:init_code_path(), etap:plan(12), @@ -36,8 +33,6 @@ main(_) -> ok. test() -> - couch_config:start_link([default_config()]), - couch_config:set("attachments", "compression_level", "0"), ok = test_to_json_success(), ok. @@ -118,16 +113,16 @@ test_to_json_success() -> { #doc{atts=[ #att{ - name = <<"big.xml">>, - type = <<"xml/sucks">>, + 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">>, + name = <<"fast.json">>, + type = <<"json/ftw">>, data = <<"{\"so\": \"there!\"}">>, revpos = 1, att_len = 16, @@ -197,4 +192,3 @@ test_to_json_success() -> etap:is(couch_doc:to_json_obj(Doc, Options), EJson, Mesg) end, Cases), ok. - diff --git a/apps/couch/test/etap/041-uuid-gen.t b/apps/couch/test/etap/041-uuid-gen.t index 1e6aa9ee..84c93a44 100755 --- a/apps/couch/test/etap/041-uuid-gen.t +++ b/apps/couch/test/etap/041-uuid-gen.t @@ -13,17 +13,15 @@ % License for the specific language governing permissions and limitations under % the License. -default_config() -> - test_util:build_file("etc/couchdb/default_dev.ini"). - seq_alg_config() -> - test_util:source_file("test/etap/041-uuid-gen-seq.ini"). + filename:join([code:lib_dir(couch, test), "etap/041-uuid-gen-seq.ini"]). utc_alg_config() -> - test_util:source_file("test/etap/041-uuid-gen-utc.ini"). + filename:join([code:lib_dir(couch, test), "etap/041-uuid-gen-utc.ini"]). % Run tests and wait for the gen_servers to shutdown run_test(IniFiles, Test) -> + couch_config_event:start_link(), {ok, Pid} = couch_config:start_link(IniFiles), erlang:monitor(process, Pid), couch_uuids:start(), @@ -40,7 +38,7 @@ run_test(IniFiles, Test) -> main(_) -> test_util:init_code_path(), application:start(crypto), - etap:plan(6), + etap:plan(5), case (catch test()) of ok -> @@ -60,9 +58,9 @@ test() -> "Can generate 10K unique IDs" ) end, - run_test([default_config()], TestUnique), - run_test([default_config(), seq_alg_config()], TestUnique), - run_test([default_config(), utc_alg_config()], TestUnique), + %run_test([default_config()], TestUnique), + run_test([seq_alg_config()], TestUnique), + run_test([utc_alg_config()], TestUnique), TestMonotonic = fun () -> etap:is( @@ -71,8 +69,8 @@ test() -> "should produce monotonically increasing ids" ) end, - run_test([default_config(), seq_alg_config()], TestMonotonic), - run_test([default_config(), utc_alg_config()], TestMonotonic), + run_test([seq_alg_config()], TestMonotonic), + run_test([utc_alg_config()], TestMonotonic), % Pretty sure that the average of a uniform distribution is the % midpoint of the range. Thus, to exceed a threshold, we need @@ -87,14 +85,14 @@ test() -> UUID = binary_to_list(couch_uuids:new()), Prefix = element(1, lists:split(26, UUID)), N = gen_until_pref_change(Prefix,0), - etap:diag("N is: ~p~n",[N]), + etap:diag("N is: ~p~n",[N]), etap:is( N >= 5000 andalso N =< 11000, true, "should roll over every so often." ) end, - run_test([default_config(), seq_alg_config()], TestRollOver). + run_test([seq_alg_config()], TestRollOver). test_unique(0, _) -> true; diff --git a/apps/couch/test/etap/050-stream.t b/apps/couch/test/etap/050-stream.t index 545dd524..03949690 100755 --- a/apps/couch/test/etap/050-stream.t +++ b/apps/couch/test/etap/050-stream.t @@ -30,7 +30,8 @@ read_all(Fd, PosList) -> iolist_to_binary(Data). test() -> - {ok, Fd} = couch_file:open("test/etap/temp.050", [create,overwrite]), + {ok, Fd} = couch_file:open("apps/couch/test/etap/temp.050", + [create,overwrite]), {ok, Stream} = couch_stream:open(Fd), etap:is(ok, couch_stream:write(Stream, <<"food">>), diff --git a/apps/couch/test/etap/070-couch-db.t b/apps/couch/test/etap/070-couch-db.t deleted file mode 100755 index 4b14aba6..00000000 --- a/apps/couch/test/etap/070-couch-db.t +++ /dev/null @@ -1,75 +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. - -main(_) -> - test_util:init_code_path(), - - etap:plan(4), - 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( - ["etc/couchdb/default_dev.ini", "etc/couchdb/local_dev.ini"] - ), - - couch_db:create(<<"etap-test-db">>, []), - {ok, AllDbs} = couch_server:all_databases(), - etap:ok(lists:member(<<"etap-test-db">>, AllDbs), "Database was created."), - - couch_server:delete(<<"etap-test-db">>, []), - {ok, AllDbs2} = couch_server:all_databases(), - etap:ok(not lists:member(<<"etap-test-db">>, AllDbs2), - "Database was deleted."), - - gen_server:call(couch_server, {set_max_dbs_open, 3}), - MkDbName = fun(Int) -> list_to_binary("lru-" ++ integer_to_list(Int)) end, - - lists:foreach(fun(Int) -> - {ok, TestDbs} = couch_server:all_databases(), - ok = case lists:member(MkDbName(Int), TestDbs) of - true -> couch_server:delete(MkDbName(Int), []); - _ -> ok - end, - {ok, Db} = couch_db:create(MkDbName(Int), []), - ok = couch_db:close(Db) - end, lists:seq(1, 6)), - - {ok, AllDbs3} = couch_server:all_databases(), - NumCreated = lists:foldl(fun(Int, Acc) -> - true = lists:member(MkDbName(Int), AllDbs3), - Acc+1 - end, 0, lists:seq(1, 6)), - etap:is(6, NumCreated, "Created all databases."), - - lists:foreach(fun(Int) -> - ok = couch_server:delete(MkDbName(Int), []) - end, lists:seq(1, 6)), - - {ok, AllDbs4} = couch_server:all_databases(), - NumDeleted = lists:foldl(fun(Int, Acc) -> - false = lists:member(MkDbName(Int), AllDbs4), - Acc+1 - end, 0, lists:seq(1, 6)), - etap:is(6, NumDeleted, "Deleted all databases."), - - ok. diff --git a/apps/couch/test/etap/080-config-get-set.ini b/apps/couch/test/etap/080-config-get-set.ini new file mode 100644 index 00000000..e72e08db --- /dev/null +++ b/apps/couch/test/etap/080-config-get-set.ini @@ -0,0 +1,8 @@ +[daemons] +something=somevalue + +[httpd_design_handlers] +_view = {couch_httpd_view, handle_view_req} + +[httpd] +port = 5984 diff --git a/apps/couch/test/etap/080-config-get-set.t b/apps/couch/test/etap/080-config-get-set.t index a4a8577a..c457c7f0 100755 --- a/apps/couch/test/etap/080-config-get-set.t +++ b/apps/couch/test/etap/080-config-get-set.t @@ -14,7 +14,7 @@ % the License. default_config() -> - test_util:build_file("etc/couchdb/default_dev.ini"). + filename:join([code:lib_dir(couch, test), "etap/080-config-get-set.ini"]). main(_) -> test_util:init_code_path(), @@ -30,6 +30,7 @@ main(_) -> test() -> % start couch_config with default + couch_config_event:start_link(), couch_config:start_link([default_config()]), diff --git a/apps/couch/test/etap/081-config-default.ini b/apps/couch/test/etap/081-config-default.ini new file mode 100644 index 00000000..abdf79bc --- /dev/null +++ b/apps/couch/test/etap/081-config-default.ini @@ -0,0 +1,6 @@ +[couchdb] +max_dbs_open=100 + +[httpd] +port=5984 +bind_address = 127.0.0.1 diff --git a/apps/couch/test/etap/081-config-override.t b/apps/couch/test/etap/081-config-override.t index 01f8b4c2..16a6b6f6 100755 --- a/apps/couch/test/etap/081-config-override.t +++ b/apps/couch/test/etap/081-config-override.t @@ -14,19 +14,20 @@ % the License. default_config() -> - test_util:build_file("etc/couchdb/default_dev.ini"). + filename:join([code:lib_dir(couch, test),"etap/081-config-default.ini"]). local_config_1() -> - test_util:source_file("test/etap/081-config-override.1.ini"). + filename:join([code:lib_dir(couch, test),"etap/081-config-override.1.ini"]). local_config_2() -> - test_util:source_file("test/etap/081-config-override.2.ini"). + filename:join([code:lib_dir(couch, test),"etap/081-config-override.2.ini"]). local_config_write() -> test_util:build_file("test/etap/temp.081"). % Run tests and wait for the config gen_server to shutdown. run_tests(IniFiles, Tests) -> + couch_config_event:start_link(), {ok, Pid} = couch_config:start_link(IniFiles), erlang:monitor(process, Pid), Tests(), diff --git a/apps/couch/test/etap/082-config-default.ini b/apps/couch/test/etap/082-config-default.ini new file mode 100644 index 00000000..e46f158f --- /dev/null +++ b/apps/couch/test/etap/082-config-default.ini @@ -0,0 +1,6 @@ +[couchdb] +max_dbs_open=500 + +[httpd] +port=5984 +bind_address = 127.0.0.1 diff --git a/apps/couch/test/etap/082-config-register.t b/apps/couch/test/etap/082-config-register.t index 191ba8f8..36b48cf8 100755 --- a/apps/couch/test/etap/082-config-register.t +++ b/apps/couch/test/etap/082-config-register.t @@ -14,7 +14,7 @@ % the License. default_config() -> - test_util:build_file("etc/couchdb/default_dev.ini"). + filename:join([code:lib_dir(couch, test), "etap/082-config-default.ini"]). main(_) -> test_util:init_code_path(), @@ -29,6 +29,7 @@ main(_) -> ok. test() -> + couch_config_event:start_link(), couch_config:start_link([default_config()]), etap:is( diff --git a/apps/couch/test/etap/083-config-no-files.t b/apps/couch/test/etap/083-config-no-files.t index 675feb59..edf8315d 100755 --- a/apps/couch/test/etap/083-config-no-files.t +++ b/apps/couch/test/etap/083-config-no-files.t @@ -14,7 +14,7 @@ % the License. default_config() -> - test_util:build_file("etc/couchdb/default_dev.ini"). + "rel/overlay/etc/default.ini". main(_) -> test_util:init_code_path(), @@ -29,6 +29,7 @@ main(_) -> ok. test() -> + couch_config_event:start_link(), couch_config:start_link([]), etap:fun_is( diff --git a/apps/couch/test/etap/110-replication-httpc.t b/apps/couch/test/etap/110-replication-httpc.t deleted file mode 100755 index b534b648..00000000 --- a/apps/couch/test/etap/110-replication-httpc.t +++ /dev/null @@ -1,134 +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. - -%% XXX: Figure out how to -include("couch_rep.hrl") --record(http_db, { - url, - auth = [], - resource = "", - headers = [ - {"User-Agent", "CouchDB/"++couch:version()}, - {"Accept", "application/json"}, - {"Accept-Encoding", "gzip"} - ], - qs = [], - method = get, - body = nil, - options = [ - {response_format,binary}, - {inactivity_timeout, 30000} - ], - retries = 10, - pause = 1, - conn = nil -}). - -server() -> "http://127.0.0.1:5984/". -dbname() -> "etap-test-db". - -config_files() -> - lists:map(fun test_util:build_file/1, [ - "etc/couchdb/default_dev.ini", - "etc/couchdb/local_dev.ini" - ]). - -main(_) -> - test_util:init_code_path(), - - etap:plan(6), - 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(config_files()), - ibrowse:start(), - crypto:start(), - - couch_server:delete(list_to_binary(dbname()), []), - {ok, Db} = couch_db:create(list_to_binary(dbname()), []), - - test_welcome(), - test_binary_url(), - test_put(), - test_qs(), - test_db_exists(), - - couch_db:close(Db), - couch_server:delete(list_to_binary(dbname()), []), - ok. - -test_welcome() -> - WelcomeReq = #http_db{url=server()}, - Expect = {[ - {<<"couchdb">>, <<"Welcome">>}, - {<<"version">>, list_to_binary(couch:version())} - ]}, - etap:is( - couch_rep_httpc:request(WelcomeReq), - Expect, - "welcome request with url-as-list" - ). - -test_binary_url() -> - Req = #http_db{url=list_to_binary(server())}, - Expect = {[ - {<<"couchdb">>, <<"Welcome">>}, - {<<"version">>, list_to_binary(couch:version())} - ]}, - etap:is( - couch_rep_httpc:request(Req), - Expect, - "welcome request with url-as-binary" - ). - -test_put() -> - Req = #http_db{ - url = server() ++ dbname() ++ "/", - resource = "test_put", - body = {[{<<"foo">>, <<"bar">>}]}, - method = put - }, - {Resp} = couch_rep_httpc:request(Req), - etap:ok(couch_util:get_value(<<"ok">>, Resp), "ok:true on upload"), - etap:is(<<"test_put">>, couch_util:get_value(<<"id">>, Resp), "id is correct"). - -test_qs() -> - Req = #http_db{ - url = server() ++ dbname() ++ "/", - resource = "foo", - qs = [ - {bar, true}, - {baz, 1.03}, - {bif, mochijson2:encode(<<"1-23456">>)} - ] - }, - Expect = server() ++ dbname() ++ "/foo?bar=true&baz=1.03&bif=\"1-23456\"", - etap:is( - couch_rep_httpc:full_url(Req), - Expect, - "query-string proplist encoding ok" - ). - -test_db_exists() -> - Req1 = #http_db{url=server() ++ dbname() ++ "/"}, - Req2 = #http_db{url=server() ++ dbname() ++ "_foo/"}, - etap:is(couch_rep_httpc:db_exists(Req1), Req1, "db_exists true check"). - % etap:is(couch_rep_httpc:db_exists(Req2), false, "db_exists false check"). diff --git a/apps/couch/test/etap/111-replication-changes-feed.t b/apps/couch/test/etap/111-replication-changes-feed.t deleted file mode 100755 index bca12bc7..00000000 --- a/apps/couch/test/etap/111-replication-changes-feed.t +++ /dev/null @@ -1,254 +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. - -%% XXX: Figure out how to -include("couch_db.hrl") --record(doc, {id= <<"">>, revs={0, []}, body={[]}, - attachments=[], deleted=false, meta=[]}). - --record(http_db, { - url, - auth = [], - resource = "", - headers = [ - {"User-Agent", "CouchDB/"++couch:version()}, - {"Accept", "application/json"}, - {"Accept-Encoding", "gzip"} - ], - qs = [], - method = get, - body = nil, - options = [ - {response_format,binary}, - {inactivity_timeout, 30000} - ], - retries = 10, - pause = 1, - conn = nil -}). - -config_files() -> - lists:map(fun test_util:build_file/1, [ - "etc/couchdb/default_dev.ini", - "etc/couchdb/local_dev.ini" - ]). - -main(_) -> - test_util:init_code_path(), - - etap:plan(13), - 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(config_files()), - ibrowse:start(), - crypto:start(), - - couch_server:delete(<<"etap-test-db">>, []), - {ok, Db1} = couch_db:create(<<"etap-test-db">>, []), - test_all(local), - couch_db:close(Db1), - couch_server:delete(<<"etap-test-db">>, []), - - couch_server:delete(<<"etap-test-db">>, []), - {ok, Db2} = couch_db:create(<<"etap-test-db">>, []), - test_all(remote), - test_remote_only(), - couch_db:close(Db2), - couch_server:delete(<<"etap-test-db">>, []), - - ok. - -test_all(Type) -> - test_unchanged_db(Type), - test_simple_change(Type), - test_since_parameter(Type), - test_continuous_parameter(Type), - test_conflicts(Type), - test_deleted_conflicts(Type). - -test_remote_only() -> - test_chunk_reassembly(remote). - -test_unchanged_db(Type) -> - {ok, Pid} = start_changes_feed(Type, 0, false), - etap:is( - couch_rep_changes_feed:next(Pid), - complete, - io_lib:format( - "(~p) changes feed for unchanged DB is automatically complete", - [Type]) - ). - -test_simple_change(Type) -> - Expect = generate_change(), - {ok, Pid} = start_changes_feed(Type, 0, false), - etap:is( - {couch_rep_changes_feed:next(Pid), couch_rep_changes_feed:next(Pid)}, - {[Expect], complete}, - io_lib:format("(~p) change one document, get one row", [Type]) - ). - -test_since_parameter(Type) -> - {ok, Pid} = start_changes_feed(Type, get_update_seq(), false), - etap:is( - couch_rep_changes_feed:next(Pid), - complete, - io_lib:format( - "(~p) since query-string parameter allows us to skip changes", - [Type]) - ). - -test_continuous_parameter(Type) -> - {ok, Pid} = start_changes_feed(Type, get_update_seq(), true), - - % make the changes_feed request before the next update - Self = self(), - spawn(fun() -> - Change = couch_rep_changes_feed:next(Pid), - Self ! {actual, Change} - end), - - Expect = generate_change(), - etap:is( - receive {actual, Actual} -> Actual end, - [Expect], - io_lib:format( - "(~p) feed=continuous query-string parameter picks up new changes", - [Type]) - ), - - ok = couch_rep_changes_feed:stop(Pid). - -test_conflicts(Type) -> - Since = get_update_seq(), - Expect = generate_conflict(), - {ok, Pid} = start_changes_feed(Type, Since, false), - etap:is( - {couch_rep_changes_feed:next(Pid), couch_rep_changes_feed:next(Pid)}, - {[Expect], complete}, - io_lib:format("(~p) conflict revisions show up in feed", [Type]) - ). - -test_deleted_conflicts(Type) -> - Since = get_update_seq(), - {ExpectProps} = generate_conflict(), - - %% delete the conflict revision - Id = couch_util:get_value(<<"id">>, ExpectProps), - [Win, {[{<<"rev">>, Lose}]}] = couch_util:get_value(<<"changes">>, ExpectProps), - Doc = couch_doc:from_json_obj({[ - {<<"_id">>, Id}, - {<<"_rev">>, Lose}, - {<<"_deleted">>, true} - ]}), - Db = get_db(), - {ok, Rev} = couch_db:update_doc(Db, Doc, [full_commit]), - couch_db:close(Db), - - Expect = {[ - {<<"seq">>, get_update_seq()}, - {<<"id">>, Id}, - {<<"changes">>, [Win, {[{<<"rev">>, couch_doc:rev_to_str(Rev)}]}]} - ]}, - - {ok, Pid} = start_changes_feed(Type, Since, false), - etap:is( - {couch_rep_changes_feed:next(Pid), couch_rep_changes_feed:next(Pid)}, - {[Expect], complete}, - io_lib:format("(~p) deleted conflict revisions show up in feed", [Type]) - ). - -test_chunk_reassembly(Type) -> - Since = get_update_seq(), - Expect = [generate_change() || _I <- lists:seq(1,30)], - {ok, Pid} = start_changes_feed(Type, Since, false), - etap:is( - get_all_changes(Pid, []), - Expect, - io_lib:format("(~p) reassembles chunks split across TCP frames", - [Type]) - ). - -get_all_changes(Pid, Acc) -> - case couch_rep_changes_feed:next(Pid) of - complete -> - lists:flatten(lists:reverse(Acc)); - Else -> - get_all_changes(Pid, [Else|Acc]) - end. - -generate_change() -> - generate_change(couch_uuids:random()). - -generate_change(Id) -> - generate_change(Id, {[]}). - -generate_change(Id, EJson) -> - Doc = couch_doc:from_json_obj(EJson), - Db = get_db(), - {ok, Rev} = couch_db:update_doc(Db, Doc#doc{id = Id}, [full_commit]), - couch_db:close(Db), - {[ - {<<"seq">>, get_update_seq()}, - {<<"id">>, Id}, - {<<"changes">>, [{[{<<"rev">>, couch_doc:rev_to_str(Rev)}]}]} - ]}. - -generate_conflict() -> - Id = couch_uuids:random(), - Db = get_db(), - Doc1 = (couch_doc:from_json_obj({[<<"foo">>, <<"bar">>]}))#doc{id = Id}, - Doc2 = (couch_doc:from_json_obj({[<<"foo">>, <<"baz">>]}))#doc{id = Id}, - {ok, Rev1} = couch_db:update_doc(Db, Doc1, [full_commit]), - {ok, Rev2} = couch_db:update_doc(Db, Doc2, [full_commit, all_or_nothing]), - - %% relies on undocumented CouchDB conflict winner algo and revision sorting! - RevList = [{[{<<"rev">>, couch_doc:rev_to_str(R)}]} || R - <- lists:sort(fun(A,B) -> B>, get_update_seq()}, - {<<"id">>, Id}, - {<<"changes">>, RevList} - ]}. - -get_db() -> - {ok, Db} = couch_db:open(<<"etap-test-db">>, []), - Db. - -get_dbname(local) -> - "etap-test-db"; -get_dbname(remote) -> - "http://127.0.0.1:5984/etap-test-db/". - -get_update_seq() -> - Db = get_db(), - Seq = couch_db:get_update_seq(Db), - couch_db:close(Db), - Seq. - -start_changes_feed(local, Since, Continuous) -> - Props = [{<<"continuous">>, Continuous}], - couch_rep_changes_feed:start_link(self(), get_db(), Since, Props); -start_changes_feed(remote, Since, Continuous) -> - Props = [{<<"continuous">>, Continuous}], - Db = #http_db{url = get_dbname(remote)}, - couch_rep_changes_feed:start_link(self(), Db, Since, Props). diff --git a/apps/couch/test/etap/112-replication-missing-revs.t b/apps/couch/test/etap/112-replication-missing-revs.t deleted file mode 100755 index ea8466f6..00000000 --- a/apps/couch/test/etap/112-replication-missing-revs.t +++ /dev/null @@ -1,195 +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. - -%% XXX: Figure out how to -include("couch_db.hrl") - --record(doc, {id= <<"">>, revs={0, []}, body={[]}, - attachments=[], deleted=false, meta=[]}). - --record(http_db, { - url, - auth = [], - resource = "", - headers = [ - {"User-Agent", "CouchDB/"++couch:version()}, - {"Accept", "application/json"}, - {"Accept-Encoding", "gzip"} - ], - qs = [], - method = get, - body = nil, - options = [ - {response_format,binary}, - {inactivity_timeout, 30000} - ], - retries = 10, - pause = 1, - conn = nil -}). - -config_files() -> - lists:map(fun test_util:build_file/1, [ - "etc/couchdb/default_dev.ini", - "etc/couchdb/local_dev.ini" - ]). - -main(_) -> - test_util:init_code_path(), - - etap:plan(12), - 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(config_files()), - ibrowse:start(), - crypto:start(), - - couch_server:delete(<<"etap-test-source">>, []), - couch_server:delete(<<"etap-test-target">>, []), - - Dbs1 = setup(), - test_all(local, local), - ok = teardown(Dbs1), - - Dbs2 = setup(), - test_all(local, remote), - ok = teardown(Dbs2), - - Dbs3 = setup(), - test_all(remote, local), - ok = teardown(Dbs3), - - Dbs4 = setup(), - test_all(remote, remote), - ok = teardown(Dbs4), - - ok. - -test_all(SrcType, TgtType) -> - test_unchanged_db(SrcType, TgtType), - test_multiple_changes(SrcType, TgtType), - test_changes_not_missing(SrcType, TgtType). - -test_unchanged_db(SrcType, TgtType) -> - {ok, Pid1} = start_changes_feed(SrcType, 0, false), - {ok, Pid2} = start_missing_revs(TgtType, Pid1), - etap:is( - couch_rep_missing_revs:next(Pid2), - complete, - io_lib:format( - "(~p, ~p) no missing revs if source is unchanged", - [SrcType, TgtType]) - ). - -test_multiple_changes(SrcType, TgtType) -> - Expect = {2, [generate_change(), generate_change()]}, - {ok, Pid1} = start_changes_feed(SrcType, 0, false), - {ok, Pid2} = start_missing_revs(TgtType, Pid1), - etap:is( - get_all_missing_revs(Pid2, {0, []}), - Expect, - io_lib:format("(~p, ~p) add src docs, get missing tgt revs + high seq", - [SrcType, TgtType]) - ). - -test_changes_not_missing(SrcType, TgtType) -> - %% put identical changes on source and target - Id = couch_uuids:random(), - {Id, _Seq, [Rev]} = Expect = generate_change(Id, {[]}, get_db(source)), - {Id, _, [Rev]} = generate_change(Id, {[]}, get_db(target)), - - %% confirm that this change is not in missing revs feed - {ok, Pid1} = start_changes_feed(SrcType, 0, false), - {ok, Pid2} = start_missing_revs(TgtType, Pid1), - {HighSeq, AllRevs} = get_all_missing_revs(Pid2, {0, []}), - - %% etap:none/3 has a bug, so just define it correctly here - etap:is( - lists:member(Expect, AllRevs), - false, - io_lib:format( - "(~p, ~p) skip revs that already exist on target", - [SrcType, TgtType]) - ). - -generate_change() -> - generate_change(couch_uuids:random()). - -generate_change(Id) -> - generate_change(Id, {[]}). - -generate_change(Id, EJson) -> - generate_change(Id, EJson, get_db(source)). - -generate_change(Id, EJson, Db) -> - Doc = couch_doc:from_json_obj(EJson), - Seq = get_update_seq(), - {ok, Rev} = couch_db:update_doc(Db, Doc#doc{id = Id}, [full_commit]), - couch_db:close(Db), - {Id, Seq+1, [Rev]}. - -get_all_missing_revs(Pid, {HighSeq, Revs}) -> - case couch_rep_missing_revs:next(Pid) of - complete -> - {HighSeq, lists:flatten(lists:reverse(Revs))}; - {Seq, More} -> - get_all_missing_revs(Pid, {Seq, [More|Revs]}) - end. - -get_db(source) -> - {ok, Db} = couch_db:open(<<"etap-test-source">>, []), - Db; -get_db(target) -> - {ok, Db} = couch_db:open(<<"etap-test-target">>, []), - Db. - -get_update_seq() -> - Db = get_db(source), - Seq = couch_db:get_update_seq(Db), - couch_db:close(Db), - Seq. - -setup() -> - {ok, DbA} = couch_db:create(<<"etap-test-source">>, []), - {ok, DbB} = couch_db:create(<<"etap-test-target">>, []), - [DbA, DbB]. - -teardown([DbA, DbB]) -> - couch_db:close(DbA), - couch_db:close(DbB), - couch_server:delete(<<"etap-test-source">>, []), - couch_server:delete(<<"etap-test-target">>, []), - ok. - -start_changes_feed(local, Since, Continuous) -> - Props = [{<<"continuous">>, Continuous}], - couch_rep_changes_feed:start_link(self(), get_db(source), Since, Props); -start_changes_feed(remote, Since, Continuous) -> - Props = [{<<"continuous">>, Continuous}], - Db = #http_db{url = "http://127.0.0.1:5984/etap-test-source/"}, - couch_rep_changes_feed:start_link(self(), Db, Since, Props). - -start_missing_revs(local, Changes) -> - couch_rep_missing_revs:start_link(self(), get_db(target), Changes, []); -start_missing_revs(remote, Changes) -> - Db = #http_db{url = "http://127.0.0.1:5984/etap-test-target/"}, - couch_rep_missing_revs:start_link(self(), Db, Changes, []). diff --git a/apps/couch/test/etap/113-replication-attachment-comp.t b/apps/couch/test/etap/113-replication-attachment-comp.t deleted file mode 100755 index 30f602ef..00000000 --- a/apps/couch/test/etap/113-replication-attachment-comp.t +++ /dev/null @@ -1,273 +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 -}). - -default_config() -> - test_util:build_file("etc/couchdb/default_dev.ini"). - -test_db_a_name() -> - <<"couch_test_rep_att_comp_a">>. - -test_db_b_name() -> - <<"couch_test_rep_att_comp_b">>. - -main(_) -> - test_util:init_code_path(), - etap:plan(30), - 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([default_config()]), - put(addr, couch_config:get("httpd", "bind_address", "127.0.0.1")), - put(port, couch_config:get("httpd", "port", "5984")), - application:start(inets), - ibrowse:start(), - timer:sleep(1000), - - % - % test pull replication - % - - delete_db(test_db_a_name()), - delete_db(test_db_b_name()), - create_db(test_db_a_name()), - create_db(test_db_b_name()), - - % enable compression - couch_config:set("attachments", "compression_level", "8"), - couch_config:set("attachments", "compressible_types", "text/*"), - - % store doc with text attachment in DB A - put_text_att(test_db_a_name()), - - % disable attachment compression - couch_config:set("attachments", "compression_level", "0"), - - % do pull replication - do_pull_replication(test_db_a_name(), test_db_b_name()), - - % verify that DB B has the attachment stored in compressed form - check_att_is_compressed(test_db_b_name()), - check_server_can_decompress_att(test_db_b_name()), - check_att_stubs(test_db_a_name(), test_db_b_name()), - - % - % test push replication - % - - delete_db(test_db_a_name()), - delete_db(test_db_b_name()), - create_db(test_db_a_name()), - create_db(test_db_b_name()), - - % enable compression - couch_config:set("attachments", "compression_level", "8"), - couch_config:set("attachments", "compressible_types", "text/*"), - - % store doc with text attachment in DB A - put_text_att(test_db_a_name()), - - % disable attachment compression - couch_config:set("attachments", "compression_level", "0"), - - % do push replication - do_push_replication(test_db_a_name(), test_db_b_name()), - - % verify that DB B has the attachment stored in compressed form - check_att_is_compressed(test_db_b_name()), - check_server_can_decompress_att(test_db_b_name()), - check_att_stubs(test_db_a_name(), test_db_b_name()), - - timer:sleep(3000), % to avoid mochiweb socket closed exceptions - delete_db(test_db_a_name()), - delete_db(test_db_b_name()), - couch_server_sup:stop(), - ok. - -put_text_att(DbName) -> - {ok, {{_, Code, _}, _Headers, _Body}} = http:request( - put, - {db_url(DbName) ++ "/testdoc1/readme.txt", [], - "text/plain", test_text_data()}, - [], - [{sync, true}]), - etap:is(Code, 201, "Created text attachment"), - ok. - -do_pull_replication(SourceDbName, TargetDbName) -> - RepObj = {[ - {<<"source">>, list_to_binary(db_url(SourceDbName))}, - {<<"target">>, TargetDbName} - ]}, - {ok, {{_, Code, _}, _Headers, Body}} = http:request( - post, - {rep_url(), [], - "application/json", list_to_binary(couch_util:json_encode(RepObj))}, - [], - [{sync, true}]), - etap:is(Code, 200, "Pull replication successfully triggered"), - Json = couch_util:json_decode(Body), - RepOk = couch_util:get_nested_json_value(Json, [<<"ok">>]), - etap:is(RepOk, true, "Pull replication completed with success"), - ok. - -do_push_replication(SourceDbName, TargetDbName) -> - RepObj = {[ - {<<"source">>, SourceDbName}, - {<<"target">>, list_to_binary(db_url(TargetDbName))} - ]}, - {ok, {{_, Code, _}, _Headers, Body}} = http:request( - post, - {rep_url(), [], - "application/json", list_to_binary(couch_util:json_encode(RepObj))}, - [], - [{sync, true}]), - etap:is(Code, 200, "Push replication successfully triggered"), - Json = couch_util:json_decode(Body), - RepOk = couch_util:get_nested_json_value(Json, [<<"ok">>]), - etap:is(RepOk, true, "Push replication completed with success"), - ok. - -check_att_is_compressed(DbName) -> - {ok, {{_, Code, _}, Headers, Body}} = http:request( - get, - {db_url(DbName) ++ "/testdoc1/readme.txt", - [{"Accept-Encoding", "gzip"}]}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code for the attachment request is 200"), - Gziped = lists:member({"content-encoding", "gzip"}, Headers), - etap:is(Gziped, true, "The attachment was received in compressed form"), - Uncompressed = binary_to_list(zlib:gunzip(list_to_binary(Body))), - etap:is( - Uncompressed, - test_text_data(), - "The attachment content is valid after decompression at the client side" - ), - ok. - -check_server_can_decompress_att(DbName) -> - {ok, {{_, Code, _}, Headers, Body}} = http:request( - get, - {db_url(DbName) ++ "/testdoc1/readme.txt", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code for the attachment request is 200"), - Gziped = lists:member({"content-encoding", "gzip"}, Headers), - etap:is( - Gziped, false, "The attachment was not received in compressed form" - ), - etap:is( - Body, - test_text_data(), - "The attachment content is valid after server decompression" - ), - ok. - -check_att_stubs(SourceDbName, TargetDbName) -> - {ok, {{_, Code1, _}, _Headers1, Body1}} = http:request( - get, - {db_url(SourceDbName) ++ "/testdoc1?att_encoding_info=true", []}, - [], - [{sync, true}]), - etap:is( - Code1, - 200, - "HTTP response code is 200 for the source DB doc request" - ), - Json1 = couch_util:json_decode(Body1), - SourceAttStub = couch_util:get_nested_json_value( - Json1, - [<<"_attachments">>, <<"readme.txt">>] - ), - {ok, {{_, Code2, _}, _Headers2, Body2}} = http:request( - get, - {db_url(TargetDbName) ++ "/testdoc1?att_encoding_info=true", []}, - [], - [{sync, true}]), - etap:is( - Code2, - 200, - "HTTP response code is 200 for the target DB doc request" - ), - Json2 = couch_util:json_decode(Body2), - TargetAttStub = couch_util:get_nested_json_value( - Json2, - [<<"_attachments">>, <<"readme.txt">>] - ), - IdenticalStubs = (SourceAttStub =:= TargetAttStub), - etap:is(IdenticalStubs, true, "Attachment stubs are identical"), - TargetAttStubLength = couch_util:get_nested_json_value( - TargetAttStub, - [<<"length">>] - ), - TargetAttStubEnc = couch_util:get_nested_json_value( - TargetAttStub, - [<<"encoding">>] - ), - etap:is( - TargetAttStubEnc, - <<"gzip">>, - "Attachment stub has encoding property set to gzip" - ), - TargetAttStubEncLength = couch_util:get_nested_json_value( - TargetAttStub, - [<<"encoded_length">>] - ), - EncLengthDefined = is_integer(TargetAttStubEncLength), - etap:is( - EncLengthDefined, - true, - "Stubs have the encoded_length field properly defined" - ), - EncLengthSmaller = (TargetAttStubEncLength < TargetAttStubLength), - etap:is( - EncLengthSmaller, - true, - "Stubs have the encoded_length field smaller than their length field" - ), - ok. - -admin_user_ctx() -> - {user_ctx, #user_ctx{roles=[<<"_admin">>]}}. - -create_db(DbName) -> - {ok, _} = couch_db:create(DbName, [admin_user_ctx()]). - -delete_db(DbName) -> - couch_server:delete(DbName, [admin_user_ctx()]). - -db_url(DbName) -> - "http://" ++ get(addr) ++ ":" ++ get(port) ++ "/" ++ - binary_to_list(DbName). - -rep_url() -> - "http://" ++ get(addr) ++ ":" ++ get(port) ++ "/_replicate". - -test_text_data() -> - {ok, Data} = file:read_file(test_util:source_file("README")), - binary_to_list(Data). diff --git a/apps/couch/test/etap/120-stats-collect.inactive b/apps/couch/test/etap/120-stats-collect.inactive new file mode 100755 index 00000000..dee88765 --- /dev/null +++ b/apps/couch/test/etap/120-stats-collect.inactive @@ -0,0 +1,150 @@ +#!/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. + +main(_) -> + test_util:init_code_path(), + etap:plan(11), + case (catch test()) of + ok -> + etap:end_tests(); + Other -> + etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), + etap:bail() + end, + ok. + +test() -> + couch_stats_collector:start(), + ok = test_counters(), + ok = test_abs_values(), + ok = test_proc_counting(), + ok = test_all(), + ok. + +test_counters() -> + AddCount = fun() -> couch_stats_collector:increment(foo) end, + RemCount = fun() -> couch_stats_collector:decrement(foo) end, + repeat(AddCount, 100), + repeat(RemCount, 25), + repeat(AddCount, 10), + repeat(RemCount, 5), + etap:is( + couch_stats_collector:get(foo), + 80, + "Incrememnt tracks correctly." + ), + + repeat(RemCount, 80), + etap:is( + couch_stats_collector:get(foo), + 0, + "Decremented to zaro." + ), + ok. + +test_abs_values() -> + lists:map(fun(Val) -> + couch_stats_collector:record(bar, Val) + end, lists:seq(1, 15)), + etap:is( + couch_stats_collector:get(bar), + lists:seq(1, 15), + "Absolute values are recorded correctly." + ), + + couch_stats_collector:clear(bar), + etap:is( + couch_stats_collector:get(bar), + nil, + "Absolute values are cleared correctly." + ), + ok. + +test_proc_counting() -> + Self = self(), + OnePid = spawn(fun() -> + couch_stats_collector:track_process_count(hoopla), + Self ! reporting, + receive sepuku -> ok end + end), + R1 = erlang:monitor(process, OnePid), + receive reporting -> ok end, + etap:is( + couch_stats_collector:get(hoopla), + 1, + "track_process_count incrememnts the counter." + ), + + TwicePid = spawn(fun() -> + couch_stats_collector:track_process_count(hoopla), + couch_stats_collector:track_process_count(hoopla), + Self ! reporting, + receive sepuku -> ok end + end), + R2 = erlang:monitor(process, TwicePid), + receive reporting -> ok end, + etap:is( + couch_stats_collector:get(hoopla), + 3, + "track_process_count allows more than one incrememnt per Pid" + ), + + OnePid ! sepuku, + receive {'DOWN', R1, _, _, _} -> ok end, + timer:sleep(250), + etap:is( + couch_stats_collector:get(hoopla), + 2, + "Process count is decremented when process exits." + ), + + TwicePid ! sepuku, + receive {'DOWN', R2, _, _, _} -> ok end, + timer:sleep(250), + etap:is( + couch_stats_collector:get(hoopla), + 0, + "Process count is decremented for each call to track_process_count." + ), + ok. + +test_all() -> + couch_stats_collector:record(bar, 0.0), + couch_stats_collector:record(bar, 1.0), + etap:is( + couch_stats_collector:all(), + [{foo, 0}, {hoopla, 0}, {bar, [1.0, 0.0]}], + "all/0 returns all counters and absolute values." + ), + + etap:is( + couch_stats_collector:all(incremental), + [{foo, 0}, {hoopla, 0}], + "all/1 returns only the specified type." + ), + + couch_stats_collector:record(zing, 90), + etap:is( + couch_stats_collector:all(absolute), + [{zing, [90]}, {bar, [1.0, 0.0]}], + "all/1 returns only the specified type." + ), + ok. + +repeat(_, 0) -> + ok; +repeat(Fun, Count) -> + Fun(), + repeat(Fun, Count-1). diff --git a/apps/couch/test/etap/120-stats-collect.t b/apps/couch/test/etap/120-stats-collect.t deleted file mode 100755 index dee88765..00000000 --- a/apps/couch/test/etap/120-stats-collect.t +++ /dev/null @@ -1,150 +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. - -main(_) -> - test_util:init_code_path(), - etap:plan(11), - case (catch test()) of - ok -> - etap:end_tests(); - Other -> - etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), - etap:bail() - end, - ok. - -test() -> - couch_stats_collector:start(), - ok = test_counters(), - ok = test_abs_values(), - ok = test_proc_counting(), - ok = test_all(), - ok. - -test_counters() -> - AddCount = fun() -> couch_stats_collector:increment(foo) end, - RemCount = fun() -> couch_stats_collector:decrement(foo) end, - repeat(AddCount, 100), - repeat(RemCount, 25), - repeat(AddCount, 10), - repeat(RemCount, 5), - etap:is( - couch_stats_collector:get(foo), - 80, - "Incrememnt tracks correctly." - ), - - repeat(RemCount, 80), - etap:is( - couch_stats_collector:get(foo), - 0, - "Decremented to zaro." - ), - ok. - -test_abs_values() -> - lists:map(fun(Val) -> - couch_stats_collector:record(bar, Val) - end, lists:seq(1, 15)), - etap:is( - couch_stats_collector:get(bar), - lists:seq(1, 15), - "Absolute values are recorded correctly." - ), - - couch_stats_collector:clear(bar), - etap:is( - couch_stats_collector:get(bar), - nil, - "Absolute values are cleared correctly." - ), - ok. - -test_proc_counting() -> - Self = self(), - OnePid = spawn(fun() -> - couch_stats_collector:track_process_count(hoopla), - Self ! reporting, - receive sepuku -> ok end - end), - R1 = erlang:monitor(process, OnePid), - receive reporting -> ok end, - etap:is( - couch_stats_collector:get(hoopla), - 1, - "track_process_count incrememnts the counter." - ), - - TwicePid = spawn(fun() -> - couch_stats_collector:track_process_count(hoopla), - couch_stats_collector:track_process_count(hoopla), - Self ! reporting, - receive sepuku -> ok end - end), - R2 = erlang:monitor(process, TwicePid), - receive reporting -> ok end, - etap:is( - couch_stats_collector:get(hoopla), - 3, - "track_process_count allows more than one incrememnt per Pid" - ), - - OnePid ! sepuku, - receive {'DOWN', R1, _, _, _} -> ok end, - timer:sleep(250), - etap:is( - couch_stats_collector:get(hoopla), - 2, - "Process count is decremented when process exits." - ), - - TwicePid ! sepuku, - receive {'DOWN', R2, _, _, _} -> ok end, - timer:sleep(250), - etap:is( - couch_stats_collector:get(hoopla), - 0, - "Process count is decremented for each call to track_process_count." - ), - ok. - -test_all() -> - couch_stats_collector:record(bar, 0.0), - couch_stats_collector:record(bar, 1.0), - etap:is( - couch_stats_collector:all(), - [{foo, 0}, {hoopla, 0}, {bar, [1.0, 0.0]}], - "all/0 returns all counters and absolute values." - ), - - etap:is( - couch_stats_collector:all(incremental), - [{foo, 0}, {hoopla, 0}], - "all/1 returns only the specified type." - ), - - couch_stats_collector:record(zing, 90), - etap:is( - couch_stats_collector:all(absolute), - [{zing, [90]}, {bar, [1.0, 0.0]}], - "all/1 returns only the specified type." - ), - ok. - -repeat(_, 0) -> - ok; -repeat(Fun, Count) -> - Fun(), - repeat(Fun, Count-1). diff --git a/apps/couch/test/etap/121-stats-aggregates.inactive b/apps/couch/test/etap/121-stats-aggregates.inactive new file mode 100755 index 00000000..d678aa9d --- /dev/null +++ b/apps/couch/test/etap/121-stats-aggregates.inactive @@ -0,0 +1,171 @@ +#!/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. + +ini_file() -> + test_util:source_file("test/etap/121-stats-aggregates.ini"). + +cfg_file() -> + test_util:source_file("test/etap/121-stats-aggregates.cfg"). + +main(_) -> + test_util:init_code_path(), + etap:plan(17), + case (catch test()) of + ok -> + etap:end_tests(); + Other -> + etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), + etap:bail() + end, + ok. + +test() -> + couch_config:start_link([ini_file()]), + couch_stats_collector:start(), + couch_stats_aggregator:start(cfg_file()), + ok = test_all_empty(), + ok = test_get_empty(), + ok = test_count_stats(), + ok = test_abs_stats(), + ok. + +test_all_empty() -> + {Aggs} = couch_stats_aggregator:all(), + + etap:is(length(Aggs), 2, "There are only two aggregate types in testing."), + etap:is( + couch_util:get_value(testing, Aggs), + {[{stuff, make_agg(<<"yay description">>, + null, null, null, null, null)}]}, + "{testing, stuff} is empty at start." + ), + etap:is( + couch_util:get_value(number, Aggs), + {[{'11', make_agg(<<"randomosity">>, + null, null, null, null, null)}]}, + "{number, '11'} is empty at start." + ), + ok. + +test_get_empty() -> + etap:is( + couch_stats_aggregator:get_json({testing, stuff}), + make_agg(<<"yay description">>, null, null, null, null, null), + "Getting {testing, stuff} returns an empty aggregate." + ), + etap:is( + couch_stats_aggregator:get_json({number, '11'}), + make_agg(<<"randomosity">>, null, null, null, null, null), + "Getting {number, '11'} returns an empty aggregate." + ), + ok. + +test_count_stats() -> + lists:foreach(fun(_) -> + couch_stats_collector:increment({testing, stuff}) + end, lists:seq(1, 100)), + couch_stats_aggregator:collect_sample(), + etap:is( + couch_stats_aggregator:get_json({testing, stuff}), + make_agg(<<"yay description">>, 100, 100, null, 100, 100), + "COUNT: Adding values changes the stats." + ), + etap:is( + couch_stats_aggregator:get_json({testing, stuff}, 1), + make_agg(<<"yay description">>, 100, 100, null, 100, 100), + "COUNT: Adding values changes stats for all times." + ), + + timer:sleep(500), + couch_stats_aggregator:collect_sample(), + etap:is( + couch_stats_aggregator:get_json({testing, stuff}), + make_agg(<<"yay description">>, 100, 50, 70.711, 0, 100), + "COUNT: Removing values changes stats." + ), + etap:is( + couch_stats_aggregator:get_json({testing, stuff}, 1), + make_agg(<<"yay description">>, 100, 50, 70.711, 0, 100), + "COUNT: Removing values changes stats for all times." + ), + + timer:sleep(600), + couch_stats_aggregator:collect_sample(), + etap:is( + couch_stats_aggregator:get_json({testing, stuff}), + make_agg(<<"yay description">>, 100, 33.333, 57.735, 0, 100), + "COUNT: Letting time passes doesn't remove data from time 0 aggregates" + ), + etap:is( + couch_stats_aggregator:get_json({testing, stuff}, 1), + make_agg(<<"yay description">>, 0, 0, 0, 0, 0), + "COUNT: Letting time pass removes data from other time aggregates." + ), + ok. + +test_abs_stats() -> + lists:foreach(fun(X) -> + couch_stats_collector:record({number, 11}, X) + end, lists:seq(0, 10)), + couch_stats_aggregator:collect_sample(), + etap:is( + couch_stats_aggregator:get_json({number, 11}), + make_agg(<<"randomosity">>, 5, 5, null, 5, 5), + "ABS: Adding values changes the stats." + ), + etap:is( + couch_stats_aggregator:get_json({number, 11}, 1), + make_agg(<<"randomosity">>, 5, 5, null, 5, 5), + "ABS: Adding values changes stats for all times." + ), + + timer:sleep(500), + couch_stats_collector:record({number, 11}, 15), + couch_stats_aggregator:collect_sample(), + etap:is( + couch_stats_aggregator:get_json({number, 11}), + make_agg(<<"randomosity">>, 20, 10, 7.071, 5, 15), + "ABS: New values changes stats" + ), + etap:is( + couch_stats_aggregator:get_json({number, 11}, 1), + make_agg(<<"randomosity">>, 20, 10, 7.071, 5, 15), + "ABS: Removing values changes stats for all times." + ), + + timer:sleep(600), + couch_stats_aggregator:collect_sample(), + etap:is( + couch_stats_aggregator:get_json({number, 11}), + make_agg(<<"randomosity">>, 20, 10, 7.071, 5, 15), + "ABS: Letting time passes doesn't remove data from time 0 aggregates" + ), + etap:is( + couch_stats_aggregator:get_json({number, 11}, 1), + make_agg(<<"randomosity">>, 15, 15, null, 15, 15), + "ABS: Letting time pass removes data from other time aggregates." + ), + ok. + +make_agg(Desc, Sum, Mean, StdDev, Min, Max) -> + {[ + {description, Desc}, + {current, Sum}, + {sum, Sum}, + {mean, Mean}, + {stddev, StdDev}, + {min, Min}, + {max, Max} + ]}. diff --git a/apps/couch/test/etap/121-stats-aggregates.t b/apps/couch/test/etap/121-stats-aggregates.t deleted file mode 100755 index d678aa9d..00000000 --- a/apps/couch/test/etap/121-stats-aggregates.t +++ /dev/null @@ -1,171 +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. - -ini_file() -> - test_util:source_file("test/etap/121-stats-aggregates.ini"). - -cfg_file() -> - test_util:source_file("test/etap/121-stats-aggregates.cfg"). - -main(_) -> - test_util:init_code_path(), - etap:plan(17), - case (catch test()) of - ok -> - etap:end_tests(); - Other -> - etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), - etap:bail() - end, - ok. - -test() -> - couch_config:start_link([ini_file()]), - couch_stats_collector:start(), - couch_stats_aggregator:start(cfg_file()), - ok = test_all_empty(), - ok = test_get_empty(), - ok = test_count_stats(), - ok = test_abs_stats(), - ok. - -test_all_empty() -> - {Aggs} = couch_stats_aggregator:all(), - - etap:is(length(Aggs), 2, "There are only two aggregate types in testing."), - etap:is( - couch_util:get_value(testing, Aggs), - {[{stuff, make_agg(<<"yay description">>, - null, null, null, null, null)}]}, - "{testing, stuff} is empty at start." - ), - etap:is( - couch_util:get_value(number, Aggs), - {[{'11', make_agg(<<"randomosity">>, - null, null, null, null, null)}]}, - "{number, '11'} is empty at start." - ), - ok. - -test_get_empty() -> - etap:is( - couch_stats_aggregator:get_json({testing, stuff}), - make_agg(<<"yay description">>, null, null, null, null, null), - "Getting {testing, stuff} returns an empty aggregate." - ), - etap:is( - couch_stats_aggregator:get_json({number, '11'}), - make_agg(<<"randomosity">>, null, null, null, null, null), - "Getting {number, '11'} returns an empty aggregate." - ), - ok. - -test_count_stats() -> - lists:foreach(fun(_) -> - couch_stats_collector:increment({testing, stuff}) - end, lists:seq(1, 100)), - couch_stats_aggregator:collect_sample(), - etap:is( - couch_stats_aggregator:get_json({testing, stuff}), - make_agg(<<"yay description">>, 100, 100, null, 100, 100), - "COUNT: Adding values changes the stats." - ), - etap:is( - couch_stats_aggregator:get_json({testing, stuff}, 1), - make_agg(<<"yay description">>, 100, 100, null, 100, 100), - "COUNT: Adding values changes stats for all times." - ), - - timer:sleep(500), - couch_stats_aggregator:collect_sample(), - etap:is( - couch_stats_aggregator:get_json({testing, stuff}), - make_agg(<<"yay description">>, 100, 50, 70.711, 0, 100), - "COUNT: Removing values changes stats." - ), - etap:is( - couch_stats_aggregator:get_json({testing, stuff}, 1), - make_agg(<<"yay description">>, 100, 50, 70.711, 0, 100), - "COUNT: Removing values changes stats for all times." - ), - - timer:sleep(600), - couch_stats_aggregator:collect_sample(), - etap:is( - couch_stats_aggregator:get_json({testing, stuff}), - make_agg(<<"yay description">>, 100, 33.333, 57.735, 0, 100), - "COUNT: Letting time passes doesn't remove data from time 0 aggregates" - ), - etap:is( - couch_stats_aggregator:get_json({testing, stuff}, 1), - make_agg(<<"yay description">>, 0, 0, 0, 0, 0), - "COUNT: Letting time pass removes data from other time aggregates." - ), - ok. - -test_abs_stats() -> - lists:foreach(fun(X) -> - couch_stats_collector:record({number, 11}, X) - end, lists:seq(0, 10)), - couch_stats_aggregator:collect_sample(), - etap:is( - couch_stats_aggregator:get_json({number, 11}), - make_agg(<<"randomosity">>, 5, 5, null, 5, 5), - "ABS: Adding values changes the stats." - ), - etap:is( - couch_stats_aggregator:get_json({number, 11}, 1), - make_agg(<<"randomosity">>, 5, 5, null, 5, 5), - "ABS: Adding values changes stats for all times." - ), - - timer:sleep(500), - couch_stats_collector:record({number, 11}, 15), - couch_stats_aggregator:collect_sample(), - etap:is( - couch_stats_aggregator:get_json({number, 11}), - make_agg(<<"randomosity">>, 20, 10, 7.071, 5, 15), - "ABS: New values changes stats" - ), - etap:is( - couch_stats_aggregator:get_json({number, 11}, 1), - make_agg(<<"randomosity">>, 20, 10, 7.071, 5, 15), - "ABS: Removing values changes stats for all times." - ), - - timer:sleep(600), - couch_stats_aggregator:collect_sample(), - etap:is( - couch_stats_aggregator:get_json({number, 11}), - make_agg(<<"randomosity">>, 20, 10, 7.071, 5, 15), - "ABS: Letting time passes doesn't remove data from time 0 aggregates" - ), - etap:is( - couch_stats_aggregator:get_json({number, 11}, 1), - make_agg(<<"randomosity">>, 15, 15, null, 15, 15), - "ABS: Letting time pass removes data from other time aggregates." - ), - ok. - -make_agg(Desc, Sum, Mean, StdDev, Min, Max) -> - {[ - {description, Desc}, - {current, Sum}, - {sum, Sum}, - {mean, Mean}, - {stddev, StdDev}, - {min, Min}, - {max, Max} - ]}. diff --git a/apps/couch/test/etap/130-attachments-md5.t b/apps/couch/test/etap/130-attachments-md5.t deleted file mode 100755 index 4c40f83a..00000000 --- a/apps/couch/test/etap/130-attachments-md5.t +++ /dev/null @@ -1,252 +0,0 @@ -#!/usr/bin/env escript -% 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. - -default_config() -> - test_util:build_file("etc/couchdb/default_dev.ini"). - -test_db_name() -> - <<"etap-test-db">>. - -docid() -> - case get(docid) of - undefined -> - put(docid, 1), - "1"; - Count -> - put(docid, Count+1), - integer_to_list(Count+1) - end. - -main(_) -> - test_util:init_code_path(), - - etap:plan(16), - 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([default_config()]), - Addr = couch_config:get("httpd", "bind_address", any), - Port = list_to_integer(couch_config:get("httpd", "port", "5984")), - put(addr, Addr), - put(port, Port), - timer:sleep(1000), - - couch_server:delete(test_db_name(), []), - couch_db:create(test_db_name(), []), - - test_identity_without_md5(), - test_chunked_without_md5(), - - test_identity_with_valid_md5(), - test_chunked_with_valid_md5_header(), - test_chunked_with_valid_md5_trailer(), - - test_identity_with_invalid_md5(), - test_chunked_with_invalid_md5_header(), - test_chunked_with_invalid_md5_trailer(), - - couch_server:delete(test_db_name(), []), - couch_server_sup:stop(), - ok. - -test_identity_without_md5() -> - Data = [ - "PUT /", test_db_name(), "/", docid(), "/readme.txt HTTP/1.1\r\n", - "Content-Type: text/plain\r\n", - "Content-Length: 34\r\n", - "\r\n", - "We all live in a yellow submarine!"], - - {Code, Json} = do_request(Data), - etap:is(Code, 201, "Stored with identity encoding and no MD5"), - etap:is(get_json(Json, [<<"ok">>]), true, "Body indicates success."). - -test_chunked_without_md5() -> - AttData = <<"We all live in a yellow submarine!">>, - <> = AttData, - Data = [ - "PUT /", test_db_name(), "/", docid(), "/readme.txt HTTP/1.1\r\n", - "Content-Type: text/plain\r\n", - "Transfer-Encoding: chunked\r\n", - "\r\n", - to_hex(size(Part1)), "\r\n", - Part1, "\r\n", - to_hex(size(Part2)), "\r\n", - Part2, "\r\n" - "0\r\n" - "\r\n"], - - {Code, Json} = do_request(Data), - etap:is(Code, 201, "Stored with chunked encoding and no MD5"), - etap:is(get_json(Json, [<<"ok">>]), true, "Body indicates success."). - -test_identity_with_valid_md5() -> - AttData = "We all live in a yellow submarine!", - Data = [ - "PUT /", test_db_name(), "/", docid(), "/readme.txt HTTP/1.1\r\n", - "Content-Type: text/plain\r\n", - "Content-Length: 34\r\n", - "Content-MD5: ", base64:encode(couch_util:md5(AttData)), "\r\n", - "\r\n", - AttData], - - {Code, Json} = do_request(Data), - etap:is(Code, 201, "Stored with identity encoding and valid MD5"), - etap:is(get_json(Json, [<<"ok">>]), true, "Body indicates success."). - -test_chunked_with_valid_md5_header() -> - AttData = <<"We all live in a yellow submarine!">>, - <> = AttData, - Data = [ - "PUT /", test_db_name(), "/", docid(), "/readme.txt HTTP/1.1\r\n", - "Content-Type: text/plain\r\n", - "Transfer-Encoding: chunked\r\n", - "Content-MD5: ", base64:encode(couch_util:md5(AttData)), "\r\n", - "\r\n", - to_hex(size(Part1)), "\r\n", - Part1, "\r\n", - to_hex(size(Part2)), "\r\n", - Part2, "\r\n", - "0\r\n", - "\r\n"], - - {Code, Json} = do_request(Data), - etap:is(Code, 201, "Stored with chunked encoding and valid MD5 header."), - etap:is(get_json(Json, [<<"ok">>]), true, "Body indicates success."). - -test_chunked_with_valid_md5_trailer() -> - AttData = <<"We all live in a yellow submarine!">>, - <> = AttData, - Data = [ - "PUT /", test_db_name(), "/", docid(), "/readme.txt HTTP/1.1\r\n", - "Content-Type: text/plain\r\n", - "Transfer-Encoding: chunked\r\n", - "Trailer: Content-MD5\r\n", - "\r\n", - to_hex(size(Part1)), "\r\n", - Part1, "\r\n", - to_hex(size(Part2)), "\r\n", - Part2, "\r\n", - "0\r\n", - "Content-MD5: ", base64:encode(couch_util:md5(AttData)), "\r\n", - "\r\n"], - - {Code, Json} = do_request(Data), - etap:is(Code, 201, "Stored with chunked encoding and valid MD5 trailer."), - etap:is(get_json(Json, [<<"ok">>]), true, "Body indicates success."). - -test_identity_with_invalid_md5() -> - Data = [ - "PUT /", test_db_name(), "/", docid(), "/readme.txt HTTP/1.1\r\n", - "Content-Type: text/plain\r\n", - "Content-Length: 34\r\n", - "Content-MD5: ", base64:encode(<<"foobar!">>), "\r\n", - "\r\n", - "We all live in a yellow submarine!"], - - {Code, Json} = do_request(Data), - etap:is(Code, 400, "Invalid MD5 header causes an error: identity"), - etap:is( - get_json(Json, [<<"error">>]), - <<"content_md5_mismatch">>, - "Body indicates reason for failure." - ). - -test_chunked_with_invalid_md5_header() -> - AttData = <<"We all live in a yellow submarine!">>, - <> = AttData, - Data = [ - "PUT /", test_db_name(), "/", docid(), "/readme.txt HTTP/1.1\r\n", - "Content-Type: text/plain\r\n", - "Transfer-Encoding: chunked\r\n", - "Content-MD5: ", base64:encode(<<"so sneaky...">>), "\r\n", - "\r\n", - to_hex(size(Part1)), "\r\n", - Part1, "\r\n", - to_hex(size(Part2)), "\r\n", - Part2, "\r\n", - "0\r\n", - "\r\n"], - - {Code, Json} = do_request(Data), - etap:is(Code, 400, "Invalid MD5 header causes an error: chunked"), - etap:is( - get_json(Json, [<<"error">>]), - <<"content_md5_mismatch">>, - "Body indicates reason for failure." - ). - -test_chunked_with_invalid_md5_trailer() -> - AttData = <<"We all live in a yellow submarine!">>, - <> = AttData, - Data = [ - "PUT /", test_db_name(), "/", docid(), "/readme.txt HTTP/1.1\r\n", - "Content-Type: text/plain\r\n", - "Transfer-Encoding: chunked\r\n", - "Trailer: Content-MD5\r\n", - "\r\n", - to_hex(size(Part1)), "\r\n", - Part1, "\r\n", - to_hex(size(Part2)), "\r\n", - Part2, "\r\n", - "0\r\n", - "Content-MD5: ", base64:encode(<<"Kool-Aid Fountain!">>), "\r\n", - "\r\n"], - - {Code, Json} = do_request(Data), - etap:is(Code, 400, "Invalid MD5 Trailer causes an error"), - etap:is( - get_json(Json, [<<"error">>]), - <<"content_md5_mismatch">>, - "Body indicates reason for failure." - ). - - -get_socket() -> - Options = [binary, {packet, 0}, {active, false}], - {ok, Sock} = gen_tcp:connect(get(addr), get(port), Options), - Sock. - -do_request(Request) -> - Sock = get_socket(), - gen_tcp:send(Sock, list_to_binary(lists:flatten(Request))), - timer:sleep(1000), - {ok, R} = gen_tcp:recv(Sock, 0), - gen_tcp:close(Sock), - [Header, Body] = re:split(R, "\r\n\r\n", [{return, binary}]), - {ok, {http_response, _, Code, _}, _} = - erlang:decode_packet(http, Header, []), - Json = couch_util:json_decode(Body), - {Code, Json}. - -get_json(Json, Path) -> - couch_util:get_nested_json_value(Json, Path). - -to_hex(Val) -> - to_hex(Val, []). - -to_hex(0, Acc) -> - Acc; -to_hex(Val, Acc) -> - to_hex(Val div 16, [hex_char(Val rem 16) | Acc]). - -hex_char(V) when V < 10 -> $0 + V; -hex_char(V) -> $A + V - 10. - diff --git a/apps/couch/test/etap/140-attachment-comp.t b/apps/couch/test/etap/140-attachment-comp.t deleted file mode 100755 index 98d37abc..00000000 --- a/apps/couch/test/etap/140-attachment-comp.t +++ /dev/null @@ -1,711 +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. - -default_config() -> - test_util:build_file("etc/couchdb/default_dev.ini"). - -test_db_name() -> - <<"couch_test_atts_compression">>. - -main(_) -> - test_util:init_code_path(), - - etap:plan(78), - 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([default_config()]), - put(addr, couch_config:get("httpd", "bind_address", "127.0.0.1")), - put(port, couch_config:get("httpd", "port", "5984")), - application:start(inets), - timer:sleep(1000), - couch_server:delete(test_db_name(), []), - couch_db:create(test_db_name(), []), - - couch_config:set("attachments", "compression_level", "8"), - couch_config:set("attachments", "compressible_types", "text/*"), - - create_1st_text_att(), - create_1st_png_att(), - create_2nd_text_att(), - create_2nd_png_att(), - - tests_for_1st_text_att(), - tests_for_1st_png_att(), - tests_for_2nd_text_att(), - tests_for_2nd_png_att(), - - create_already_compressed_att(db_url() ++ "/doc_comp_att", "readme.txt"), - test_already_compressed_att(db_url() ++ "/doc_comp_att", "readme.txt"), - - test_create_already_compressed_att_with_invalid_content_encoding( - db_url() ++ "/doc_att_deflate", - "readme.txt", - zlib:compress(test_text_data()), - "deflate" - ), - - test_create_already_compressed_att_with_invalid_content_encoding( - db_url() ++ "/doc_att_compress", - "readme.txt", - % Note: As of OTP R13B04, it seems there's no LZW compression - % (i.e. UNIX compress utility implementation) lib in OTP. - % However there's a simple working Erlang implementation at: - % http://scienceblogs.com/goodmath/2008/01/simple_lempelziv_compression_i.php - test_text_data(), - "compress" - ), - - timer:sleep(3000), % to avoid mochiweb socket closed exceptions - couch_server:delete(test_db_name(), []), - couch_server_sup:stop(), - ok. - -db_url() -> - "http://" ++ get(addr) ++ ":" ++ get(port) ++ "/" ++ - binary_to_list(test_db_name()). - -create_1st_text_att() -> - {ok, {{_, Code, _}, _Headers, _Body}} = http:request( - put, - {db_url() ++ "/testdoc1/readme.txt", [], - "text/plain", test_text_data()}, - [], - [{sync, true}]), - etap:is(Code, 201, "Created text attachment using the standalone api"), - ok. - -create_1st_png_att() -> - {ok, {{_, Code, _}, _Headers, _Body}} = http:request( - put, - {db_url() ++ "/testdoc2/icon.png", [], - "image/png", test_png_data()}, - [], - [{sync, true}]), - etap:is(Code, 201, "Created png attachment using the standalone api"), - ok. - -% create a text attachment using the non-standalone attachment api -create_2nd_text_att() -> - DocJson = {[ - {<<"_attachments">>, {[ - {<<"readme.txt">>, {[ - {<<"content_type">>, <<"text/plain">>}, - {<<"data">>, base64:encode(test_text_data())} - ]} - }]}} - ]}, - {ok, {{_, Code, _}, _Headers, _Body}} = http:request( - put, - {db_url() ++ "/testdoc3", [], - "application/json", list_to_binary(couch_util:json_encode(DocJson))}, - [], - [{sync, true}]), - etap:is(Code, 201, "Created text attachment using the non-standalone api"), - ok. - -% create a png attachment using the non-standalone attachment api -create_2nd_png_att() -> - DocJson = {[ - {<<"_attachments">>, {[ - {<<"icon.png">>, {[ - {<<"content_type">>, <<"image/png">>}, - {<<"data">>, base64:encode(test_png_data())} - ]} - }]}} - ]}, - {ok, {{_, Code, _}, _Headers, _Body}} = http:request( - put, - {db_url() ++ "/testdoc4", [], - "application/json", list_to_binary(couch_util:json_encode(DocJson))}, - [], - [{sync, true}]), - etap:is(Code, 201, "Created png attachment using the non-standalone api"), - ok. - -create_already_compressed_att(DocUri, AttName) -> - {ok, {{_, Code, _}, _Headers, _Body}} = http:request( - put, - {DocUri ++ "/" ++ AttName, [{"Content-Encoding", "gzip"}], - "text/plain", zlib:gzip(test_text_data())}, - [], - [{sync, true}]), - etap:is( - Code, - 201, - "Created already compressed attachment using the standalone api" - ), - ok. - -tests_for_1st_text_att() -> - test_get_1st_text_att_with_accept_encoding_gzip(), - test_get_1st_text_att_without_accept_encoding_header(), - test_get_1st_text_att_with_accept_encoding_deflate(), - test_get_1st_text_att_with_accept_encoding_deflate_only(), - test_get_doc_with_1st_text_att(), - test_1st_text_att_stub(). - -tests_for_1st_png_att() -> - test_get_1st_png_att_without_accept_encoding_header(), - test_get_1st_png_att_with_accept_encoding_gzip(), - test_get_1st_png_att_with_accept_encoding_deflate(), - test_get_doc_with_1st_png_att(), - test_1st_png_att_stub(). - -tests_for_2nd_text_att() -> - test_get_2nd_text_att_with_accept_encoding_gzip(), - test_get_2nd_text_att_without_accept_encoding_header(), - test_get_doc_with_2nd_text_att(), - test_2nd_text_att_stub(). - -tests_for_2nd_png_att() -> - test_get_2nd_png_att_without_accept_encoding_header(), - test_get_2nd_png_att_with_accept_encoding_gzip(), - test_get_doc_with_2nd_png_att(), - test_2nd_png_att_stub(). - -test_get_1st_text_att_with_accept_encoding_gzip() -> - {ok, {{_, Code, _}, Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc1/readme.txt", [{"Accept-Encoding", "gzip"}]}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Gziped = lists:member({"content-encoding", "gzip"}, Headers), - etap:is(Gziped, true, "received body is gziped"), - Uncompressed = binary_to_list(zlib:gunzip(list_to_binary(Body))), - etap:is( - Uncompressed, - test_text_data(), - "received data for the 1st text attachment is ok" - ), - ok. - -test_get_1st_text_att_without_accept_encoding_header() -> - {ok, {{_, Code, _}, Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc1/readme.txt", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Gziped = lists:member({"content-encoding", "gzip"}, Headers), - etap:is(Gziped, false, "received body is not gziped"), - etap:is( - Body, - test_text_data(), - "received data for the 1st text attachment is ok" - ), - ok. - -test_get_1st_text_att_with_accept_encoding_deflate() -> - {ok, {{_, Code, _}, Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc1/readme.txt", [{"Accept-Encoding", "deflate"}]}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Gziped = lists:member({"content-encoding", "gzip"}, Headers), - etap:is(Gziped, false, "received body is not gziped"), - Deflated = lists:member({"content-encoding", "deflate"}, Headers), - etap:is(Deflated, false, "received body is not deflated"), - etap:is( - Body, - test_text_data(), - "received data for the 1st text attachment is ok" - ), - ok. - -test_get_1st_text_att_with_accept_encoding_deflate_only() -> - {ok, {{_, Code, _}, _Headers, _Body}} = http:request( - get, - {db_url() ++ "/testdoc1/readme.txt", - [{"Accept-Encoding", "deflate, *;q=0"}]}, - [], - [{sync, true}]), - etap:is( - Code, - 406, - "HTTP response code is 406 for an unsupported content encoding request" - ), - ok. - -test_get_1st_png_att_without_accept_encoding_header() -> - {ok, {{_, Code, _}, Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc2/icon.png", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Gziped = lists:member({"content-encoding", "gzip"}, Headers), - etap:is(Gziped, false, "received body is not gziped"), - etap:is( - Body, - test_png_data(), - "received data for the 1st png attachment is ok" - ), - ok. - -test_get_1st_png_att_with_accept_encoding_gzip() -> - {ok, {{_, Code, _}, Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc2/icon.png", [{"Accept-Encoding", "gzip"}]}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Gziped = lists:member({"content-encoding", "gzip"}, Headers), - etap:is(Gziped, false, "received body is not gziped"), - etap:is( - Body, - test_png_data(), - "received data for the 1st png attachment is ok" - ), - ok. - -test_get_1st_png_att_with_accept_encoding_deflate() -> - {ok, {{_, Code, _}, Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc2/icon.png", [{"Accept-Encoding", "deflate"}]}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Deflated = lists:member({"content-encoding", "deflate"}, Headers), - etap:is(Deflated, false, "received body is not deflated"), - Gziped = lists:member({"content-encoding", "gzip"}, Headers), - etap:is(Gziped, false, "received body is not gziped"), - etap:is( - Body, - test_png_data(), - "received data for the 1st png attachment is ok" - ), - ok. - -test_get_doc_with_1st_text_att() -> - {ok, {{_, Code, _}, _Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc1?attachments=true", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Json = couch_util:json_decode(Body), - TextAttJson = couch_util:get_nested_json_value( - Json, - [<<"_attachments">>, <<"readme.txt">>] - ), - TextAttType = couch_util:get_nested_json_value( - TextAttJson, - [<<"content_type">>] - ), - TextAttData = couch_util:get_nested_json_value( - TextAttJson, - [<<"data">>] - ), - etap:is( - TextAttType, - <<"text/plain">>, - "1st text attachment has type text/plain" - ), - %% check the attachment's data is the base64 encoding of the plain text - %% and not the base64 encoding of the gziped plain text - etap:is( - TextAttData, - base64:encode(test_text_data()), - "1st text attachment data is properly base64 encoded" - ), - ok. - -test_1st_text_att_stub() -> - {ok, {{_, Code, _}, _Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc1?att_encoding_info=true", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Json = couch_util:json_decode(Body), - {TextAttJson} = couch_util:get_nested_json_value( - Json, - [<<"_attachments">>, <<"readme.txt">>] - ), - TextAttLength = couch_util:get_value(<<"length">>, TextAttJson), - etap:is( - TextAttLength, - length(test_text_data()), - "1st text attachment stub length matches the uncompressed length" - ), - TextAttEncoding = couch_util:get_value(<<"encoding">>, TextAttJson), - etap:is( - TextAttEncoding, - <<"gzip">>, - "1st text attachment stub has the encoding field set to gzip" - ), - TextAttEncLength = couch_util:get_value(<<"encoded_length">>, TextAttJson), - etap:is( - TextAttEncLength, - iolist_size(zlib:gzip(test_text_data())), - "1st text attachment stub encoded_length matches the compressed length" - ), - ok. - -test_get_doc_with_1st_png_att() -> - {ok, {{_, Code, _}, _Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc2?attachments=true", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Json = couch_util:json_decode(Body), - PngAttJson = couch_util:get_nested_json_value( - Json, - [<<"_attachments">>, <<"icon.png">>] - ), - PngAttType = couch_util:get_nested_json_value( - PngAttJson, - [<<"content_type">>] - ), - PngAttData = couch_util:get_nested_json_value( - PngAttJson, - [<<"data">>] - ), - etap:is(PngAttType, <<"image/png">>, "attachment has type image/png"), - etap:is( - PngAttData, - base64:encode(test_png_data()), - "1st png attachment data is properly base64 encoded" - ), - ok. - -test_1st_png_att_stub() -> - {ok, {{_, Code, _}, _Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc2?att_encoding_info=true", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Json = couch_util:json_decode(Body), - {PngAttJson} = couch_util:get_nested_json_value( - Json, - [<<"_attachments">>, <<"icon.png">>] - ), - PngAttLength = couch_util:get_value(<<"length">>, PngAttJson), - etap:is( - PngAttLength, - length(test_png_data()), - "1st png attachment stub length matches the uncompressed length" - ), - PngEncoding = couch_util:get_value(<<"encoding">>, PngAttJson), - etap:is( - PngEncoding, - undefined, - "1st png attachment stub doesn't have an encoding field" - ), - PngEncLength = couch_util:get_value(<<"encoded_length">>, PngAttJson), - etap:is( - PngEncLength, - undefined, - "1st png attachment stub doesn't have an encoded_length field" - ), - ok. - -test_get_2nd_text_att_with_accept_encoding_gzip() -> - {ok, {{_, Code, _}, Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc3/readme.txt", [{"Accept-Encoding", "gzip"}]}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Gziped = lists:member({"content-encoding", "gzip"}, Headers), - etap:is(Gziped, true, "received body is gziped"), - Uncompressed = binary_to_list(zlib:gunzip(list_to_binary(Body))), - etap:is( - Uncompressed, - test_text_data(), - "received data for the 2nd text attachment is ok" - ), - ok. - -test_get_2nd_text_att_without_accept_encoding_header() -> - {ok, {{_, Code, _}, Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc3/readme.txt", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Gziped = lists:member({"content-encoding", "gzip"}, Headers), - etap:is(Gziped, false, "received body is not gziped"), - etap:is( - Body, - test_text_data(), - "received data for the 2nd text attachment is ok" - ), - ok. - -test_get_2nd_png_att_without_accept_encoding_header() -> - {ok, {{_, Code, _}, Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc4/icon.png", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Gziped = lists:member({"content-encoding", "gzip"}, Headers), - etap:is(Gziped, false, "received body is not gziped"), - etap:is( - Body, - test_png_data(), - "received data for the 2nd png attachment is ok" - ), - ok. - -test_get_2nd_png_att_with_accept_encoding_gzip() -> - {ok, {{_, Code, _}, Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc4/icon.png", [{"Accept-Encoding", "gzip"}]}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Gziped = lists:member({"content-encoding", "gzip"}, Headers), - etap:is(Gziped, false, "received body is not gziped"), - etap:is( - Body, - test_png_data(), - "received data for the 2nd png attachment is ok" - ), - ok. - -test_get_doc_with_2nd_text_att() -> - {ok, {{_, Code, _}, _Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc3?attachments=true", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Json = couch_util:json_decode(Body), - TextAttJson = couch_util:get_nested_json_value( - Json, - [<<"_attachments">>, <<"readme.txt">>] - ), - TextAttType = couch_util:get_nested_json_value( - TextAttJson, - [<<"content_type">>] - ), - TextAttData = couch_util:get_nested_json_value( - TextAttJson, - [<<"data">>] - ), - etap:is(TextAttType, <<"text/plain">>, "attachment has type text/plain"), - %% check the attachment's data is the base64 encoding of the plain text - %% and not the base64 encoding of the gziped plain text - etap:is( - TextAttData, - base64:encode(test_text_data()), - "2nd text attachment data is properly base64 encoded" - ), - ok. - -test_2nd_text_att_stub() -> - {ok, {{_, Code, _}, _Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc3?att_encoding_info=true", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Json = couch_util:json_decode(Body), - {TextAttJson} = couch_util:get_nested_json_value( - Json, - [<<"_attachments">>, <<"readme.txt">>] - ), - TextAttLength = couch_util:get_value(<<"length">>, TextAttJson), - etap:is( - TextAttLength, - length(test_text_data()), - "2nd text attachment stub length matches the uncompressed length" - ), - TextAttEncoding = couch_util:get_value(<<"encoding">>, TextAttJson), - etap:is( - TextAttEncoding, - <<"gzip">>, - "2nd text attachment stub has the encoding field set to gzip" - ), - TextAttEncLength = couch_util:get_value(<<"encoded_length">>, TextAttJson), - etap:is( - TextAttEncLength, - iolist_size(zlib:gzip(test_text_data())), - "2nd text attachment stub encoded_length matches the compressed length" - ), - ok. - -test_get_doc_with_2nd_png_att() -> - {ok, {{_, Code, _}, _Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc4?attachments=true", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Json = couch_util:json_decode(Body), - PngAttJson = couch_util:get_nested_json_value( - Json, - [<<"_attachments">>, <<"icon.png">>] - ), - PngAttType = couch_util:get_nested_json_value( - PngAttJson, - [<<"content_type">>] - ), - PngAttData = couch_util:get_nested_json_value( - PngAttJson, - [<<"data">>] - ), - etap:is(PngAttType, <<"image/png">>, "attachment has type image/png"), - etap:is( - PngAttData, - base64:encode(test_png_data()), - "2nd png attachment data is properly base64 encoded" - ), - ok. - -test_2nd_png_att_stub() -> - {ok, {{_, Code, _}, _Headers, Body}} = http:request( - get, - {db_url() ++ "/testdoc4?att_encoding_info=true", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Json = couch_util:json_decode(Body), - {PngAttJson} = couch_util:get_nested_json_value( - Json, - [<<"_attachments">>, <<"icon.png">>] - ), - PngAttLength = couch_util:get_value(<<"length">>, PngAttJson), - etap:is( - PngAttLength, - length(test_png_data()), - "2nd png attachment stub length matches the uncompressed length" - ), - PngEncoding = couch_util:get_value(<<"encoding">>, PngAttJson), - etap:is( - PngEncoding, - undefined, - "2nd png attachment stub doesn't have an encoding field" - ), - PngEncLength = couch_util:get_value(<<"encoded_length">>, PngAttJson), - etap:is( - PngEncLength, - undefined, - "2nd png attachment stub doesn't have an encoded_length field" - ), - ok. - -test_already_compressed_att(DocUri, AttName) -> - test_get_already_compressed_att_with_accept_gzip(DocUri, AttName), - test_get_already_compressed_att_without_accept(DocUri, AttName), - test_get_already_compressed_att_stub(DocUri, AttName). - -test_get_already_compressed_att_with_accept_gzip(DocUri, AttName) -> - {ok, {{_, Code, _}, Headers, Body}} = http:request( - get, - {DocUri ++ "/" ++ AttName, [{"Accept-Encoding", "gzip"}]}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Gziped = lists:member({"content-encoding", "gzip"}, Headers), - etap:is(Gziped, true, "received body is gziped"), - etap:is( - iolist_to_binary(Body), - iolist_to_binary(zlib:gzip(test_text_data())), - "received data for the already compressed attachment is ok" - ), - ok. - -test_get_already_compressed_att_without_accept(DocUri, AttName) -> - {ok, {{_, Code, _}, Headers, Body}} = http:request( - get, - {DocUri ++ "/" ++ AttName, []}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Gziped = lists:member({"content-encoding", "gzip"}, Headers), - etap:is(Gziped, false, "received body is not gziped"), - etap:is( - iolist_to_binary(Body), - iolist_to_binary(test_text_data()), - "received data for the already compressed attachment is ok" - ), - ok. - -test_get_already_compressed_att_stub(DocUri, AttName) -> - {ok, {{_, Code, _}, _Headers, Body}} = http:request( - get, - {DocUri ++ "?att_encoding_info=true", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "HTTP response code is 200"), - Json = couch_util:json_decode(Body), - {AttJson} = couch_util:get_nested_json_value( - Json, - [<<"_attachments">>, iolist_to_binary(AttName)] - ), - AttLength = couch_util:get_value(<<"length">>, AttJson), - etap:is( - AttLength, - iolist_size((zlib:gzip(test_text_data()))), - "Already compressed attachment stub length matches the " - "compressed length" - ), - Encoding = couch_util:get_value(<<"encoding">>, AttJson), - etap:is( - Encoding, - <<"gzip">>, - "Already compressed attachment stub has the encoding field set to gzip" - ), - EncLength = couch_util:get_value(<<"encoded_length">>, AttJson), - etap:is( - EncLength, - AttLength, - "Already compressed attachment stub encoded_length matches the " - "length field value" - ), - ok. - -test_create_already_compressed_att_with_invalid_content_encoding( - DocUri, AttName, AttData, Encoding) -> - {ok, {{_, Code, _}, _Headers, _Body}} = http:request( - put, - {DocUri ++ "/" ++ AttName, [{"Content-Encoding", Encoding}], - "text/plain", AttData}, - [], - [{sync, true}]), - etap:is( - Code, - 415, - "Couldn't create an already compressed attachment using the " - "unsupported encoding '" ++ Encoding ++ "'" - ), - ok. - -test_png_data() -> - {ok, Data} = file:read_file( - test_util:source_file("share/www/image/logo.png") - ), - binary_to_list(Data). - -test_text_data() -> - {ok, Data} = file:read_file( - test_util:source_file("README") - ), - binary_to_list(Data). diff --git a/apps/couch/test/etap/150-invalid-view-seq.t b/apps/couch/test/etap/150-invalid-view-seq.t deleted file mode 100755 index 0664c116..00000000 --- a/apps/couch/test/etap/150-invalid-view-seq.t +++ /dev/null @@ -1,192 +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 -}). - -default_config() -> - test_util:build_file("etc/couchdb/default_dev.ini"). - -test_db_name() -> - <<"couch_test_invalid_view_seq">>. - -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. - -%% NOTE: since during the test we stop the server, -%% a huge and ugly but harmless stack trace is sent to stderr -%% -test() -> - couch_server_sup:start_link([default_config()]), - timer:sleep(1000), - delete_db(), - create_db(), - - create_docs(), - create_design_doc(), - - % make DB file backup - backup_db_file(), - - put(addr, couch_config:get("httpd", "bind_address", "127.0.0.1")), - put(port, couch_config:get("httpd", "port", "5984")), - application:start(inets), - - create_new_doc(), - query_view_before_restore_backup(), - - % restore DB file backup after querying view - restore_backup_db_file(), - - query_view_after_restore_backup(), - - delete_db(), - couch_server_sup:stop(), - ok. - -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()]). - -create_docs() -> - {ok, Db} = couch_db:open(test_db_name(), [admin_user_ctx()]), - Doc1 = couch_doc:from_json_obj({[ - {<<"_id">>, <<"doc1">>}, - {<<"value">>, 1} - - ]}), - Doc2 = couch_doc:from_json_obj({[ - {<<"_id">>, <<"doc2">>}, - {<<"value">>, 2} - - ]}), - Doc3 = couch_doc:from_json_obj({[ - {<<"_id">>, <<"doc3">>}, - {<<"value">>, 3} - - ]}), - {ok, _} = couch_db:update_docs(Db, [Doc1, Doc2, Doc3]), - couch_db:ensure_full_commit(Db), - couch_db:close(Db). - -create_design_doc() -> - {ok, Db} = couch_db:open(test_db_name(), [admin_user_ctx()]), - DDoc = couch_doc:from_json_obj({[ - {<<"_id">>, <<"_design/foo">>}, - {<<"language">>, <<"javascript">>}, - {<<"views">>, {[ - {<<"bar">>, {[ - {<<"map">>, <<"function(doc) { emit(doc.value, 1); }">>} - ]}} - ]}} - ]}), - {ok, _} = couch_db:update_docs(Db, [DDoc]), - couch_db:ensure_full_commit(Db), - couch_db:close(Db). - -backup_db_file() -> - DbFile = test_util:build_file("tmp/lib/" ++ - binary_to_list(test_db_name()) ++ ".couch"), - {ok, _} = file:copy(DbFile, DbFile ++ ".backup"), - ok. - -create_new_doc() -> - {ok, Db} = couch_db:open(test_db_name(), [admin_user_ctx()]), - Doc666 = couch_doc:from_json_obj({[ - {<<"_id">>, <<"doc666">>}, - {<<"value">>, 999} - - ]}), - {ok, _} = couch_db:update_docs(Db, [Doc666]), - couch_db:ensure_full_commit(Db), - couch_db:close(Db). - -db_url() -> - "http://" ++ get(addr) ++ ":" ++ get(port) ++ "/" ++ - binary_to_list(test_db_name()). - -query_view_before_restore_backup() -> - {ok, {{_, Code, _}, _Headers, Body}} = http:request( - get, - {db_url() ++ "/_design/foo/_view/bar", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "Got view response before restoring backup."), - ViewJson = couch_util:json_decode(Body), - Rows = couch_util:get_nested_json_value(ViewJson, [<<"rows">>]), - HasDoc1 = has_doc("doc1", Rows), - HasDoc2 = has_doc("doc2", Rows), - HasDoc3 = has_doc("doc3", Rows), - HasDoc666 = has_doc("doc666", Rows), - etap:is(HasDoc1, true, "Before backup restore, view has doc1"), - etap:is(HasDoc2, true, "Before backup restore, view has doc2"), - etap:is(HasDoc3, true, "Before backup restore, view has doc3"), - etap:is(HasDoc666, true, "Before backup restore, view has doc666"), - ok. - -has_doc(DocId1, Rows) -> - DocId = iolist_to_binary(DocId1), - lists:any( - fun({R}) -> lists:member({<<"id">>, DocId}, R) end, - Rows - ). - -restore_backup_db_file() -> - couch_server_sup:stop(), - timer:sleep(3000), - DbFile = test_util:build_file("tmp/lib/" ++ - binary_to_list(test_db_name()) ++ ".couch"), - ok = file:delete(DbFile), - ok = file:rename(DbFile ++ ".backup", DbFile), - couch_server_sup:start_link([default_config()]), - timer:sleep(1000), - ok. - -query_view_after_restore_backup() -> - {ok, {{_, Code, _}, _Headers, Body}} = http:request( - get, - {db_url() ++ "/_design/foo/_view/bar", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "Got view response after restoring backup."), - ViewJson = couch_util:json_decode(Body), - Rows = couch_util:get_nested_json_value(ViewJson, [<<"rows">>]), - HasDoc1 = has_doc("doc1", Rows), - HasDoc2 = has_doc("doc2", Rows), - HasDoc3 = has_doc("doc3", Rows), - HasDoc666 = has_doc("doc666", Rows), - etap:is(HasDoc1, true, "After backup restore, view has doc1"), - etap:is(HasDoc2, true, "After backup restore, view has doc2"), - etap:is(HasDoc3, true, "After backup restore, view has doc3"), - etap:is(HasDoc666, false, "After backup restore, view does not have doc666"), - ok. diff --git a/apps/couch/test/etap/160-vhosts.t b/apps/couch/test/etap/160-vhosts.t deleted file mode 100755 index 7694010a..00000000 --- a/apps/couch/test/etap/160-vhosts.t +++ /dev/null @@ -1,131 +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. - -%% XXX: Figure out how to -include("couch_rep.hrl") --record(http_db, { - url, - auth = [], - resource = "", - headers = [ - {"User-Agent", "CouchDB/"++couch:version()}, - {"Accept", "application/json"}, - {"Accept-Encoding", "gzip"} - ], - qs = [], - method = get, - body = nil, - options = [ - {response_format,binary}, - {inactivity_timeout, 30000} - ], - retries = 10, - pause = 1, - conn = nil -}). - --record(user_ctx, { - name = null, - roles = [], - handler -}). - -server() -> "http://127.0.0.1:5984/". -dbname() -> "etap-test-db". -admin_user_ctx() -> {user_ctx, #user_ctx{roles=[<<"_admin">>]}}. - -config_files() -> - lists:map(fun test_util:build_file/1, [ - "etc/couchdb/default_dev.ini", - "etc/couchdb/local_dev.ini" - ]). - -main(_) -> - test_util:init_code_path(), - - etap:plan(4), - 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(config_files()), - ibrowse:start(), - crypto:start(), - - couch_server:delete(list_to_binary(dbname()), [admin_user_ctx()]), - {ok, Db} = couch_db:create(list_to_binary(dbname()), [admin_user_ctx()]), - - Doc = couch_doc:from_json_obj({[ - {<<"_id">>, <<"doc1">>}, - {<<"value">>, 666} - ]}), - {ok, _} = couch_db:update_docs(Db, [Doc]), - couch_db:ensure_full_commit(Db), - - %% end boilerplate, start test - - couch_config:set("vhosts", "example.com", "/etap-test-db", false), - test_regular_request(), - test_vhost_request(), - test_vhost_request_with_qs(), - test_vhost_request_with_global(), - - %% restart boilerplate - couch_db:close(Db), - couch_server:delete(list_to_binary(dbname()), []), - ok. - -test_regular_request() -> - case ibrowse:send_req(server(), [], get, []) of - {ok, _, _, Body} -> - {[{<<"couchdb">>, <<"Welcome">>}, - {<<"version">>,_} - ]} = couch_util:json_decode(Body), - etap:is(true, true, "should return server info"); - _Else -> false - end. - -test_vhost_request() -> - case ibrowse:send_req(server(), [], get, [], [{host_header, "example.com"}]) of - {ok, _, _, Body} -> - {[{<<"db_name">>, <<"etap-test-db">>},_,_,_,_,_,_,_,_,_]} - = couch_util:json_decode(Body), - etap:is(true, true, "should return database info"); - _Else -> false - end. - -test_vhost_request_with_qs() -> - Url = server() ++ "doc1?revs_info=true", - case ibrowse:send_req(Url, [], get, [], [{host_header, "example.com"}]) of - {ok, _, _, Body} -> - {JsonProps} = couch_util:json_decode(Body), - HasRevsInfo = proplists:is_defined(<<"_revs_info">>, JsonProps), - etap:is(HasRevsInfo, true, "should return _revs_info"); - _Else -> false - end. - -test_vhost_request_with_global() -> - Url2 = server() ++ "_utils/index.html", - case ibrowse:send_req(Url2, [], get, [], [{host_header, "example.com"}]) of - {ok, _, _, Body2} -> - " false - end. -- cgit v1.2.3