diff options
Diffstat (limited to 'test/etap')
60 files changed, 0 insertions, 7214 deletions
diff --git a/test/etap/001-load.t b/test/etap/001-load.t deleted file mode 100755 index 6f49e1ba..00000000 --- a/test/etap/001-load.t +++ /dev/null @@ -1,68 +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. - -% Test that we can load each module. - -main(_) -> - test_util:init_code_path(), - etap:plan(37), - Modules = [ - couch_btree, - couch_config, - couch_config_writer, - couch_db, - couch_db_update_notifier, - couch_db_update_notifier_sup, - couch_db_updater, - couch_doc, - couch_event_sup, - couch_external_manager, - couch_external_server, - couch_file, - couch_httpd, - couch_httpd_db, - couch_httpd_external, - couch_httpd_misc_handlers, - couch_httpd_show, - couch_httpd_stats_handlers, - couch_httpd_view, - couch_key_tree, - couch_log, - couch_os_process, - couch_query_servers, - couch_ref_counter, - couch_rep, - couch_rep_sup, - couch_server, - couch_server_sup, - couch_stats_aggregator, - couch_stats_collector, - couch_stream, - couch_task_status, - couch_util, - couch_view, - couch_view_compactor, - couch_view_group, - couch_view_updater - ], - - lists:foreach( - fun(Module) -> - etap_can:loaded_ok( - Module, - lists:concat(["Loaded: ", Module]) - ) - end, Modules), - etap:end_tests(). diff --git a/test/etap/002-icu-driver.t b/test/etap/002-icu-driver.t deleted file mode 100644 index d70f3303..00000000 --- a/test/etap/002-icu-driver.t +++ /dev/null @@ -1,33 +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. - - -main(_) -> - test_util:init_code_path(), - etap:plan(3), - etap:is( - couch_util:start_driver("src/couchdb/priv/.libs"), - ok, - "Started couch_icu_driver." - ), - etap:is( - couch_util:collate(<<"foo">>, <<"bar">>), - 1, - "Can collate stuff" - ), - etap:is( - couch_util:collate(<<"A">>, <<"aa">>), - -1, - "Collate's non-ascii style." - ), - etap:end_tests(). diff --git a/test/etap/010-file-basics.t b/test/etap/010-file-basics.t deleted file mode 100755 index ed71f5e8..00000000 --- a/test/etap/010-file-basics.t +++ /dev/null @@ -1,108 +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. - -filename() -> test_util:build_file("test/etap/temp.010"). - -main(_) -> - test_util:init_code_path(), - etap:plan(19), - case (catch test()) of - ok -> - etap:end_tests(); - Other -> - etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), - etap:bail() - end, - ok. - -test() -> - etap:is({error, enoent}, couch_file:open("not a real file"), - "Opening a non-existant file should return an enoent error."), - - etap:fun_is( - fun({ok, _}) -> true; (_) -> false end, - couch_file:open(filename() ++ ".1", [create, invalid_option]), - "Invalid flags to open are ignored." - ), - - {ok, Fd} = couch_file:open(filename() ++ ".0", [create, overwrite]), - etap:ok(is_pid(Fd), - "Returned file descriptor is a Pid"), - - etap:is({ok, 0}, couch_file:bytes(Fd), - "Newly created files have 0 bytes."), - - etap:is({ok, 0}, couch_file:append_term(Fd, foo), - "Appending a term returns the previous end of file position."), - - {ok, Size} = couch_file:bytes(Fd), - etap:is_greater(Size, 0, - "Writing a term increased the file size."), - - etap:is({ok, Size}, couch_file:append_binary(Fd, <<"fancy!">>), - "Appending a binary returns the current file size."), - - etap:is({ok, foo}, couch_file:pread_term(Fd, 0), - "Reading the first term returns what we wrote: foo"), - - etap:is({ok, <<"fancy!">>}, couch_file:pread_binary(Fd, Size), - "Reading back the binary returns what we wrote: <<\"fancy\">>."), - - etap:is({ok, <<131, 100, 0, 3, 102, 111, 111>>}, - couch_file:pread_binary(Fd, 0), - "Reading a binary at a term position returns the term as binary." - ), - - {ok, BinPos} = couch_file:append_binary(Fd, <<131,100,0,3,102,111,111>>), - etap:is({ok, foo}, couch_file:pread_term(Fd, BinPos), - "Reading a term from a written binary term representation succeeds."), - - BigBin = list_to_binary(lists:duplicate(100000, 0)), - {ok, BigBinPos} = couch_file:append_binary(Fd, BigBin), - etap:is({ok, BigBin}, couch_file:pread_binary(Fd, BigBinPos), - "Reading a large term from a written representation succeeds."), - - ok = couch_file:write_header(Fd, hello), - etap:is({ok, hello}, couch_file:read_header(Fd), - "Reading a header succeeds."), - - {ok, BigBinPos2} = couch_file:append_binary(Fd, BigBin), - etap:is({ok, BigBin}, couch_file:pread_binary(Fd, BigBinPos2), - "Reading a large term from a written representation succeeds 2."), - - % append_binary == append_iolist? - % Possible bug in pread_iolist or iolist() -> append_binary - {ok, IOLPos} = couch_file:append_binary(Fd, ["foo", $m, <<"bam">>]), - {ok, IoList} = couch_file:pread_iolist(Fd, IOLPos), - etap:is(<<"foombam">>, iolist_to_binary(IoList), - "Reading an results in a binary form of the written iolist()"), - - % XXX: How does on test fsync? - etap:is(ok, couch_file:sync(Fd), - "Syncing does not cause an error."), - - etap:is(ok, couch_file:truncate(Fd, Size), - "Truncating a file succeeds."), - - %etap:is(eof, (catch couch_file:pread_binary(Fd, Size)), - % "Reading data that was truncated fails.") - etap:skip(fun() -> ok end, - "No idea how to test reading beyond EOF"), - - etap:is({ok, foo}, couch_file:pread_term(Fd, 0), - "Truncating does not affect data located before the truncation mark."), - - etap:is(ok, couch_file:close(Fd), - "Files close properly."), - ok. diff --git a/test/etap/011-file-headers.t b/test/etap/011-file-headers.t deleted file mode 100755 index 4705f629..00000000 --- a/test/etap/011-file-headers.t +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env escript -%% -*- erlang -*- -%%! -pa ./src/couchdb -sasl errlog_type error -boot start_sasl -noshell - -% 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. - -filename() -> test_util:build_file("test/etap/temp.011"). -sizeblock() -> 4096. % Need to keep this in sync with couch_file.erl - -main(_) -> - test_util:init_code_path(), - {S1, S2, S3} = now(), - random:seed(S1, S2, S3), - - 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() -> - {ok, Fd} = couch_file:open(filename(), [create,overwrite]), - - etap:is({ok, 0}, couch_file:bytes(Fd), - "File should be initialized to contain zero bytes."), - - etap:is(ok, couch_file:write_header(Fd, {<<"some_data">>, 32}), - "Writing a header succeeds."), - - {ok, Size1} = couch_file:bytes(Fd), - etap:is_greater(Size1, 0, - "Writing a header allocates space in the file."), - - etap:is({ok, {<<"some_data">>, 32}}, couch_file:read_header(Fd), - "Reading the header returns what we wrote."), - - etap:is(ok, couch_file:write_header(Fd, [foo, <<"more">>]), - "Writing a second header succeeds."), - - {ok, Size2} = couch_file:bytes(Fd), - etap:is_greater(Size2, Size1, - "Writing a second header allocates more space."), - - etap:is({ok, [foo, <<"more">>]}, couch_file:read_header(Fd), - "Reading the second header does not return the first header."), - - % Delete the second header. - ok = couch_file:truncate(Fd, Size1), - - etap:is({ok, {<<"some_data">>, 32}}, couch_file:read_header(Fd), - "Reading the header after a truncation returns a previous header."), - - couch_file:write_header(Fd, [foo, <<"more">>]), - etap:is({ok, Size2}, couch_file:bytes(Fd), - "Rewriting the same second header returns the same second size."), - - ok = couch_file:close(Fd), - - % Now for the fun stuff. Try corrupting the second header and see - % if we recover properly. - - % Destroy the 0x1 byte that marks a header - check_header_recovery(fun(CouchFd, RawFd, Expect, HeaderPos) -> - etap:isnt(Expect, couch_file:read_header(CouchFd), - "Should return a different header before corruption."), - file:pwrite(RawFd, HeaderPos, <<0>>), - etap:is(Expect, couch_file:read_header(CouchFd), - "Corrupting the byte marker should read the previous header.") - end), - - % Corrupt the size. - check_header_recovery(fun(CouchFd, RawFd, Expect, HeaderPos) -> - etap:isnt(Expect, couch_file:read_header(CouchFd), - "Should return a different header before corruption."), - % +1 for 0x1 byte marker - file:pwrite(RawFd, HeaderPos+1, <<10/integer>>), - etap:is(Expect, couch_file:read_header(CouchFd), - "Corrupting the size should read the previous header.") - end), - - % Corrupt the MD5 signature - check_header_recovery(fun(CouchFd, RawFd, Expect, HeaderPos) -> - etap:isnt(Expect, couch_file:read_header(CouchFd), - "Should return a different header before corruption."), - % +5 = +1 for 0x1 byte and +4 for term size. - file:pwrite(RawFd, HeaderPos+5, <<"F01034F88D320B22">>), - etap:is(Expect, couch_file:read_header(CouchFd), - "Corrupting the MD5 signature should read the previous header.") - end), - - % Corrupt the data - check_header_recovery(fun(CouchFd, RawFd, Expect, HeaderPos) -> - etap:isnt(Expect, couch_file:read_header(CouchFd), - "Should return a different header before corruption."), - % +21 = +1 for 0x1 byte, +4 for term size and +16 for MD5 sig - file:pwrite(RawFd, HeaderPos+21, <<"some data goes here!">>), - etap:is(Expect, couch_file:read_header(CouchFd), - "Corrupting the header data should read the previous header.") - end), - - ok. - -check_header_recovery(CheckFun) -> - {ok, Fd} = couch_file:open(filename(), [create,overwrite]), - {ok, RawFd} = file:open(filename(), [read, write, raw, binary]), - - {ok, _} = write_random_data(Fd), - ExpectHeader = {some_atom, <<"a binary">>, 756}, - ok = couch_file:write_header(Fd, ExpectHeader), - - {ok, HeaderPos} = write_random_data(Fd), - ok = couch_file:write_header(Fd, {2342, <<"corruption! greed!">>}), - - CheckFun(Fd, RawFd, {ok, ExpectHeader}, HeaderPos), - - ok = file:close(RawFd), - ok = couch_file:close(Fd), - ok. - -write_random_data(Fd) -> - write_random_data(Fd, 100 + random:uniform(1000)). - -write_random_data(Fd, 0) -> - {ok, Bytes} = couch_file:bytes(Fd), - {ok, (1 + Bytes div sizeblock()) * sizeblock()}; -write_random_data(Fd, N) -> - Choices = [foo, bar, <<"bizzingle">>, "bank", ["rough", stuff]], - Term = lists:nth(random:uniform(4) + 1, Choices), - {ok, _} = couch_file:append_term(Fd, Term), - write_random_data(Fd, N-1). - diff --git a/test/etap/020-btree-basics.t b/test/etap/020-btree-basics.t deleted file mode 100755 index 18c4a836..00000000 --- a/test/etap/020-btree-basics.t +++ /dev/null @@ -1,205 +0,0 @@ -#!/usr/bin/env escript -%% -*- erlang -*- -%%! -pa ./src/couchdb -sasl errlog_type error -boot start_sasl -noshell - -% 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. - -filename() -> test_util:build_file("test/etap/temp.020"). -rows() -> 250. - --record(btree, {fd, root, extract_kv, assemble_kv, less, reduce}). - -main(_) -> - test_util:init_code_path(), - etap:plan(48), - case (catch test()) of - ok -> - etap:end_tests(); - Other -> - etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), - etap:bail() - end, - ok. - -%% @todo Determine if this number should be greater to see if the btree was -%% broken into multiple nodes. AKA "How do we appropiately detect if multiple -%% nodes were created." -test()-> - Sorted = [{Seq, random:uniform()} || Seq <- lists:seq(1, rows())], - etap:ok(test_kvs(Sorted), "Testing sorted keys"), - etap:ok(test_kvs(lists:reverse(Sorted)), "Testing reversed sorted keys"), - etap:ok(test_kvs(shuffle(Sorted)), "Testing shuffled keys."), - ok. - -test_kvs(KeyValues) -> - ReduceFun = fun - (reduce, KVs) -> - length(KVs); - (rereduce, Reds) -> - lists:sum(Reds) - end, - - Keys = [K || {K, _} <- KeyValues], - - {ok, Fd} = couch_file:open(filename(), [create,overwrite]), - {ok, Btree} = couch_btree:open(nil, Fd), - etap:ok(is_record(Btree, btree), "Created btree is really a btree record"), - etap:is(Btree#btree.fd, Fd, "Btree#btree.fd is set correctly."), - etap:is(Btree#btree.root, nil, "Btree#btree.root is set correctly."), - - Btree1 = couch_btree:set_options(Btree, [{reduce, ReduceFun}]), - etap:is(Btree1#btree.reduce, ReduceFun, "Reduce function was set"), - {ok, _, EmptyRes} = couch_btree:foldl(Btree1, fun(_, X) -> {ok, X+1} end, 0), - etap:is(EmptyRes, 0, "Folding over an empty btree"), - - {ok, Btree2} = couch_btree:add_remove(Btree1, KeyValues, []), - etap:ok(test_btree(Btree2, KeyValues), - "Adding all keys at once returns a complete btree."), - - etap:fun_is( - fun - ({ok, {kp_node, _}}) -> true; - (_) -> false - end, - couch_file:pread_term(Fd, element(1, Btree2#btree.root)), - "Btree root pointer is a kp_node." - ), - - {ok, Btree3} = couch_btree:add_remove(Btree2, [], Keys), - etap:ok(test_btree(Btree3, []), - "Removing all keys at once returns an empty btree."), - - Btree4 = lists:foldl(fun(KV, BtAcc) -> - {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [KV], []), - BtAcc2 - end, Btree3, KeyValues), - etap:ok(test_btree(Btree4, KeyValues), - "Adding all keys one at a time returns a complete btree."), - - Btree5 = lists:foldl(fun({K, _}, BtAcc) -> - {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [], [K]), - BtAcc2 - end, Btree4, KeyValues), - etap:ok(test_btree(Btree5, []), - "Removing all keys one at a time returns an empty btree."), - - KeyValuesRev = lists:reverse(KeyValues), - Btree6 = lists:foldl(fun(KV, BtAcc) -> - {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [KV], []), - BtAcc2 - end, Btree5, KeyValuesRev), - etap:ok(test_btree(Btree6, KeyValues), - "Adding all keys in reverse order returns a complete btree."), - - {_, Rem2Keys0, Rem2Keys1} = lists:foldl(fun(X, {Count, Left, Right}) -> - case Count rem 2 == 0 of - true-> {Count+1, [X | Left], Right}; - false -> {Count+1, Left, [X | Right]} - end - end, {0, [], []}, KeyValues), - - etap:ok(test_add_remove(Btree6, Rem2Keys0, Rem2Keys1), - "Add/Remove every other key."), - - etap:ok(test_add_remove(Btree6, Rem2Keys1, Rem2Keys0), - "Add/Remove opposite every other key."), - - {ok, Btree7} = couch_btree:add_remove(Btree6, [], [K||{K,_}<-Rem2Keys1]), - {ok, Btree8} = couch_btree:add_remove(Btree7, [], [K||{K,_}<-Rem2Keys0]), - etap:ok(test_btree(Btree8, []), - "Removing both halves of every other key returns an empty btree."), - - %% Third chunk (close out) - etap:is(couch_file:close(Fd), ok, "closing out"), - true. - -test_btree(Btree, KeyValues) -> - ok = test_key_access(Btree, KeyValues), - ok = test_lookup_access(Btree, KeyValues), - ok = test_final_reductions(Btree, KeyValues), - true. - -test_add_remove(Btree, OutKeyValues, RemainingKeyValues) -> - Btree2 = lists:foldl(fun({K, _}, BtAcc) -> - {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [], [K]), - BtAcc2 - end, Btree, OutKeyValues), - true = test_btree(Btree2, RemainingKeyValues), - - Btree3 = lists:foldl(fun(KV, BtAcc) -> - {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [KV], []), - BtAcc2 - end, Btree2, OutKeyValues), - true = test_btree(Btree3, OutKeyValues ++ RemainingKeyValues). - -test_key_access(Btree, List) -> - FoldFun = fun(Element, {[HAcc|TAcc], Count}) -> - case Element == HAcc of - true -> {ok, {TAcc, Count + 1}}; - _ -> {ok, {TAcc, Count + 1}} - end - end, - Length = length(List), - Sorted = lists:sort(List), - {ok, _, {[], Length}} = couch_btree:foldl(Btree, FoldFun, {Sorted, 0}), - {ok, _, {[], Length}} = couch_btree:fold(Btree, FoldFun, {Sorted, 0}, [{dir, rev}]), - ok. - -test_lookup_access(Btree, KeyValues) -> - FoldFun = fun({Key, Value}, {Key, Value}) -> {stop, true} end, - lists:foreach(fun({Key, Value}) -> - [{ok, {Key, Value}}] = couch_btree:lookup(Btree, [Key]), - {ok, _, true} = couch_btree:foldl(Btree, FoldFun, {Key, Value}, [{start_key, Key}]) - end, KeyValues). - -test_final_reductions(Btree, KeyValues) -> - KVLen = length(KeyValues), - FoldLFun = fun(_X, LeadingReds, Acc) -> - CountToStart = KVLen div 3 + Acc, - CountToStart = couch_btree:final_reduce(Btree, LeadingReds), - {ok, Acc+1} - end, - FoldRFun = fun(_X, LeadingReds, Acc) -> - CountToEnd = KVLen - KVLen div 3 + Acc, - CountToEnd = couch_btree:final_reduce(Btree, LeadingReds), - {ok, Acc+1} - end, - {LStartKey, _} = case KVLen of - 0 -> {nil, nil}; - _ -> lists:nth(KVLen div 3 + 1, lists:sort(KeyValues)) - end, - {RStartKey, _} = case KVLen of - 0 -> {nil, nil}; - _ -> lists:nth(KVLen div 3, lists:sort(KeyValues)) - end, - {ok, _, FoldLRed} = couch_btree:foldl(Btree, FoldLFun, 0, [{start_key, LStartKey}]), - {ok, _, FoldRRed} = couch_btree:fold(Btree, FoldRFun, 0, [{dir, rev}, {start_key, RStartKey}]), - KVLen = FoldLRed + FoldRRed, - ok. - -shuffle(List) -> - randomize(round(math:log(length(List)) + 0.5), List). - -randomize(1, List) -> - randomize(List); -randomize(T, List) -> - lists:foldl(fun(_E, Acc) -> - randomize(Acc) - end, randomize(List), lists:seq(1, (T - 1))). - -randomize(List) -> - D = lists:map(fun(A) -> - {random:uniform(), A} - end, List), - {_, D1} = lists:unzip(lists:keysort(1, D)), - D1. diff --git a/test/etap/021-btree-reductions.t b/test/etap/021-btree-reductions.t deleted file mode 100755 index 331e49af..00000000 --- a/test/etap/021-btree-reductions.t +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env escript -%% -*- erlang -*- -%%! -pa ./src/couchdb -sasl errlog_type error -boot start_sasl -noshell - -% 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. - -filename() -> "./test/etap/temp.021". -rows() -> 1000. - -main(_) -> - test_util:init_code_path(), - etap:plan(8), - case (catch test()) of - ok -> - etap:end_tests(); - Other -> - etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), - etap:bail() - end, - ok. - -test()-> - ReduceFun = fun - (reduce, KVs) -> length(KVs); - (rereduce, Reds) -> lists:sum(Reds) - end, - - {ok, Fd} = couch_file:open(filename(), [create,overwrite]), - {ok, Btree} = couch_btree:open(nil, Fd, [{reduce, ReduceFun}]), - - % Create a list, of {"even", Value} or {"odd", Value} pairs. - {_, EvenOddKVs} = lists:foldl(fun(Idx, {Key, Acc}) -> - case Key of - "even" -> {"odd", [{{Key, Idx}, 1} | Acc]}; - _ -> {"even", [{{Key, Idx}, 1} | Acc]} - end - end, {"odd", []}, lists:seq(1, rows())), - - {ok, Btree2} = couch_btree:add_remove(Btree, EvenOddKVs, []), - - GroupFun = fun({K1, _}, {K2, _}) -> K1 == K2 end, - FoldFun = fun(GroupedKey, Unreduced, Acc) -> - {ok, [{GroupedKey, couch_btree:final_reduce(Btree2, Unreduced)} | Acc]} - end, - - {SK1, EK1} = {{"even", -1}, {"even", foo}}, - {SK2, EK2} = {{"odd", -1}, {"odd", foo}}, - - etap:fun_is( - fun - ({ok, [{{"odd", _}, 500}, {{"even", _}, 500}]}) -> - true; - (_) -> - false - end, - couch_btree:fold_reduce(Btree2, FoldFun, [], [{key_group_fun, GroupFun}]), - "Reduction works with no specified direction, startkey, or endkey." - ), - - etap:fun_is( - fun - ({ok, [{{"odd", _}, 500}, {{"even", _}, 500}]}) -> - true; - (_) -> - false - end, - couch_btree:fold_reduce(Btree2, FoldFun, [], [{key_group_fun, GroupFun}, {dir, fwd}]), - "Reducing forward works with no startkey or endkey." - ), - - etap:fun_is( - fun - ({ok, [{{"even", _}, 500}, {{"odd", _}, 500}]}) -> - true; - (_) -> - false - end, - couch_btree:fold_reduce(Btree2, FoldFun, [], [{key_group_fun, GroupFun}, {dir, rev}]), - "Reducing backwards works with no startkey or endkey." - ), - - etap:fun_is( - fun - ({ok, [{{"odd", _}, 500}, {{"even", _}, 500}]}) -> - true; - (_) -> - false - end, - couch_btree:fold_reduce(Btree2, FoldFun, [], [{dir, fwd}, {key_group_fun, GroupFun}, {start_key, SK1}, {end_key, EK2}]), - "Reducing works over the entire range with startkey and endkey set." - ), - - etap:fun_is( - fun - ({ok, [{{"even", _}, 500}]}) -> true; - (_) -> false - end, - couch_btree:fold_reduce(Btree2, FoldFun, [], [{dir, fwd}, {key_group_fun, GroupFun}, {start_key, SK1}, {end_key, EK1}]), - "Reducing forward over first half works with a startkey and endkey." - ), - - etap:fun_is( - fun - ({ok, [{{"odd", _}, 500}]}) -> true; - (_) -> false - end, - couch_btree:fold_reduce(Btree2, FoldFun, [], [{dir, fwd}, {key_group_fun, GroupFun}, {start_key, SK2}, {end_key, EK2}]), - "Reducing forward over second half works with second startkey and endkey" - ), - - etap:fun_is( - fun - ({ok, [{{"odd", _}, 500}]}) -> true; - (_) -> false - end, - couch_btree:fold_reduce(Btree2, FoldFun, [], [{dir, rev}, {key_group_fun, GroupFun}, {start_key, EK2}, {end_key, SK2}]), - "Reducing in reverse works after swapping the startkey and endkey." - ), - - etap:fun_is( - fun - ({ok, [{{"even", _}, 500}, {{"odd", _}, 500}]}) -> - true; - (_) -> - false - end, - couch_btree:fold_reduce(Btree2, FoldFun, [], [{dir, rev}, {key_group_fun, GroupFun}, {start_key, EK2}, {end_key, SK1}]), - "Reducing in reverse results in reversed accumulator." - ), - - couch_file:close(Fd). diff --git a/test/etap/030-doc-from-json.t b/test/etap/030-doc-from-json.t deleted file mode 100755 index b0c393ef..00000000 --- a/test/etap/030-doc-from-json.t +++ /dev/null @@ -1,236 +0,0 @@ -#!/usr/bin/env escript -%% -*- erlang -*- -%%! -pa ./src/couchdb -pa ./src/mochiweb -sasl errlog_type false -noshell - -% 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={[]}, - atts=[], deleted=false, meta=[]}). --record(att, {name, type, att_len, disk_len, md5= <<>>, revpos=0, data, - encoding=identity}). - -main(_) -> - test_util:init_code_path(), - etap:plan(26), - 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(test_util:config_files()), - couch_config:set("attachments", "compression_level", "0", false), - ok = test_from_json_success(), - ok = test_from_json_errors(), - ok. - -test_from_json_success() -> - Cases = [ - { - {[]}, - #doc{}, - "Return an empty document for an empty JSON object." - }, - { - {[{<<"_id">>, <<"zing!">>}]}, - #doc{id= <<"zing!">>}, - "Parses document ids." - }, - { - {[{<<"_id">>, <<"_design/foo">>}]}, - #doc{id= <<"_design/foo">>}, - "_design/document ids." - }, - { - {[{<<"_id">>, <<"_local/bam">>}]}, - #doc{id= <<"_local/bam">>}, - "_local/document ids." - }, - { - {[{<<"_rev">>, <<"4-230234">>}]}, - #doc{revs={4, [<<"230234">>]}}, - "_rev stored in revs." - }, - { - {[{<<"soap">>, 35}]}, - #doc{body={[{<<"soap">>, 35}]}}, - "Non underscore prefixed fields stored in body." - }, - { - {[{<<"_attachments">>, {[ - {<<"my_attachment.fu">>, {[ - {<<"stub">>, true}, - {<<"content_type">>, <<"application/awesome">>}, - {<<"length">>, 45} - ]}}, - {<<"noahs_private_key.gpg">>, {[ - {<<"data">>, <<"SSBoYXZlIGEgcGV0IGZpc2gh">>}, - {<<"content_type">>, <<"application/pgp-signature">>} - ]}} - ]}}]}, - #doc{atts=[ - #att{ - name = <<"my_attachment.fu">>, - data = stub, - type = <<"application/awesome">>, - att_len = 45, - disk_len = 45, - revpos = nil - }, - #att{ - name = <<"noahs_private_key.gpg">>, - data = <<"I have a pet fish!">>, - type = <<"application/pgp-signature">>, - att_len = 18, - disk_len = 18, - revpos = 0 - } - ]}, - "Attachments are parsed correctly." - }, - { - {[{<<"_deleted">>, true}]}, - #doc{deleted=true}, - "_deleted controls the deleted field." - }, - { - {[{<<"_deleted">>, false}]}, - #doc{}, - "{\"_deleted\": false} is ok." - }, - { - {[ - {<<"_revisions">>, {[ - {<<"start">>, 4}, - {<<"ids">>, [<<"foo1">>, <<"phi3">>, <<"omega">>]} - ]}}, - {<<"_rev">>, <<"6-something">>} - ]}, - #doc{revs={4, [<<"foo1">>, <<"phi3">>, <<"omega">>]}}, - "_revisions attribute are preferred to _rev." - }, - { - {[{<<"_revs_info">>, dropping}]}, - #doc{}, - "Drops _revs_info." - }, - { - {[{<<"_local_seq">>, dropping}]}, - #doc{}, - "Drops _local_seq." - }, - { - {[{<<"_conflicts">>, dropping}]}, - #doc{}, - "Drops _conflicts." - }, - { - {[{<<"_deleted_conflicts">>, dropping}]}, - #doc{}, - "Drops _deleted_conflicts." - } - ], - - lists:foreach(fun({EJson, Expect, Mesg}) -> - etap:is(couch_doc:from_json_obj(EJson), Expect, Mesg) - end, Cases), - ok. - -test_from_json_errors() -> - Cases = [ - { - [], - {bad_request, "Document must be a JSON object"}, - "arrays are invalid" - }, - { - 4, - {bad_request, "Document must be a JSON object"}, - "integers are invalid" - }, - { - true, - {bad_request, "Document must be a JSON object"}, - "literals are invalid" - }, - { - {[{<<"_id">>, {[{<<"foo">>, 5}]}}]}, - {bad_request, <<"Document id must be a string">>}, - "Document id must be a string." - }, - { - {[{<<"_id">>, <<"_random">>}]}, - {bad_request, - <<"Only reserved document ids may start with underscore.">>}, - "Disallow arbitrary underscore prefixed docids." - }, - { - {[{<<"_rev">>, 5}]}, - {bad_request, <<"Invalid rev format">>}, - "_rev must be a string" - }, - { - {[{<<"_rev">>, "foobar"}]}, - {bad_request, <<"Invalid rev format">>}, - "_rev must be %d-%s" - }, - { - {[{<<"_rev">>, "foo-bar"}]}, - "Error if _rev's integer expection is broken." - }, - { - {[{<<"_revisions">>, {[{<<"start">>, true}]}}]}, - {doc_validation, "_revisions.start isn't an integer."}, - "_revisions.start must be an integer." - }, - { - {[{<<"_revisions">>, {[ - {<<"start">>, 0}, - {<<"ids">>, 5} - ]}}]}, - {doc_validation, "_revisions.ids isn't a array."}, - "_revions.ids must be a list." - }, - { - {[{<<"_revisions">>, {[ - {<<"start">>, 0}, - {<<"ids">>, [5]} - ]}}]}, - {doc_validation, "RevId isn't a string"}, - "Revision ids must be strings." - }, - { - {[{<<"_something">>, 5}]}, - {doc_validation, <<"Bad special document member: _something">>}, - "Underscore prefix fields are reserved." - } - ], - - lists:foreach(fun - ({EJson, Expect, Mesg}) -> - Error = (catch couch_doc:from_json_obj(EJson)), - etap:is(Error, Expect, Mesg); - ({EJson, Mesg}) -> - try - couch_doc:from_json_obj(EJson), - etap:ok(false, "Conversion failed to raise an exception.") - catch - _:_ -> etap:ok(true, Mesg) - end - end, Cases), - ok. diff --git a/test/etap/031-doc-to-json.t b/test/etap/031-doc-to-json.t deleted file mode 100755 index ce950f95..00000000 --- a/test/etap/031-doc-to-json.t +++ /dev/null @@ -1,197 +0,0 @@ -#!/usr/bin/env escript -%% -*- erlang -*- -%%! -pa ./src/couchdb -pa ./src/mochiweb -sasl errlog_type false -noshell - -% 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={[]}, - atts=[], deleted=false, meta=[]}). --record(att, {name, type, att_len, disk_len, md5= <<>>, revpos=0, data, - encoding=identity}). - -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() - end, - ok. - -test() -> - couch_config:start_link(test_util:config_files()), - couch_config:set("attachments", "compression_level", "0", false), - ok = test_to_json_success(), - ok. - -test_to_json_success() -> - Cases = [ - { - #doc{}, - {[{<<"_id">>, <<"">>}]}, - "Empty docs are {\"_id\": \"\"}" - }, - { - #doc{id= <<"foo">>}, - {[{<<"_id">>, <<"foo">>}]}, - "_id is added." - }, - { - #doc{revs={5, ["foo"]}}, - {[{<<"_id">>, <<>>}, {<<"_rev">>, <<"5-foo">>}]}, - "_rev is added." - }, - { - [revs], - #doc{revs={5, [<<"first">>, <<"second">>]}}, - {[ - {<<"_id">>, <<>>}, - {<<"_rev">>, <<"5-first">>}, - {<<"_revisions">>, {[ - {<<"start">>, 5}, - {<<"ids">>, [<<"first">>, <<"second">>]} - ]}} - ]}, - "_revisions include with revs option" - }, - { - #doc{body={[{<<"foo">>, <<"bar">>}]}}, - {[{<<"_id">>, <<>>}, {<<"foo">>, <<"bar">>}]}, - "Arbitrary fields are added." - }, - { - #doc{deleted=true, body={[{<<"foo">>, <<"bar">>}]}}, - {[{<<"_id">>, <<>>}, {<<"foo">>, <<"bar">>}, {<<"_deleted">>, true}]}, - "Deleted docs no longer drop body members." - }, - { - #doc{meta=[ - {revs_info, 4, [{<<"fin">>, deleted}, {<<"zim">>, missing}]} - ]}, - {[ - {<<"_id">>, <<>>}, - {<<"_revs_info">>, [ - {[{<<"rev">>, <<"4-fin">>}, {<<"status">>, <<"deleted">>}]}, - {[{<<"rev">>, <<"3-zim">>}, {<<"status">>, <<"missing">>}]} - ]} - ]}, - "_revs_info field is added correctly." - }, - { - #doc{meta=[{local_seq, 5}]}, - {[{<<"_id">>, <<>>}, {<<"_local_seq">>, 5}]}, - "_local_seq is added as an integer." - }, - { - #doc{meta=[{conflicts, [{3, <<"yep">>}, {1, <<"snow">>}]}]}, - {[ - {<<"_id">>, <<>>}, - {<<"_conflicts">>, [<<"3-yep">>, <<"1-snow">>]} - ]}, - "_conflicts is added as an array of strings." - }, - { - #doc{meta=[{deleted_conflicts, [{10923, <<"big_cowboy_hat">>}]}]}, - {[ - {<<"_id">>, <<>>}, - {<<"_deleted_conflicts">>, [<<"10923-big_cowboy_hat">>]} - ]}, - "_deleted_conflicsts is added as an array of strings." - }, - { - #doc{atts=[ - #att{ - name = <<"big.xml">>, - type = <<"xml/sucks">>, - data = fun() -> ok end, - revpos = 1, - att_len = 400, - disk_len = 400 - }, - #att{ - name = <<"fast.json">>, - type = <<"json/ftw">>, - data = <<"{\"so\": \"there!\"}">>, - revpos = 1, - att_len = 16, - disk_len = 16 - } - ]}, - {[ - {<<"_id">>, <<>>}, - {<<"_attachments">>, {[ - {<<"big.xml">>, {[ - {<<"content_type">>, <<"xml/sucks">>}, - {<<"revpos">>, 1}, - {<<"length">>, 400}, - {<<"stub">>, true} - ]}}, - {<<"fast.json">>, {[ - {<<"content_type">>, <<"json/ftw">>}, - {<<"revpos">>, 1}, - {<<"length">>, 16}, - {<<"stub">>, true} - ]}} - ]}} - ]}, - "Attachments attached as stubs only include a length." - }, - { - [attachments], - #doc{atts=[ - #att{ - name = <<"stuff.txt">>, - type = <<"text/plain">>, - data = fun() -> <<"diet pepsi">> end, - revpos = 1, - att_len = 10, - disk_len = 10 - }, - #att{ - name = <<"food.now">>, - type = <<"application/food">>, - revpos = 1, - data = <<"sammich">> - } - ]}, - {[ - {<<"_id">>, <<>>}, - {<<"_attachments">>, {[ - {<<"stuff.txt">>, {[ - {<<"content_type">>, <<"text/plain">>}, - {<<"revpos">>, 1}, - {<<"data">>, <<"ZGlldCBwZXBzaQ==">>} - ]}}, - {<<"food.now">>, {[ - {<<"content_type">>, <<"application/food">>}, - {<<"revpos">>, 1}, - {<<"data">>, <<"c2FtbWljaA==">>} - ]}} - ]}} - ]}, - "Attachments included inline with attachments option." - } - ], - - lists:foreach(fun - ({Doc, EJson, Mesg}) -> - etap:is(couch_doc:to_json_obj(Doc, []), EJson, Mesg); - ({Options, Doc, EJson, Mesg}) -> - etap:is(couch_doc:to_json_obj(Doc, Options), EJson, Mesg) - end, Cases), - ok. - diff --git a/test/etap/040-util.t b/test/etap/040-util.t deleted file mode 100755 index 8f80db87..00000000 --- a/test/etap/040-util.t +++ /dev/null @@ -1,80 +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(), - application:start(crypto), - - etap:plan(14), - 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() -> - % to_existing_atom - etap:is(true, couch_util:to_existing_atom(true), "An atom is an atom."), - etap:is(foo, couch_util:to_existing_atom(<<"foo">>), - "A binary foo is the atom foo."), - etap:is(foobarbaz, couch_util:to_existing_atom("foobarbaz"), - "A list of atoms is one munged atom."), - - % implode - etap:is([1, 38, 2, 38, 3], couch_util:implode([1,2,3],"&"), - "use & as separator in list."), - - % trim - Strings = [" foo", "foo ", "\tfoo", " foo ", "foo\t", "foo\n", "\nfoo"], - etap:ok(lists:all(fun(S) -> couch_util:trim(S) == "foo" end, Strings), - "everything here trimmed should be foo."), - - % abs_pathname - {ok, Cwd} = file:get_cwd(), - etap:is(Cwd ++ "/foo", couch_util:abs_pathname("./foo"), - "foo is in this directory."), - - % should_flush - etap:ok(not couch_util:should_flush(), - "Not using enough memory to flush."), - AcquireMem = fun() -> - IntsToAGazillion = lists:seq(1, 200000), - LotsOfData = lists:map( - fun(Int) -> {Int, <<"foobar">>} end, - lists:seq(1, 500000)), - etap:ok(couch_util:should_flush(), - "Allocation 200K tuples puts us above the memory threshold.") - end, - AcquireMem(), - - etap:ok(not couch_util:should_flush(), - "Checking to flush invokes GC."), - - % verify - etap:is(true, couch_util:verify("It4Vooya", "It4Vooya"), - "String comparison."), - etap:is(false, couch_util:verify("It4VooyaX", "It4Vooya"), - "String comparison (unequal lengths)."), - etap:is(true, couch_util:verify(<<"ahBase3r">>, <<"ahBase3r">>), - "Binary comparison."), - etap:is(false, couch_util:verify(<<"ahBase3rX">>, <<"ahBase3r">>), - "Binary comparison (unequal lengths)."), - etap:is(false, couch_util:verify(nil, <<"ahBase3r">>), - "Binary comparison with atom."), - - ok. diff --git a/test/etap/041-uuid-gen-seq.ini b/test/etap/041-uuid-gen-seq.ini deleted file mode 100644 index 94cebc6f..00000000 --- a/test/etap/041-uuid-gen-seq.ini +++ /dev/null @@ -1,19 +0,0 @@ -; Licensed to the Apache Software Foundation (ASF) under one -; or more contributor license agreements. See the NOTICE file -; distributed with this work for additional information -; regarding copyright ownership. The ASF licenses this file -; to you 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. - -[uuids] -algorithm = sequential diff --git a/test/etap/041-uuid-gen-utc.ini b/test/etap/041-uuid-gen-utc.ini deleted file mode 100644 index c2b83831..00000000 --- a/test/etap/041-uuid-gen-utc.ini +++ /dev/null @@ -1,19 +0,0 @@ -; Licensed to the Apache Software Foundation (ASF) under one -; or more contributor license agreements. See the NOTICE file -; distributed with this work for additional information -; regarding copyright ownership. The ASF licenses this file -; to you 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. - -[uuids] -algorithm = utc_random diff --git a/test/etap/041-uuid-gen.t b/test/etap/041-uuid-gen.t deleted file mode 100755 index 1e6aa9ee..00000000 --- a/test/etap/041-uuid-gen.t +++ /dev/null @@ -1,118 +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"). - -seq_alg_config() -> - test_util:source_file("test/etap/041-uuid-gen-seq.ini"). - -utc_alg_config() -> - test_util:source_file("test/etap/041-uuid-gen-utc.ini"). - -% Run tests and wait for the gen_servers to shutdown -run_test(IniFiles, Test) -> - {ok, Pid} = couch_config:start_link(IniFiles), - erlang:monitor(process, Pid), - couch_uuids:start(), - Test(), - couch_uuids:stop(), - couch_config:stop(), - receive - {'DOWN', _, _, Pid, _} -> ok; - _Other -> etap:diag("OTHER: ~p~n", [_Other]) - after - 1000 -> throw({timeout_error, config_stop}) - end. - -main(_) -> - test_util:init_code_path(), - application:start(crypto), - 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() -> - - TestUnique = fun() -> - etap:is( - test_unique(10000, couch_uuids:new()), - true, - "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), - - TestMonotonic = fun () -> - etap:is( - couch_uuids:new() < couch_uuids:new(), - true, - "should produce monotonically increasing ids" - ) - end, - run_test([default_config(), seq_alg_config()], TestMonotonic), - run_test([default_config(), 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 - % approximately Total / (Range/2 + RangeMin) samples. - % - % In our case this works out to be 8194. (0xFFF000 / 0x7FF) - % These tests just fudge the limits for a good generator at 25% - % in either direction. Technically it should be possible to generate - % bounds that will show if your random number generator is not - % sufficiently random but I hated statistics in school. - TestRollOver = fun() -> - 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:is( - N >= 5000 andalso N =< 11000, - true, - "should roll over every so often." - ) - end, - run_test([default_config(), seq_alg_config()], TestRollOver). - -test_unique(0, _) -> - true; -test_unique(N, UUID) -> - case couch_uuids:new() of - UUID -> - etap:diag("N: ~p~n", [N]), - false; - Else -> test_unique(N-1, Else) - end. - -get_prefix(UUID) -> - element(1, lists:split(26, binary_to_list(UUID))). - -gen_until_pref_change(_, Count) when Count > 8251 -> - Count; -gen_until_pref_change(Prefix, N) -> - case get_prefix(couch_uuids:new()) of - Prefix -> gen_until_pref_change(Prefix, N+1); - _ -> N - end. diff --git a/test/etap/050-stream.t b/test/etap/050-stream.t deleted file mode 100755 index d30b524a..00000000 --- a/test/etap/050-stream.t +++ /dev/null @@ -1,87 +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(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. - -read_all(Fd, PosList) -> - Data = couch_stream:foldl(Fd, PosList, fun(Bin, Acc) -> [Bin, Acc] end, []), - iolist_to_binary(Data). - -test() -> - {ok, Fd} = couch_file:open("test/etap/temp.050", [create,overwrite]), - {ok, Stream} = couch_stream:open(Fd), - - etap:is(ok, couch_stream:write(Stream, <<"food">>), - "Writing to streams works."), - - etap:is(ok, couch_stream:write(Stream, <<"foob">>), - "Consecutive writing to streams works."), - - etap:is(ok, couch_stream:write(Stream, <<>>), - "Writing an empty binary does nothing."), - - {Ptrs, Length, _, _, _} = couch_stream:close(Stream), - etap:is(Ptrs, [{0, 8}], "Close returns the file pointers."), - etap:is(Length, 8, "Close also returns the number of bytes written."), - etap:is(<<"foodfoob">>, read_all(Fd, Ptrs), "Returned pointers are valid."), - - % Remeber where we expect the pointer to be. - {ok, ExpPtr} = couch_file:bytes(Fd), - {ok, Stream2} = couch_stream:open(Fd), - OneBits = <<1:(8*10)>>, - etap:is(ok, couch_stream:write(Stream2, OneBits), - "Successfully wrote 80 1 bits."), - - ZeroBits = <<0:(8*10)>>, - etap:is(ok, couch_stream:write(Stream2, ZeroBits), - "Successfully wrote 80 0 bits."), - - {Ptrs2, Length2, _, _, _} = couch_stream:close(Stream2), - etap:is(Ptrs2, [{ExpPtr, 20}], "Closing stream returns the file pointers."), - etap:is(Length2, 20, "Length written is 160 bytes."), - - AllBits = iolist_to_binary([OneBits,ZeroBits]), - etap:is(AllBits, read_all(Fd, Ptrs2), "Returned pointers are valid."), - - % Stream more the 4K chunk size. - {ok, ExpPtr2} = couch_file:bytes(Fd), - {ok, Stream3} = couch_stream:open(Fd), - Acc2 = lists:foldl(fun(_, Acc) -> - Data = <<"a1b2c">>, - couch_stream:write(Stream3, Data), - [Data | Acc] - end, [], lists:seq(1, 1024)), - {Ptrs3, Length3, _, _, _} = couch_stream:close(Stream3), - - % 4095 because of 5 * 4096 rem 5 (last write before exceeding threshold) - % + 5 puts us over the threshold - % + 4 bytes for the term_to_binary adding a length header - % + 1 byte every 4K for tail append headers - SecondPtr = ExpPtr2 + 4095 + 5 + 4 + 1, - etap:is(Ptrs3, [{ExpPtr2, 4100}, {SecondPtr, 1020}], "Pointers every 4K bytes."), - etap:is(Length3, 5120, "Wrote the expected 5K bytes."), - - couch_file:close(Fd), - ok. diff --git a/test/etap/060-kt-merging.t b/test/etap/060-kt-merging.t deleted file mode 100755 index efbdbf69..00000000 --- a/test/etap/060-kt-merging.t +++ /dev/null @@ -1,176 +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(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() -> - One = {1, {"1","foo",[]}}, - - etap:is( - {[One], no_conflicts}, - couch_key_tree:merge([], One, 10), - "The empty tree is the identity for merge." - ), - etap:is( - {[One], no_conflicts}, - couch_key_tree:merge([One], One, 10), - "Merging is reflexive." - ), - - TwoSibs = [{1, {"1","foo",[]}}, - {1, {"2","foo",[]}}], - - etap:is( - {TwoSibs, no_conflicts}, - couch_key_tree:merge(TwoSibs, One, 10), - "Merging a prefix of a tree with the tree yields the tree." - ), - - Three = {1, {"3","foo",[]}}, - ThreeSibs = [{1, {"1","foo",[]}}, - {1, {"2","foo",[]}}, - {1, {"3","foo",[]}}], - - etap:is( - {ThreeSibs, conflicts}, - couch_key_tree:merge(TwoSibs, Three, 10), - "Merging a third unrelated branch leads to a conflict." - ), - - - TwoChild = {1, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}}, - - etap:is( - {[TwoChild], no_conflicts}, - couch_key_tree:merge([TwoChild], TwoChild, 10), - "Merging two children is still reflexive." - ), - - TwoChildSibs = {1, {"1","foo", [{"1a", "bar", []}, - {"1b", "bar", []}]}}, - etap:is( - {[TwoChildSibs], no_conflicts}, - couch_key_tree:merge([TwoChildSibs], TwoChildSibs, 10), - "Merging a tree to itself is itself."), - - TwoChildPlusSibs = - {1, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}, - {"1b", "bar", []}]}}, - - etap:is( - {[TwoChildPlusSibs], no_conflicts}, - couch_key_tree:merge([TwoChild], TwoChildSibs, 10), - "Merging tree of uneven length at node 2."), - - Stemmed1b = {2, {"1a", "bar", []}}, - etap:is( - {[TwoChildSibs], no_conflicts}, - couch_key_tree:merge([TwoChildSibs], Stemmed1b, 10), - "Merging a tree with a stem." - ), - - TwoChildSibs2 = {1, {"1","foo", [{"1a", "bar", []}, - {"1b", "bar", [{"1bb", "boo", []}]}]}}, - Stemmed1bb = {3, {"1bb", "boo", []}}, - etap:is( - {[TwoChildSibs2], no_conflicts}, - couch_key_tree:merge([TwoChildSibs2], Stemmed1bb, 10), - "Merging a stem at a deeper level." - ), - - StemmedTwoChildSibs2 = [{2,{"1a", "bar", []}}, - {2,{"1b", "bar", [{"1bb", "boo", []}]}}], - - etap:is( - {StemmedTwoChildSibs2, no_conflicts}, - couch_key_tree:merge(StemmedTwoChildSibs2, Stemmed1bb, 10), - "Merging a stem at a deeper level against paths at deeper levels." - ), - - Stemmed1aa = {3, {"1aa", "bar", []}}, - etap:is( - {[TwoChild], no_conflicts}, - couch_key_tree:merge([TwoChild], Stemmed1aa, 10), - "Merging a single tree with a deeper stem." - ), - - Stemmed1a = {2, {"1a", "bar", [{"1aa", "bar", []}]}}, - etap:is( - {[TwoChild], no_conflicts}, - couch_key_tree:merge([TwoChild], Stemmed1a, 10), - "Merging a larger stem." - ), - - etap:is( - {[Stemmed1a], no_conflicts}, - couch_key_tree:merge([Stemmed1a], Stemmed1aa, 10), - "More merging." - ), - - OneChild = {1, {"1","foo",[{"1a", "bar", []}]}}, - Expect1 = [OneChild, Stemmed1aa], - etap:is( - {Expect1, conflicts}, - couch_key_tree:merge([OneChild], Stemmed1aa, 10), - "Merging should create conflicts." - ), - - etap:is( - {[TwoChild], no_conflicts}, - couch_key_tree:merge(Expect1, TwoChild, 10), - "Merge should have no conflicts." - ), - - %% this test is based on couch-902-test-case2.py - %% foo has conflicts from replication at depth two - %% foo3 is the current value - Foo = {1, {"foo", - "val1", - [{"foo2","val2",[]}, - {"foo3", "val3", []} - ]}}, - %% foo now has an attachment added, which leads to foo4 and val4 - %% off foo3 - Bar = {1, {"foo", - [], - [{"foo3", - [], - [{"foo4","val4",[]} - ]}]}}, - %% this is what the merge returns - %% note that it ignore the conflicting branch as there's no match - FooBar = {1, {"foo", - "val1", - [{"foo2","val2",[]}, - {"foo3", "val3", [{"foo4","val4",[]}]} - ]}}, - - etap:is( - {[FooBar], no_conflicts}, - couch_key_tree:merge([Foo],Bar,10), - "Merging trees with conflicts ought to behave." - ), - - ok. diff --git a/test/etap/061-kt-missing-leaves.t b/test/etap/061-kt-missing-leaves.t deleted file mode 100755 index d60b4db8..00000000 --- a/test/etap/061-kt-missing-leaves.t +++ /dev/null @@ -1,65 +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() -> - TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}], - Stemmed1 = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}], - Stemmed2 = [{2, {"1aa", "bar", []}}], - - etap:is( - [], - couch_key_tree:find_missing(TwoChildSibs, [{0,"1"}, {1,"1a"}]), - "Look for missing keys." - ), - - etap:is( - [{0, "10"}, {100, "x"}], - couch_key_tree:find_missing( - TwoChildSibs, - [{0,"1"}, {0, "10"}, {1,"1a"}, {100, "x"}] - ), - "Look for missing keys." - ), - - etap:is( - [{0, "1"}, {100, "x"}], - couch_key_tree:find_missing( - Stemmed1, - [{0,"1"}, {1,"1a"}, {100, "x"}] - ), - "Look for missing keys." - ), - etap:is( - [{0, "1"}, {1,"1a"}, {100, "x"}], - couch_key_tree:find_missing( - Stemmed2, - [{0,"1"}, {1,"1a"}, {100, "x"}] - ), - "Look for missing keys." - ), - - ok. diff --git a/test/etap/062-kt-remove-leaves.t b/test/etap/062-kt-remove-leaves.t deleted file mode 100755 index 745a00be..00000000 --- a/test/etap/062-kt-remove-leaves.t +++ /dev/null @@ -1,69 +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(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() -> - OneChild = [{0, {"1","foo",[{"1a", "bar", []}]}}], - TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}], - Stemmed = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}], - - etap:is( - {TwoChildSibs, []}, - couch_key_tree:remove_leafs(TwoChildSibs, []), - "Removing no leaves has no effect on the tree." - ), - - etap:is( - {TwoChildSibs, []}, - couch_key_tree:remove_leafs(TwoChildSibs, [{0, "1"}]), - "Removing a non-existant branch has no effect." - ), - - etap:is( - {OneChild, [{1, "1b"}]}, - couch_key_tree:remove_leafs(TwoChildSibs, [{1, "1b"}]), - "Removing a leaf removes the leaf." - ), - - etap:is( - {[], [{1, "1b"},{1, "1a"}]}, - couch_key_tree:remove_leafs(TwoChildSibs, [{1, "1a"}, {1, "1b"}]), - "Removing all leaves returns an empty tree." - ), - - etap:is( - {Stemmed, []}, - couch_key_tree:remove_leafs(Stemmed, [{1, "1a"}]), - "Removing a non-existant node has no effect." - ), - - etap:is( - {[], [{2, "1aa"}]}, - couch_key_tree:remove_leafs(Stemmed, [{2, "1aa"}]), - "Removing the last leaf returns an empty tree." - ), - - ok. diff --git a/test/etap/063-kt-get-leaves.t b/test/etap/063-kt-get-leaves.t deleted file mode 100755 index 6d4e8007..00000000 --- a/test/etap/063-kt-get-leaves.t +++ /dev/null @@ -1,98 +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(Other) - end, - ok. - -test() -> - TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}], - Stemmed = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}], - - etap:is( - {[{"foo", {0, ["1"]}}],[]}, - couch_key_tree:get(TwoChildSibs, [{0, "1"}]), - "extract a subtree." - ), - - etap:is( - {[{"bar", {1, ["1a", "1"]}}],[]}, - couch_key_tree:get(TwoChildSibs, [{1, "1a"}]), - "extract a subtree." - ), - - etap:is( - {[],[{0,"x"}]}, - couch_key_tree:get_key_leafs(TwoChildSibs, [{0, "x"}]), - "gather up the leaves." - ), - - etap:is( - {[{"bar", {1, ["1a","1"]}}],[]}, - couch_key_tree:get_key_leafs(TwoChildSibs, [{1, "1a"}]), - "gather up the leaves." - ), - - etap:is( - {[{"bar", {1, ["1a","1"]}},{"bar",{1, ["1b","1"]}}],[]}, - couch_key_tree:get_key_leafs(TwoChildSibs, [{0, "1"}]), - "gather up the leaves." - ), - - etap:is( - {[{0,[{"1", "foo"}]}],[]}, - couch_key_tree:get_full_key_paths(TwoChildSibs, [{0, "1"}]), - "retrieve full key paths." - ), - - etap:is( - {[{1,[{"1a", "bar"},{"1", "foo"}]}],[]}, - couch_key_tree:get_full_key_paths(TwoChildSibs, [{1, "1a"}]), - "retrieve full key paths." - ), - - etap:is( - [{2, [{"1aa", "bar"},{"1a", "bar"}]}], - couch_key_tree:get_all_leafs_full(Stemmed), - "retrieve all leaves." - ), - - etap:is( - [{1, [{"1a", "bar"},{"1", "foo"}]}, {1, [{"1b", "bar"},{"1", "foo"}]}], - couch_key_tree:get_all_leafs_full(TwoChildSibs), - "retrieve all the leaves." - ), - - etap:is( - [{"bar", {2, ["1aa","1a"]}}], - couch_key_tree:get_all_leafs(Stemmed), - "retrieve all leaves." - ), - - etap:is( - [{"bar", {1, ["1a", "1"]}}, {"bar", {1, ["1b","1"]}}], - couch_key_tree:get_all_leafs(TwoChildSibs), - "retrieve all the leaves." - ), - - ok. diff --git a/test/etap/064-kt-counting.t b/test/etap/064-kt-counting.t deleted file mode 100755 index f182d287..00000000 --- a/test/etap/064-kt-counting.t +++ /dev/null @@ -1,46 +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() -> - EmptyTree = [], - One = [{0, {"1","foo",[]}}], - TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}], - Stemmed = [{2, {"1bb", "boo", []}}], - - etap:is(0, couch_key_tree:count_leafs(EmptyTree), - "Empty trees have no leaves."), - - etap:is(1, couch_key_tree:count_leafs(One), - "Single node trees have a single leaf."), - - etap:is(2, couch_key_tree:count_leafs(TwoChildSibs), - "Two children siblings counted as two leaves."), - - etap:is(1, couch_key_tree:count_leafs(Stemmed), - "Stemming does not affect leaf counting."), - - ok. diff --git a/test/etap/065-kt-stemming.t b/test/etap/065-kt-stemming.t deleted file mode 100755 index 6e781c1d..00000000 --- a/test/etap/065-kt-stemming.t +++ /dev/null @@ -1,42 +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(3), - 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() -> - TwoChild = [{0, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}}], - Stemmed1 = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}], - Stemmed2 = [{2, {"1aa", "bar", []}}], - - etap:is(TwoChild, couch_key_tree:stem(TwoChild, 3), - "Stemming more levels than what exists does nothing."), - - etap:is(Stemmed1, couch_key_tree:stem(TwoChild, 2), - "Stemming with a depth of two returns the deepest two nodes."), - - etap:is(Stemmed2, couch_key_tree:stem(TwoChild, 1), - "Stemming to a depth of one returns the deepest node."), - - ok. diff --git a/test/etap/070-couch-db.t b/test/etap/070-couch-db.t deleted file mode 100755 index 787d6c6a..00000000 --- a/test/etap/070-couch-db.t +++ /dev/null @@ -1,73 +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(test_util:config_files()), - - 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/test/etap/080-config-get-set.t b/test/etap/080-config-get-set.t deleted file mode 100755 index a4a8577a..00000000 --- a/test/etap/080-config-get-set.t +++ /dev/null @@ -1,128 +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"). - -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() -> - % start couch_config with default - couch_config:start_link([default_config()]), - - - % Check that we can get values - - - etap:fun_is( - fun(List) -> length(List) > 0 end, - couch_config:all(), - "Data was loaded from the INI file." - ), - - etap:fun_is( - fun(List) -> length(List) > 0 end, - couch_config:get("daemons"), - "There are settings in the [daemons] section of the INI file." - ), - - etap:is( - couch_config:get("httpd_design_handlers", "_view"), - "{couch_httpd_view, handle_view_req}", - "The {httpd_design_handlers, view} is the expected default." - ), - - etap:is( - couch_config:get("httpd", "foo", "bar"), - "bar", - "Returns the default when key doesn't exist in config." - ), - - etap:is( - couch_config:get("httpd", "foo"), - undefined, - "The default default is the atom 'undefined'." - ), - - etap:is( - couch_config:get("httpd", "port", "bar"), - "5984", - "Only returns the default when the config setting does not exist." - ), - - - % Check that setting values works. - - - ok = couch_config:set("log", "level", "severe", false), - - etap:is( - couch_config:get("log", "level"), - "severe", - "Non persisted changes take effect." - ), - - etap:is( - couch_config:get("new_section", "bizzle"), - undefined, - "Section 'new_section' does not exist." - ), - - ok = couch_config:set("new_section", "bizzle", "bang", false), - - etap:is( - couch_config:get("new_section", "bizzle"), - "bang", - "New section 'new_section' was created for a new key/value pair." - ), - - - % Check that deleting works - - - ok = couch_config:delete("new_section", "bizzle", false), - etap:is( - couch_config:get("new_section", "bizzle"), - undefined, - "Deleting sets the value to \"\"" - ), - - - % Check ge/set/delete binary strings - - ok = couch_config:set(<<"foo">>, <<"bar">>, <<"baz">>, false), - etap:is( - couch_config:get(<<"foo">>, <<"bar">>), - <<"baz">>, - "Can get and set with binary section and key values." - ), - ok = couch_config:delete(<<"foo">>, <<"bar">>, false), - etap:is( - couch_config:get(<<"foo">>, <<"bar">>), - undefined, - "Deleting with binary section/key pairs sets the value to \"\"" - ), - - ok. diff --git a/test/etap/081-config-override.1.ini b/test/etap/081-config-override.1.ini deleted file mode 100644 index 55451dad..00000000 --- a/test/etap/081-config-override.1.ini +++ /dev/null @@ -1,22 +0,0 @@ -; Licensed to the Apache Software Foundation (ASF) under one -; or more contributor license agreements. See the NOTICE file -; distributed with this work for additional information -; regarding copyright ownership. The ASF licenses this file -; to you 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. - -[couchdb] -max_dbs_open=10 - -[httpd] -port=4895 diff --git a/test/etap/081-config-override.2.ini b/test/etap/081-config-override.2.ini deleted file mode 100644 index 5f46357f..00000000 --- a/test/etap/081-config-override.2.ini +++ /dev/null @@ -1,22 +0,0 @@ -; Licensed to the Apache Software Foundation (ASF) under one -; or more contributor license agreements. See the NOTICE file -; distributed with this work for additional information -; regarding copyright ownership. The ASF licenses this file -; to you 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. - -[httpd] -port = 80 - -[fizbang] -unicode = normalized diff --git a/test/etap/081-config-override.t b/test/etap/081-config-override.t deleted file mode 100755 index 01f8b4c2..00000000 --- a/test/etap/081-config-override.t +++ /dev/null @@ -1,212 +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"). - -local_config_1() -> - test_util:source_file("test/etap/081-config-override.1.ini"). - -local_config_2() -> - test_util:source_file("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) -> - {ok, Pid} = couch_config:start_link(IniFiles), - erlang:monitor(process, Pid), - Tests(), - couch_config:stop(), - receive - {'DOWN', _, _, Pid, _} -> ok; - _Other -> etap:diag("OTHER: ~p~n", [_Other]) - after - 1000 -> throw({timeout_error, config_stop}) - end. - -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(Other) - end, - ok. - -test() -> - - CheckStartStop = fun() -> ok end, - run_tests([default_config()], CheckStartStop), - - CheckDefaults = fun() -> - etap:is( - couch_config:get("couchdb", "max_dbs_open"), - "100", - "{couchdb, max_dbs_open} is 100 by defualt." - ), - - etap:is( - couch_config:get("httpd","port"), - "5984", - "{httpd, port} is 5984 by default" - ), - - etap:is( - couch_config:get("fizbang", "unicode"), - undefined, - "{fizbang, unicode} is undefined by default" - ) - end, - - run_tests([default_config()], CheckDefaults), - - - % Check that subsequent files override values appropriately - - CheckOverride = fun() -> - etap:is( - couch_config:get("couchdb", "max_dbs_open"), - "10", - "{couchdb, max_dbs_open} was overriden with the value 10" - ), - - etap:is( - couch_config:get("httpd", "port"), - "4895", - "{httpd, port} was overriden with the value 4895" - ) - end, - - run_tests([default_config(), local_config_1()], CheckOverride), - - - % Check that overrides can create new sections - - CheckOverride2 = fun() -> - etap:is( - couch_config:get("httpd", "port"), - "80", - "{httpd, port} is overriden with the value 80" - ), - - etap:is( - couch_config:get("fizbang", "unicode"), - "normalized", - "{fizbang, unicode} was created by override INI file" - ) - end, - - run_tests([default_config(), local_config_2()], CheckOverride2), - - - % Check that values can be overriden multiple times - - CheckOverride3 = fun() -> - etap:is( - couch_config:get("httpd", "port"), - "80", - "{httpd, port} value was taken from the last specified INI file." - ) - end, - - run_tests( - [default_config(), local_config_1(), local_config_2()], - CheckOverride3 - ), - - % Check persistence to last file. - - % Empty the file in case it exists. - {ok, Fd} = file:open(local_config_write(), write), - ok = file:truncate(Fd), - ok = file:close(Fd), - - % Open and write a value - CheckCanWrite = fun() -> - etap:is( - couch_config:get("httpd", "port"), - "5984", - "{httpd, port} is still 5984 by default" - ), - - etap:is( - couch_config:set("httpd", "port", "8080"), - ok, - "Writing {httpd, port} is kosher." - ), - - etap:is( - couch_config:get("httpd", "port"), - "8080", - "{httpd, port} was updated to 8080 successfully." - ), - - etap:is( - couch_config:delete("httpd", "bind_address"), - ok, - "Deleting {httpd, bind_address} succeeds" - ), - - etap:is( - couch_config:get("httpd", "bind_address"), - undefined, - "{httpd, bind_address} was actually deleted." - ) - end, - - run_tests([default_config(), local_config_write()], CheckCanWrite), - - % Open and check where we don't expect persistence. - - CheckDidntWrite = fun() -> - etap:is( - couch_config:get("httpd", "port"), - "5984", - "{httpd, port} was not persisted to the primary INI file." - ), - - etap:is( - couch_config:get("httpd", "bind_address"), - "127.0.0.1", - "{httpd, bind_address} was not deleted form the primary INI file." - ) - end, - - run_tests([default_config()], CheckDidntWrite), - - % Open and check we have only the persistence we expect. - CheckDidWrite = fun() -> - etap:is( - couch_config:get("httpd", "port"), - "8080", - "{httpd, port} is still 8080 after reopening the config." - ), - - etap:is( - couch_config:get("httpd", "bind_address"), - undefined, - "{httpd, bind_address} is still \"\" after reopening." - ) - end, - - run_tests([local_config_write()], CheckDidWrite), - - ok. diff --git a/test/etap/082-config-register.t b/test/etap/082-config-register.t deleted file mode 100755 index 191ba8f8..00000000 --- a/test/etap/082-config-register.t +++ /dev/null @@ -1,94 +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"). - -main(_) -> - test_util:init_code_path(), - etap:plan(5), - 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_config:start_link([default_config()]), - - etap:is( - couch_config:get("httpd", "port"), - "5984", - "{httpd, port} is 5984 by default." - ), - - ok = couch_config:set("httpd", "port", "4895", false), - - etap:is( - couch_config:get("httpd", "port"), - "4895", - "{httpd, port} changed to 4895" - ), - - SentinelFunc = fun() -> - % Ping/Pong to make sure we wait for this - % process to die - receive {ping, From} -> From ! pong end - end, - SentinelPid = spawn(SentinelFunc), - - couch_config:register( - fun("httpd", "port", Value) -> - etap:is(Value, "8080", "Registered function got notification.") - end, - SentinelPid - ), - - ok = couch_config:set("httpd", "port", "8080", false), - - % Implicitly checking that we *don't* call the function - etap:is( - couch_config:get("httpd", "bind_address"), - "127.0.0.1", - "{httpd, bind_address} is not '0.0.0.0'" - ), - ok = couch_config:set("httpd", "bind_address", "0.0.0.0", false), - - % Ping-Pong kill process - SentinelPid ! {ping, self()}, - receive - _Any -> ok - after 1000 -> - throw({timeout_error, registered_pid}) - end, - - ok = couch_config:set("httpd", "port", "80", false), - etap:is( - couch_config:get("httpd", "port"), - "80", - "Implicitly test that the function got de-registered" - ), - - % test passing of Persist flag - couch_config:register( - fun("httpd", _, _, Persist) -> - etap:is(Persist, false) - end), - ok = couch_config:set("httpd", "port", "80", false), - - ok. diff --git a/test/etap/083-config-no-files.t b/test/etap/083-config-no-files.t deleted file mode 100755 index bc40ec9d..00000000 --- a/test/etap/083-config-no-files.t +++ /dev/null @@ -1,55 +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"). - -main(_) -> - test_util:init_code_path(), - etap:plan(3), - 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_config:start_link([]), - - etap:fun_is( - fun(KVPairs) -> length(KVPairs) == 0 end, - couch_config:all(), - "No INI files specified returns 0 key/value pairs." - ), - - ok = couch_config:set("httpd", "port", "80", false), - - etap:is( - couch_config:get("httpd", "port"), - "80", - "Created a new non-persisted k/v pair." - ), - - ok = couch_config:set("httpd", "bind_address", "127.0.0.1", false), - etap:is( - couch_config:get("httpd", "bind_address"), - "127.0.0.1", - "Asking for a persistent key/value pair doesn't choke." - ), - - ok. diff --git a/test/etap/090-task-status.t b/test/etap/090-task-status.t deleted file mode 100755 index b278de7f..00000000 --- a/test/etap/090-task-status.t +++ /dev/null @@ -1,209 +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(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. - -check_status(Pid,ListPropLists) -> - From = list_to_binary(pid_to_list(Pid)), - Element = lists:foldl( - fun(PropList,Acc) -> - case couch_util:get_value(pid,PropList) of - From -> - [PropList | Acc]; - _ -> - [] - end - end, - [], ListPropLists - ), - couch_util:get_value(status,hd(Element)). - -loop() -> - receive - {add, From} -> - Resp = couch_task_status:add_task("type", "task", "init"), - From ! {ok, self(), Resp}, - loop(); - {update, Status, From} -> - Resp = couch_task_status:update(Status), - From ! {ok, self(), Resp}, - loop(); - {update_frequency, Msecs, From} -> - Resp = couch_task_status:set_update_frequency(Msecs), - From ! {ok, self(), Resp}, - loop(); - {done, From} -> - From ! {ok, self(), ok} - end. - -call(Pid, Command) -> - Pid ! {Command, self()}, - wait(Pid). - -call(Pid, Command, Arg) -> - Pid ! {Command, Arg, self()}, - wait(Pid). - -wait(Pid) -> - receive - {ok, Pid, Msg} -> Msg - after 1000 -> - throw(timeout_error) - end. - -test() -> - {ok, TaskStatusPid} = couch_task_status:start_link(), - - TaskUpdater = fun() -> loop() end, - % create three updaters - Pid1 = spawn(TaskUpdater), - Pid2 = spawn(TaskUpdater), - Pid3 = spawn(TaskUpdater), - - ok = call(Pid1, add), - etap:is( - length(couch_task_status:all()), - 1, - "Started a task" - ), - - etap:is( - call(Pid1, add), - {add_task_error, already_registered}, - "Unable to register multiple tasks for a single Pid." - ), - - etap:is( - check_status(Pid1, couch_task_status:all()), - <<"init">>, - "Task status was set to 'init'." - ), - - call(Pid1,update,"running"), - etap:is( - check_status(Pid1,couch_task_status:all()), - <<"running">>, - "Status updated to 'running'." - ), - - - call(Pid2,add), - etap:is( - length(couch_task_status:all()), - 2, - "Started a second task." - ), - - etap:is( - check_status(Pid2, couch_task_status:all()), - <<"init">>, - "Second tasks's status was set to 'init'." - ), - - call(Pid2, update, "running"), - etap:is( - check_status(Pid2, couch_task_status:all()), - <<"running">>, - "Second task's status updated to 'running'." - ), - - - call(Pid3, add), - etap:is( - length(couch_task_status:all()), - 3, - "Registered a third task." - ), - - etap:is( - check_status(Pid3, couch_task_status:all()), - <<"init">>, - "Third tasks's status was set to 'init'." - ), - - call(Pid3, update, "running"), - etap:is( - check_status(Pid3, couch_task_status:all()), - <<"running">>, - "Third task's status updated to 'running'." - ), - - - call(Pid3, update_frequency, 500), - call(Pid3, update, "still running"), - etap:is( - check_status(Pid3, couch_task_status:all()), - <<"still running">>, - "Third task's status updated to 'still running'." - ), - - call(Pid3, update, "skip this update"), - etap:is( - check_status(Pid3, couch_task_status:all()), - <<"still running">>, - "Status update dropped because of frequency limit." - ), - - call(Pid3, update_frequency, 0), - call(Pid3, update, "don't skip"), - etap:is( - check_status(Pid3, couch_task_status:all()), - <<"don't skip">>, - "Status updated after reseting frequency limit." - ), - - - call(Pid1, done), - etap:is( - length(couch_task_status:all()), - 2, - "First task finished." - ), - - call(Pid2, done), - etap:is( - length(couch_task_status:all()), - 1, - "Second task finished." - ), - - call(Pid3, done), - etap:is( - length(couch_task_status:all()), - 0, - "Third task finished." - ), - - erlang:monitor(process, TaskStatusPid), - couch_task_status:stop(), - receive - {'DOWN', _, _, TaskStatusPid, _} -> - ok - after - 1000 -> - throw(timeout_error) - end, - - ok. diff --git a/test/etap/100-ref-counter.t b/test/etap/100-ref-counter.t deleted file mode 100755 index 8f996d04..00000000 --- a/test/etap/100-ref-counter.t +++ /dev/null @@ -1,114 +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(8), - case (catch test()) of - ok -> - etap:end_tests(); - Other -> - etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), - etap:bail(Other) - end, - ok. - -loop() -> - receive - close -> ok - end. - -wait() -> - receive - {'DOWN', _, _, _, _} -> ok - after 1000 -> - throw(timeout_error) - end. - -test() -> - {ok, RefCtr} = couch_ref_counter:start([]), - - etap:is( - couch_ref_counter:count(RefCtr), - 1, - "A ref_counter is initialized with the calling process as a referer." - ), - - ChildPid1 = spawn(fun() -> loop() end), - - % This is largely implicit in that nothing else breaks - % as ok is just returned from gen_server:cast() - etap:is( - couch_ref_counter:drop(RefCtr, ChildPid1), - ok, - "Dropping an unknown Pid is ignored." - ), - - couch_ref_counter:add(RefCtr, ChildPid1), - etap:is( - couch_ref_counter:count(RefCtr), - 2, - "Adding a Pid to the ref_counter increases it's count." - ), - - couch_ref_counter:add(RefCtr, ChildPid1), - etap:is( - couch_ref_counter:count(RefCtr), - 2, - "Readding the same Pid maintains the count but increments it's refs." - ), - - couch_ref_counter:drop(RefCtr, ChildPid1), - etap:is( - couch_ref_counter:count(RefCtr), - 2, - "Droping the doubly added Pid only removes a ref, not a referer." - ), - - couch_ref_counter:drop(RefCtr, ChildPid1), - etap:is( - couch_ref_counter:count(RefCtr), - 1, - "Dropping the second ref drops the referer." - ), - - couch_ref_counter:add(RefCtr, ChildPid1), - etap:is( - couch_ref_counter:count(RefCtr), - 2, - "Sanity checking that the Pid was re-added." - ), - - erlang:monitor(process, ChildPid1), - ChildPid1 ! close, - wait(), - - CheckFun = fun - (Iter, nil) -> - case couch_ref_counter:count(RefCtr) of - 1 -> Iter; - _ -> nil - end; - (_, Acc) -> - Acc - end, - Result = lists:foldl(CheckFun, nil, lists:seq(1, 10000)), - etap:isnt( - Result, - nil, - "The referer count was decremented automatically on process exit." - ), - - ok. diff --git a/test/etap/110-replication-httpc.t b/test/etap/110-replication-httpc.t deleted file mode 100755 index 39b0755e..00000000 --- a/test/etap/110-replication-httpc.t +++ /dev/null @@ -1,132 +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_server:get_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() -> - lists:concat([ - "http://127.0.0.1:", mochiweb_socket_server:get(couch_httpd, port), "/" - ]). - -dbname() -> "etap-test-db". - -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(test_util: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_server:get_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_server:get_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/test/etap/111-replication-changes-feed.t b/test/etap/111-replication-changes-feed.t deleted file mode 100755 index 358bf1e2..00000000 --- a/test/etap/111-replication-changes-feed.t +++ /dev/null @@ -1,253 +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_server:get_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 -}). - -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(test_util: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<A end, [Rev1,Rev2])], - {[ - {<<"seq">>, 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) -> - server() ++ "etap-test-db/". - -server() -> - lists:concat([ - "http://127.0.0.1:", mochiweb_socket_server:get(couch_httpd, port), "/" - ]). - -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/test/etap/112-replication-missing-revs.t b/test/etap/112-replication-missing-revs.t deleted file mode 100755 index 39280aee..00000000 --- a/test/etap/112-replication-missing-revs.t +++ /dev/null @@ -1,207 +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_server:get_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 -}). - -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(test_util: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 = server() ++ "etap-test-source/"}, - couch_rep_changes_feed:start_link(self(), Db, Since, Props). - -server() -> - lists:concat([ - "http://127.0.0.1:", mochiweb_socket_server:get(couch_httpd, port), "/" - ]). - -couch_rep_pid(Db) -> - spawn(fun() -> couch_rep_pid_loop(Db) end). - -couch_rep_pid_loop(Db) -> - receive - {'$gen_call', From, get_target_db} -> - gen_server:reply(From, {ok, Db}) - end, - couch_rep_pid_loop(Db). - -start_missing_revs(local, Changes) -> - TargetDb = get_db(target), - MainPid = couch_rep_pid(TargetDb), - couch_rep_missing_revs:start_link(MainPid, TargetDb, Changes, []); -start_missing_revs(remote, Changes) -> - TargetDb = #http_db{url = server() ++ "etap-test-target/"}, - MainPid = couch_rep_pid(TargetDb), - couch_rep_missing_revs:start_link(MainPid, TargetDb, Changes, []). diff --git a/test/etap/113-replication-attachment-comp.t b/test/etap/113-replication-attachment-comp.t deleted file mode 100755 index e30a96bc..00000000 --- a/test/etap/113-replication-attachment-comp.t +++ /dev/null @@ -1,314 +0,0 @@ -#!/usr/bin/env escript -%% -*- erlang -*- - -% Licensed under the Apache License, Version 2.0 (the "License"); you may not -% use this file except in compliance with the License. You may obtain a copy of -% the License at -% -% http://www.apache.org/licenses/LICENSE-2.0 -% -% Unless required by applicable law or agreed to in writing, software -% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -% License for the specific language governing permissions and limitations under -% the License. - --record(user_ctx, { - name = null, - roles = [], - handler -}). - -test_db_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(45), - case (catch test()) of - ok -> - etap:end_tests(); - Other -> - etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), - etap:bail(Other) - end, - ok. - -test() -> - couch_server_sup:start_link(test_util:config_files()), - put(addr, couch_config:get("httpd", "bind_address", "127.0.0.1")), - put(port, integer_to_list(mochiweb_socket_server:get(couch_httpd, port))), - 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", false), - couch_config:set("attachments", "compressible_types", "text/*", false), - - % 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", false), - - % 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", false), - couch_config:set("attachments", "compressible_types", "text/*", false), - - % 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", false), - - % 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()), - - % - % test local 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", false), - couch_config:set("attachments", "compressible_types", "text/*", false), - - % 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", false), - - % do local-local replication - do_local_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. - -do_local_replication(SourceDbName, TargetDbName) -> - RepObj = {[ - {<<"source">>, 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, "Local replication successfully triggered"), - Json = couch_util:json_decode(Body), - RepOk = couch_util:get_nested_json_value(Json, [<<"ok">>]), - etap:is(RepOk, true, "Local 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/test/etap/120-stats-collect.t b/test/etap/120-stats-collect.t deleted file mode 100755 index dee88765..00000000 --- a/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/test/etap/121-stats-aggregates.cfg b/test/etap/121-stats-aggregates.cfg deleted file mode 100644 index 30e475da..00000000 --- a/test/etap/121-stats-aggregates.cfg +++ /dev/null @@ -1,19 +0,0 @@ -% Licensed to the Apache Software Foundation (ASF) under one -% or more contributor license agreements. See the NOTICE file -% distributed with this work for additional information -% regarding copyright ownership. The ASF licenses this file -% to you 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. - -{testing, stuff, "yay description"}. -{number, '11', "randomosity"}. diff --git a/test/etap/121-stats-aggregates.ini b/test/etap/121-stats-aggregates.ini deleted file mode 100644 index cc5cd218..00000000 --- a/test/etap/121-stats-aggregates.ini +++ /dev/null @@ -1,20 +0,0 @@ -; Licensed to the Apache Software Foundation (ASF) under one -; or more contributor license agreements. See the NOTICE file -; distributed with this work for additional information -; regarding copyright ownership. The ASF licenses this file -; to you 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. - -[stats] -rate = 10000000 ; We call collect_sample in testing -samples = [0, 1] diff --git a/test/etap/121-stats-aggregates.t b/test/etap/121-stats-aggregates.t deleted file mode 100755 index d678aa9d..00000000 --- a/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/test/etap/130-attachments-md5.t b/test/etap/130-attachments-md5.t deleted file mode 100755 index 6296e08a..00000000 --- a/test/etap/130-attachments-md5.t +++ /dev/null @@ -1,248 +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. - -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(test_util:config_files()), - Addr = couch_config:get("httpd", "bind_address", any), - put(addr, Addr), - put(port, mochiweb_socket_server:get(couch_httpd, 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!">>, - <<Part1:21/binary, Part2:13/binary>> = 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!">>, - <<Part1:21/binary, Part2:13/binary>> = 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!">>, - <<Part1:21/binary, Part2:13/binary>> = 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!">>, - <<Part1:21/binary, Part2:13/binary>> = 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!">>, - <<Part1:21/binary, Part2:13/binary>> = 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/test/etap/140-attachment-comp.t b/test/etap/140-attachment-comp.t deleted file mode 100755 index 475f4fb0..00000000 --- a/test/etap/140-attachment-comp.t +++ /dev/null @@ -1,762 +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. - -test_db_name() -> - <<"couch_test_atts_compression">>. - -main(_) -> - test_util:init_code_path(), - - etap:plan(85), - case (catch test()) of - ok -> - etap:end_tests(); - Other -> - etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), - etap:bail(Other) - end, - ok. - -test() -> - couch_server_sup:start_link(test_util:config_files()), - put(addr, couch_config:get("httpd", "bind_address", "127.0.0.1")), - put(port, integer_to_list(mochiweb_socket_server:get(couch_httpd, port))), - 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", false), - couch_config:set("attachments", "compressible_types", "text/*", false), - - 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" - ), - - test_compressible_type_with_parameters(), - - 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"), - Encoding = couch_util:get_value("content-encoding", Headers), - etap:is(Encoding, undefined, "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"), - Encoding = couch_util:get_value("content-encoding", Headers), - etap:is(Encoding, undefined, "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"), - Encoding = couch_util:get_value("content-encoding", Headers), - etap:is(Encoding, undefined, "received body is in identity form"), - 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", - [{"Accept", "application/json"}]}, - [], - [{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", - [{"Accept", "application/json"}]}, - [], - [{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", - [{"Accept", "application/json"}]}, - [], - [{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", - [{"Accept", "application/json"}]}, - [], - [{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_compressible_type_with_parameters() -> - {ok, {{_, Code, _}, _Headers, _Body}} = http:request( - put, - {db_url() ++ "/testdoc5/readme.txt", [], - "text/plain; charset=UTF-8", test_text_data()}, - [], - [{sync, true}]), - etap:is(Code, 201, "Created text attachment with MIME type " - "'text/plain; charset=UTF-8' using the standalone api"), - {ok, {{_, Code2, _}, Headers2, Body}} = http:request( - get, - {db_url() ++ "/testdoc5/readme.txt", [{"Accept-Encoding", "gzip"}]}, - [], - [{sync, true}]), - etap:is(Code2, 200, "HTTP response code is 200"), - Gziped = lists:member({"content-encoding", "gzip"}, Headers2), - 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 is gzipped"), - {ok, {{_, Code3, _}, _Headers3, Body3}} = http:request( - get, - {db_url() ++ "/testdoc5?att_encoding_info=true", []}, - [], - [{sync, true}]), - etap:is(Code3, 200, "HTTP response code is 200"), - Json = couch_util:json_decode(Body3), - {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()), - "text attachment stub length matches the uncompressed length" - ), - TextAttEncoding = couch_util:get_value(<<"encoding">>, TextAttJson), - etap:is( - TextAttEncoding, - <<"gzip">>, - "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())), - "text attachment stub encoded_length matches the compressed length" - ), - 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/test/etap/150-invalid-view-seq.t b/test/etap/150-invalid-view-seq.t deleted file mode 100755 index 594d3416..00000000 --- a/test/etap/150-invalid-view-seq.t +++ /dev/null @@ -1,190 +0,0 @@ -#!/usr/bin/env escript -%% -*- erlang -*- - -% Licensed under the Apache License, Version 2.0 (the "License"); you may not -% use this file except in compliance with the License. You may obtain a copy of -% the License at -% -% http://www.apache.org/licenses/LICENSE-2.0 -% -% Unless required by applicable law or agreed to in writing, software -% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -% License for the specific language governing permissions and limitations under -% the License. - --record(user_ctx, { - name = null, - roles = [], - handler -}). - -test_db_name() -> - <<"couch_test_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(test_util:config_files()), - 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, integer_to_list(mochiweb_socket_server:get(couch_httpd, port))), - 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(test_util:config_files()), - timer:sleep(1000), - put(port, integer_to_list(mochiweb_socket_server:get(couch_httpd, port))), - 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/test/etap/160-vhosts.t b/test/etap/160-vhosts.t deleted file mode 100755 index 8dac53e5..00000000 --- a/test/etap/160-vhosts.t +++ /dev/null @@ -1,291 +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_server:get_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() -> - lists:concat([ - "http://127.0.0.1:", mochiweb_socket_server:get(couch_httpd, port), "/" - ]). - -dbname() -> "etap-test-db". -admin_user_ctx() -> {user_ctx, #user_ctx{roles=[<<"_admin">>]}}. - -main(_) -> - test_util:init_code_path(), - - etap:plan(14), - case (catch test()) of - ok -> - etap:end_tests(); - Other -> - etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), - etap:bail(Other) - end, - ok. - -test() -> - couch_server_sup:start_link(test_util:config_files()), - ibrowse:start(), - crypto:start(), - - timer:sleep(1000), - 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} - ]}), - - Doc1 = couch_doc:from_json_obj({[ - {<<"_id">>, <<"_design/doc1">>}, - {<<"shows">>, {[ - {<<"test">>, <<"function(doc, req) { - return { json: { - requested_path: '/' + req.requested_path.join('/'), - path: '/' + req.path.join('/') - }}; -}">>} - ]}}, - {<<"rewrites">>, [ - {[ - {<<"from">>, <<"/">>}, - {<<"to">>, <<"_show/test">>} - ]} - ]} - ]}), - - {ok, _} = couch_db:update_docs(Db, [Doc, Doc1]), - - couch_db:ensure_full_commit(Db), - - %% end boilerplate, start test - - ok = couch_config:set("vhosts", "example.com", "/etap-test-db", false), - ok = couch_config:set("vhosts", "*.example.com", - "/etap-test-db/_design/doc1/_rewrite", false), - ok = couch_config:set("vhosts", "example.com/test", "/etap-test-db", false), - ok = couch_config:set("vhosts", "example1.com", - "/etap-test-db/_design/doc1/_rewrite/", false), - ok = couch_config:set("vhosts",":appname.:dbname.example1.com", - "/:dbname/_design/:appname/_rewrite/", false), - ok = couch_config:set("vhosts", ":dbname.example1.com", "/:dbname", false), - - ok = couch_config:set("vhosts", "*.example2.com", "/*", false), - ok = couch_config:set("vhosts", "*/test", "/etap-test-db", false), - ok = couch_config:set("vhosts", "*.example2.com/test", "/*", false), - ok = couch_config:set("vhosts", "*/test1", - "/etap-test-db/_design/doc1/_show/test", false), - - % let couch_httpd restart - timer:sleep(100), - - test_regular_request(), - test_vhost_request(), - test_vhost_request_with_qs(), - test_vhost_request_with_global(), - test_vhost_requested_path(), - test_vhost_requested_path_path(), - test_vhost_request_wildcard(), - test_vhost_request_replace_var(), - test_vhost_request_replace_var1(), - test_vhost_request_replace_wildcard(), - test_vhost_request_path(), - test_vhost_request_path1(), - test_vhost_request_path2(), - test_vhost_request_path3(), - - %% restart boilerplate - couch_db:close(Db), - timer:sleep(3000), - couch_server_sup:stop(), - - ok. - -test_regular_request() -> - Result = 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 -> - etap:is(false, true, <<"ibrowse fail">>) - end. - -test_vhost_request() -> - case ibrowse:send_req(server(), [], get, [], [{host_header, "example.com"}]) of - {ok, _, _, Body} -> - {JsonBody} = couch_util:json_decode(Body), - HasDbNameInfo = proplists:is_defined(<<"db_name">>, JsonBody), - etap:is(HasDbNameInfo, true, "should return database info"); - _Else -> - etap:is(false, true, <<"ibrowse fail">>) - 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 -> - etap:is(false, true, <<"ibrowse fail">>) - end. - -test_vhost_request_with_global() -> - Url2 = server() ++ "_utils/index.html", - case ibrowse:send_req(Url2, [], get, [], [{host_header, "example.com"}]) of - {ok, _, _, Body2} -> - "<!DOCTYPE" ++ _Foo = Body2, - etap:is(true, true, "should serve /_utils even inside vhosts"); - _Else -> - etap:is(false, true, <<"ibrowse fail">>) - end. - -test_vhost_requested_path() -> - case ibrowse:send_req(server(), [], get, [], [{host_header, "example1.com"}]) of - {ok, _, _, Body} -> - {Json} = couch_util:json_decode(Body), - etap:is(case proplists:get_value(<<"requested_path">>, Json) of - <<"/">> -> true; - _ -> false - end, true, <<"requested path in req ok">>); - _Else -> - etap:is(false, true, <<"ibrowse fail">>) - end. - -test_vhost_requested_path_path() -> - case ibrowse:send_req(server(), [], get, [], [{host_header, "example1.com"}]) of - {ok, _, _, Body} -> - {Json} = couch_util:json_decode(Body), - etap:is(case proplists:get_value(<<"path">>, Json) of - <<"/etap-test-db/_design/doc1/_show/test">> -> true; - _ -> false - end, true, <<"path in req ok">>); - _Else -> - etap:is(false, true, <<"ibrowse fail">>) - end. - -test_vhost_request_wildcard()-> - case ibrowse:send_req(server(), [], get, [], [{host_header, "test.example.com"}]) of - {ok, _, _, Body} -> - {Json} = couch_util:json_decode(Body), - etap:is(case proplists:get_value(<<"path">>, Json) of - <<"/etap-test-db/_design/doc1/_show/test">> -> true; - _ -> false - end, true, <<"wildcard ok">>); - _Else -> etap:is(false, true, <<"ibrowse fail">>) - end. - - -test_vhost_request_replace_var() -> - case ibrowse:send_req(server(), [], get, [], [{host_header,"etap-test-db.example1.com"}]) of - {ok, _, _, Body} -> - {JsonBody} = couch_util:json_decode(Body), - HasDbNameInfo = proplists:is_defined(<<"db_name">>, JsonBody), - etap:is(HasDbNameInfo, true, "should return database info"); - _Else -> etap:is(false, true, <<"ibrowse fail">>) - end. - -test_vhost_request_replace_var1() -> - case ibrowse:send_req(server(), [], get, [], [{host_header, "doc1.etap-test-db.example1.com"}]) of - {ok, _, _, Body} -> - {Json} = couch_util:json_decode(Body), - etap:is(case proplists:get_value(<<"path">>, Json) of - <<"/etap-test-db/_design/doc1/_show/test">> -> true; - _ -> false - end, true, <<"wildcard ok">>); - _Else -> etap:is(false, true, <<"ibrowse fail">>) - end. - -test_vhost_request_replace_wildcard() -> - case ibrowse:send_req(server(), [], get, [], [{host_header,"etap-test-db.example2.com"}]) of - {ok, _, _, Body} -> - {JsonBody} = couch_util:json_decode(Body), - HasDbNameInfo = proplists:is_defined(<<"db_name">>, JsonBody), - etap:is(HasDbNameInfo, true, "should return database info"); - _Else -> etap:is(false, true, <<"ibrowse fail">>) - end. - -test_vhost_request_path() -> - Uri = server() ++ "test", - case ibrowse:send_req(Uri, [], get, [], [{host_header, "example.com"}]) of - {ok, _, _, Body} -> - {JsonBody} = couch_util:json_decode(Body), - HasDbNameInfo = proplists:is_defined(<<"db_name">>, JsonBody), - etap:is(HasDbNameInfo, true, "should return database info"); - _Else -> etap:is(false, true, <<"ibrowse fail">>) - end. - -test_vhost_request_path1() -> - Url = server() ++ "test/doc1?revs_info=true", - case ibrowse:send_req(Url, [], get, [], []) 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 -> etap:is(false, true, <<"ibrowse fail">>) - end. - -test_vhost_request_path2() -> - Uri = server() ++ "test", - case ibrowse:send_req(Uri, [], get, [], [{host_header,"etap-test-db.example2.com"}]) of - {ok, _, _, Body} -> - {JsonBody} = couch_util:json_decode(Body), - HasDbNameInfo = proplists:is_defined(<<"db_name">>, JsonBody), - etap:is(HasDbNameInfo, true, "should return database info"); - _Else -> etap:is(false, true, <<"ibrowse fail">>) - end. - -test_vhost_request_path3() -> - Uri = server() ++ "test1", - case ibrowse:send_req(Uri, [], get, [], []) of - {ok, _, _, Body} -> - {Json} = couch_util:json_decode(Body), - etap:is(case proplists:get_value(<<"path">>, Json) of - <<"/etap-test-db/_design/doc1/_show/test">> -> true; - _ -> false - end, true, <<"path in req ok">>); - _Else -> etap:is(false, true, <<"ibrowse fail">>) - end. diff --git a/test/etap/170-os-daemons.es b/test/etap/170-os-daemons.es deleted file mode 100755 index 73974e90..00000000 --- a/test/etap/170-os-daemons.es +++ /dev/null @@ -1,26 +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. - -loop() -> - loop(io:read("")). - -loop({ok, _}) -> - loop(io:read("")); -loop(eof) -> - stop; -loop({error, Reason}) -> - throw({error, Reason}). - -main([]) -> - loop(). diff --git a/test/etap/170-os-daemons.t b/test/etap/170-os-daemons.t deleted file mode 100755 index 6feaa1bf..00000000 --- a/test/etap/170-os-daemons.t +++ /dev/null @@ -1,114 +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(daemon, { - port, - name, - cmd, - kill, - status=running, - cfg_patterns=[], - errors=[], - buf=[] -}). - -config_files() -> - lists:map(fun test_util:build_file/1, [ - "etc/couchdb/default_dev.ini" - ]). - -daemon_cmd() -> - test_util:source_file("test/etap/170-os-daemons.es"). - -main(_) -> - test_util:init_code_path(), - - etap:plan(49), - 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_config:start_link(config_files()), - couch_os_daemons:start_link(), - - etap:diag("Daemons boot after configuration added."), - couch_config:set("os_daemons", "foo", daemon_cmd(), false), - timer:sleep(1000), - - {ok, [D1]} = couch_os_daemons:info([table]), - check_daemon(D1, "foo"), - - % Check table form - {ok, Tab1} = couch_os_daemons:info(), - [T1] = ets:tab2list(Tab1), - check_daemon(T1, "foo"), - - etap:diag("Daemons stop after configuration removed."), - couch_config:delete("os_daemons", "foo", false), - timer:sleep(500), - - {ok, []} = couch_os_daemons:info([table]), - {ok, Tab2} = couch_os_daemons:info(), - etap:is(ets:tab2list(Tab2), [], "As table returns empty table."), - - etap:diag("Adding multiple daemons causes both to boot."), - couch_config:set("os_daemons", "bar", daemon_cmd(), false), - couch_config:set("os_daemons", "baz", daemon_cmd(), false), - timer:sleep(500), - {ok, Daemons} = couch_os_daemons:info([table]), - lists:foreach(fun(D) -> - check_daemon(D) - end, Daemons), - - {ok, Tab3} = couch_os_daemons:info(), - lists:foreach(fun(D) -> - check_daemon(D) - end, ets:tab2list(Tab3)), - - etap:diag("Removing one daemon leaves the other alive."), - couch_config:delete("os_daemons", "bar", false), - timer:sleep(500), - - {ok, [D2]} = couch_os_daemons:info([table]), - check_daemon(D2, "baz"), - - % Check table version - {ok, Tab4} = couch_os_daemons:info(), - [T4] = ets:tab2list(Tab4), - check_daemon(T4, "baz"), - - ok. - -check_daemon(D) -> - check_daemon(D, D#daemon.name). - -check_daemon(D, Name) -> - BaseName = "170-os-daemons.es", - BaseLen = length(BaseName), - CmdLen = length(D#daemon.cmd), - CmdName = lists:sublist(D#daemon.cmd, CmdLen-BaseLen+1, BaseLen), - - etap:is(is_port(D#daemon.port), true, "Daemon port is a port."), - etap:is(D#daemon.name, Name, "Daemon name was set correctly."), - etap:is(CmdName, BaseName, "Command name was set correctly."), - etap:isnt(D#daemon.kill, undefined, "Kill command was set."), - etap:is(D#daemon.errors, [], "No errors occurred while booting."), - etap:is(D#daemon.buf, [], "No extra data left in the buffer."). diff --git a/test/etap/171-os-daemons-config.es b/test/etap/171-os-daemons-config.es deleted file mode 100755 index 1f68ddc6..00000000 --- a/test/etap/171-os-daemons-config.es +++ /dev/null @@ -1,83 +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. - -filename() -> - list_to_binary(test_util:source_file("test/etap/171-os-daemons-config.es")). - -read() -> - case io:get_line('') of - eof -> - stop; - Data -> - couch_util:json_decode(Data) - end. - -write(Mesg) -> - Data = iolist_to_binary(couch_util:json_encode(Mesg)), - io:format(binary_to_list(Data) ++ "\n", []). - -get_cfg(Section) -> - write([<<"get">>, Section]), - read(). - -get_cfg(Section, Name) -> - write([<<"get">>, Section, Name]), - read(). - -log(Mesg) -> - write([<<"log">>, Mesg]). - -log(Mesg, Level) -> - write([<<"log">>, Mesg, {[{<<"level">>, Level}]}]). - -test_get_cfg1() -> - FileName = filename(), - {[{<<"foo">>, FileName}]} = get_cfg(<<"os_daemons">>). - -test_get_cfg2() -> - FileName = filename(), - FileName = get_cfg(<<"os_daemons">>, <<"foo">>), - <<"sequential">> = get_cfg(<<"uuids">>, <<"algorithm">>). - -test_get_unknown_cfg() -> - {[]} = get_cfg(<<"aal;3p4">>), - null = get_cfg(<<"aal;3p4">>, <<"313234kjhsdfl">>). - -test_log() -> - log(<<"foobar!">>), - log(<<"some stuff!">>, <<"debug">>), - log(2), - log(true), - write([<<"log">>, <<"stuff">>, 2]), - write([<<"log">>, 3, null]), - write([<<"log">>, [1, 2], {[{<<"level">>, <<"debug">>}]}]), - write([<<"log">>, <<"true">>, {[]}]). - -do_tests() -> - test_get_cfg1(), - test_get_cfg2(), - test_get_unknown_cfg(), - test_log(), - loop(io:read("")). - -loop({ok, _}) -> - loop(io:read("")); -loop(eof) -> - init:stop(); -loop({error, _Reason}) -> - init:stop(). - -main([]) -> - test_util:init_code_path(), - do_tests(). diff --git a/test/etap/171-os-daemons-config.t b/test/etap/171-os-daemons-config.t deleted file mode 100755 index e9dc3f32..00000000 --- a/test/etap/171-os-daemons-config.t +++ /dev/null @@ -1,74 +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(daemon, { - port, - name, - cmd, - kill, - status=running, - cfg_patterns=[], - errors=[], - buf=[] -}). - -config_files() -> - lists:map(fun test_util:build_file/1, [ - "etc/couchdb/default_dev.ini" - ]). - -daemon_cmd() -> - test_util:source_file("test/etap/171-os-daemons-config.es"). - -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_config:start_link(config_files()), - couch_config:set("log", "level", "debug", false), - couch_log:start_link(), - couch_os_daemons:start_link(), - - % "foo" is a required name by this test. - couch_config:set("os_daemons", "foo", daemon_cmd(), false), - timer:sleep(1000), - - {ok, [D1]} = couch_os_daemons:info([table]), - check_daemon(D1, "foo"), - - ok. - -check_daemon(D, Name) -> - BaseName = "171-os-daemons-config.es", - BaseLen = length(BaseName), - CmdLen = length(D#daemon.cmd), - CmdName = lists:sublist(D#daemon.cmd, CmdLen-BaseLen+1, BaseLen), - - etap:is(is_port(D#daemon.port), true, "Daemon port is a port."), - etap:is(D#daemon.name, Name, "Daemon name was set correctly."), - etap:is(CmdName, BaseName, "Command name was set correctly."), - etap:isnt(D#daemon.kill, undefined, "Kill command was set."), - etap:is(D#daemon.errors, [], "No errors occurred while booting."), - etap:is(D#daemon.buf, [], "No extra data left in the buffer."). diff --git a/test/etap/172-os-daemon-errors.1.sh b/test/etap/172-os-daemon-errors.1.sh deleted file mode 100644 index 345c8b40..00000000 --- a/test/etap/172-os-daemon-errors.1.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -e -# -# 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. -# -# Please do not make this file executable as that's the error being tested. - -sleep 5 diff --git a/test/etap/172-os-daemon-errors.2.sh b/test/etap/172-os-daemon-errors.2.sh deleted file mode 100755 index 256ee793..00000000 --- a/test/etap/172-os-daemon-errors.2.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -e -# -# 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. - -exit 1 diff --git a/test/etap/172-os-daemon-errors.3.sh b/test/etap/172-os-daemon-errors.3.sh deleted file mode 100755 index f5a13684..00000000 --- a/test/etap/172-os-daemon-errors.3.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -e -# -# 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. - -sleep 1 diff --git a/test/etap/172-os-daemon-errors.4.sh b/test/etap/172-os-daemon-errors.4.sh deleted file mode 100755 index 5bc10e83..00000000 --- a/test/etap/172-os-daemon-errors.4.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -e -# -# 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. - -sleep 2 diff --git a/test/etap/172-os-daemon-errors.t b/test/etap/172-os-daemon-errors.t deleted file mode 100755 index bde5c6ff..00000000 --- a/test/etap/172-os-daemon-errors.t +++ /dev/null @@ -1,126 +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(daemon, { - port, - name, - cmd, - kill, - status=running, - cfg_patterns=[], - errors=[], - buf=[] -}). - -config_files() -> - lists:map(fun test_util:build_file/1, [ - "etc/couchdb/default_dev.ini" - ]). - -bad_perms() -> - test_util:source_file("test/etap/172-os-daemon-errors.1.sh"). - -die_on_boot() -> - test_util:source_file("test/etap/172-os-daemon-errors.2.sh"). - -die_quickly() -> - test_util:source_file("test/etap/172-os-daemon-errors.3.sh"). - -can_reboot() -> - test_util:source_file("test/etap/172-os-daemon-errors.4.sh"). - -main(_) -> - test_util:init_code_path(), - - etap:plan(36), - 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_config:start_link(config_files()), - couch_os_daemons:start_link(), - - etap:diag("Daemon not executable."), - test_halts("foo", bad_perms(), 1000), - - etap:diag("Daemon dies on boot."), - test_halts("bar", die_on_boot(), 1000), - - etap:diag("Daemon dies quickly after boot."), - test_halts("baz", die_quickly(), 4000), - - etap:diag("Daemon dies, but not quickly enough to be halted."), - test_runs("bam", can_reboot()), - - ok. - -test_halts(Name, Cmd, Time) -> - couch_config:set("os_daemons", Name, Cmd ++ " 2> /dev/null", false), - timer:sleep(Time), - {ok, [D]} = couch_os_daemons:info([table]), - check_dead(D, Name, Cmd), - couch_config:delete("os_daemons", Name, false). - -test_runs(Name, Cmd) -> - couch_config:set("os_daemons", Name, Cmd, false), - - timer:sleep(1000), - {ok, [D1]} = couch_os_daemons:info([table]), - check_daemon(D1, Name, Cmd, 0), - - % Should reboot every two seconds. We're at 1s, so wait - % utnil 3s to be in the middle of the next invocation's - % life span. - timer:sleep(2000), - {ok, [D2]} = couch_os_daemons:info([table]), - check_daemon(D2, Name, Cmd, 1), - - % If the kill command changed, that means we rebooted the process. - etap:isnt(D1#daemon.kill, D2#daemon.kill, "Kill command changed."). - -check_dead(D, Name, Cmd) -> - BaseName = filename:basename(Cmd) ++ " 2> /dev/null", - BaseLen = length(BaseName), - CmdLen = length(D#daemon.cmd), - CmdName = lists:sublist(D#daemon.cmd, CmdLen-BaseLen+1, BaseLen), - - etap:is(is_port(D#daemon.port), true, "Daemon port is a port."), - etap:is(D#daemon.name, Name, "Daemon name was set correctly."), - etap:is(CmdName, BaseName, "Command name was set correctly."), - etap:isnt(D#daemon.kill, undefined, "Kill command was set."), - etap:is(D#daemon.status, halted, "Daemon has been halted."), - etap:is(D#daemon.errors, nil, "Errors have been disabled."), - etap:is(D#daemon.buf, nil, "Buffer has been switched off."). - -check_daemon(D, Name, Cmd, Errs) -> - BaseName = filename:basename(Cmd), - BaseLen = length(BaseName), - CmdLen = length(D#daemon.cmd), - CmdName = lists:sublist(D#daemon.cmd, CmdLen-BaseLen+1, BaseLen), - - etap:is(is_port(D#daemon.port), true, "Daemon port is a port."), - etap:is(D#daemon.name, Name, "Daemon name was set correctly."), - etap:is(CmdName, BaseName, "Command name was set correctly."), - etap:isnt(D#daemon.kill, undefined, "Kill command was set."), - etap:is(D#daemon.status, running, "Daemon still running."), - etap:is(length(D#daemon.errors), Errs, "Found expected number of errors."), - etap:is(D#daemon.buf, [], "No extra data left in the buffer."). - diff --git a/test/etap/173-os-daemon-cfg-register.t b/test/etap/173-os-daemon-cfg-register.t deleted file mode 100755 index 71181aa2..00000000 --- a/test/etap/173-os-daemon-cfg-register.t +++ /dev/null @@ -1,93 +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(daemon, { - port, - name, - cmd, - kill, - status=running, - cfg_patterns=[], - errors=[], - buf=[] -}). - -daemon_name() -> - "wheee". - -daemon_cmd() -> - test_util:build_file("test/etap/test_cfg_register"). - -main(_) -> - test_util:init_code_path(), - - etap:plan(27), - 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_config:start_link(test_util:config_files()), - couch_os_daemons:start_link(), - - DaemonCmd = daemon_cmd() ++ " 2> /dev/null", - - etap:diag("Booting the daemon"), - couch_config:set("os_daemons", daemon_name(), DaemonCmd, false), - timer:sleep(1000), - {ok, [D1]} = couch_os_daemons:info([table]), - check_daemon(D1, running), - - etap:diag("Daemon restarts when section changes."), - couch_config:set("s1", "k", "foo", false), - timer:sleep(1000), - {ok, [D2]} = couch_os_daemons:info([table]), - check_daemon(D2, running), - etap:isnt(D2#daemon.kill, D1#daemon.kill, "Kill command shows restart."), - - etap:diag("Daemon doesn't restart for ignored section key."), - couch_config:set("s2", "k2", "baz", false), - timer:sleep(1000), - {ok, [D3]} = couch_os_daemons:info([table]), - etap:is(D3, D2, "Same daemon info after ignored config change."), - - etap:diag("Daemon restarts for specific section/key pairs."), - couch_config:set("s2", "k", "bingo", false), - timer:sleep(1000), - {ok, [D4]} = couch_os_daemons:info([table]), - check_daemon(D4, running), - etap:isnt(D4#daemon.kill, D3#daemon.kill, "Kill command changed again."), - - ok. - -check_daemon(D, Status) -> - BaseName = filename:basename(daemon_cmd()) ++ " 2> /dev/null", - BaseLen = length(BaseName), - CmdLen = length(D#daemon.cmd), - CmdName = lists:sublist(D#daemon.cmd, CmdLen-BaseLen+1, BaseLen), - - etap:is(is_port(D#daemon.port), true, "Daemon port is a port."), - etap:is(D#daemon.name, daemon_name(), "Daemon name was set correctly."), - etap:is(CmdName, BaseName, "Command name was set correctly."), - etap:isnt(D#daemon.kill, undefined, "Kill command was set."), - etap:is(D#daemon.status, Status, "Daemon status is correct."), - etap:is(D#daemon.cfg_patterns, [{"s1"}, {"s2", "k"}], "Cfg patterns set"), - etap:is(D#daemon.errors, [], "No errors have occurred."), - etap:isnt(D#daemon.buf, nil, "Buffer is active."). diff --git a/test/etap/180-http-proxy.ini b/test/etap/180-http-proxy.ini deleted file mode 100644 index 3e2ba137..00000000 --- a/test/etap/180-http-proxy.ini +++ /dev/null @@ -1,20 +0,0 @@ -; Licensed to the Apache Software Foundation (ASF) under one -; or more contributor license agreements. See the NOTICE file -; distributed with this work for additional information -; regarding copyright ownership. The ASF licenses this file -; to you 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. - -; 49151 is IANA Reserved, let's assume no one is listening there -[httpd_global_handlers] -_error = {couch_httpd_proxy, handle_proxy_req, <<"http://127.0.0.1:49151/">>} diff --git a/test/etap/180-http-proxy.t b/test/etap/180-http-proxy.t deleted file mode 100755 index 41c77631..00000000 --- a/test/etap/180-http-proxy.t +++ /dev/null @@ -1,378 +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. - --record(req, {method=get, path="", headers=[], body="", opts=[]}). - -server() -> - lists:concat([ - "http://127.0.0.1:", - mochiweb_socket_server:get(couch_httpd, port), - "/_test/" - ]). - -proxy() -> - "http://127.0.0.1:" ++ integer_to_list(test_web:get_port()) ++ "/". - -external() -> "https://www.google.com/". - -main(_) -> - test_util:init_code_path(), - - etap:plan(61), - case (catch test()) of - ok -> - etap:end_tests(); - Other -> - etap:diag("Test died abnormally: ~p", [Other]), - etap:bail("Bad return value.") - end, - ok. - -check_request(Name, Req, Remote, Local) -> - case Remote of - no_remote -> ok; - _ -> test_web:set_assert(Remote) - end, - Url = case proplists:lookup(url, Req#req.opts) of - none -> server() ++ Req#req.path; - {url, DestUrl} -> DestUrl - end, - Opts = [{headers_as_is, true} | Req#req.opts], - Resp =ibrowse:send_req( - Url, Req#req.headers, Req#req.method, Req#req.body, Opts - ), - %etap:diag("ibrowse response: ~p", [Resp]), - case Local of - no_local -> ok; - _ -> etap:fun_is(Local, Resp, Name) - end, - case {Remote, Local} of - {no_remote, _} -> - ok; - {_, no_local} -> - ok; - _ -> - etap:is(test_web:check_last(), was_ok, Name ++ " - request handled") - end, - Resp. - -test() -> - couch_server_sup:start_link([ - test_util:source_file("test/etap/180-http-proxy.ini") | - test_util:config_files() - ]), - ibrowse:start(), - crypto:start(), - - % start the test_web server on a random port - test_web:start_link(), - Url = lists:concat([ - "{couch_httpd_proxy, handle_proxy_req, <<\"http://127.0.0.1:", - test_web:get_port(), - "/\">>}" - ]), - couch_config:set("httpd_global_handlers", "_test", Url, false), - - % let couch_httpd restart - timer:sleep(100), - - test_basic(), - test_alternate_status(), - test_trailing_slash(), - test_passes_header(), - test_passes_host_header(), - test_passes_header_back(), - test_rewrites_location_headers(), - test_doesnt_rewrite_external_locations(), - test_rewrites_relative_location(), - test_uses_same_version(), - test_passes_body(), - test_passes_eof_body_back(), - test_passes_chunked_body(), - test_passes_chunked_body_back(), - - test_connect_error(), - - ok. - -test_basic() -> - Remote = fun(Req) -> - 'GET' = Req:get(method), - "/" = Req:get(path), - 0 = Req:get(body_length), - <<>> = Req:recv_body(), - {ok, {200, [{"Content-Type", "text/plain"}], "ok"}} - end, - Local = fun({ok, "200", _, "ok"}) -> true; (_) -> false end, - check_request("Basic proxy test", #req{}, Remote, Local). - -test_alternate_status() -> - Remote = fun(Req) -> - "/alternate_status" = Req:get(path), - {ok, {201, [], "ok"}} - end, - Local = fun({ok, "201", _, "ok"}) -> true; (_) -> false end, - Req = #req{path="alternate_status"}, - check_request("Alternate status", Req, Remote, Local). - -test_trailing_slash() -> - Remote = fun(Req) -> - "/trailing_slash/" = Req:get(path), - {ok, {200, [], "ok"}} - end, - Local = fun({ok, "200", _, "ok"}) -> true; (_) -> false end, - Req = #req{path="trailing_slash/"}, - check_request("Trailing slash", Req, Remote, Local). - -test_passes_header() -> - Remote = fun(Req) -> - "/passes_header" = Req:get(path), - "plankton" = Req:get_header_value("X-CouchDB-Ralph"), - {ok, {200, [], "ok"}} - end, - Local = fun({ok, "200", _, "ok"}) -> true; (_) -> false end, - Req = #req{ - path="passes_header", - headers=[{"X-CouchDB-Ralph", "plankton"}] - }, - check_request("Passes header", Req, Remote, Local). - -test_passes_host_header() -> - Remote = fun(Req) -> - "/passes_host_header" = Req:get(path), - "www.google.com" = Req:get_header_value("Host"), - {ok, {200, [], "ok"}} - end, - Local = fun({ok, "200", _, "ok"}) -> true; (_) -> false end, - Req = #req{ - path="passes_host_header", - headers=[{"Host", "www.google.com"}] - }, - check_request("Passes host header", Req, Remote, Local). - -test_passes_header_back() -> - Remote = fun(Req) -> - "/passes_header_back" = Req:get(path), - {ok, {200, [{"X-CouchDB-Plankton", "ralph"}], "ok"}} - end, - Local = fun - ({ok, "200", Headers, "ok"}) -> - lists:member({"X-CouchDB-Plankton", "ralph"}, Headers); - (_) -> - false - end, - Req = #req{path="passes_header_back"}, - check_request("Passes header back", Req, Remote, Local). - -test_rewrites_location_headers() -> - etap:diag("Testing location header rewrites."), - do_rewrite_tests([ - {"Location", proxy() ++ "foo/bar", server() ++ "foo/bar"}, - {"Content-Location", proxy() ++ "bing?q=2", server() ++ "bing?q=2"}, - {"Uri", proxy() ++ "zip#frag", server() ++ "zip#frag"}, - {"Destination", proxy(), server()} - ]). - -test_doesnt_rewrite_external_locations() -> - etap:diag("Testing no rewrite of external locations."), - do_rewrite_tests([ - {"Location", external() ++ "search", external() ++ "search"}, - {"Content-Location", external() ++ "s?q=2", external() ++ "s?q=2"}, - {"Uri", external() ++ "f#f", external() ++ "f#f"}, - {"Destination", external() ++ "f?q=2#f", external() ++ "f?q=2#f"} - ]). - -test_rewrites_relative_location() -> - etap:diag("Testing relative rewrites."), - do_rewrite_tests([ - {"Location", "/foo", server() ++ "foo"}, - {"Content-Location", "bar", server() ++ "bar"}, - {"Uri", "/zing?q=3", server() ++ "zing?q=3"}, - {"Destination", "bing?q=stuff#yay", server() ++ "bing?q=stuff#yay"} - ]). - -do_rewrite_tests(Tests) -> - lists:foreach(fun({Header, Location, Url}) -> - do_rewrite_test(Header, Location, Url) - end, Tests). - -do_rewrite_test(Header, Location, Url) -> - Remote = fun(Req) -> - "/rewrite_test" = Req:get(path), - {ok, {302, [{Header, Location}], "ok"}} - end, - Local = fun - ({ok, "302", Headers, "ok"}) -> - etap:is( - couch_util:get_value(Header, Headers), - Url, - "Header rewritten correctly." - ), - true; - (_) -> - false - end, - Req = #req{path="rewrite_test"}, - Label = "Rewrite test for ", - check_request(Label ++ Header, Req, Remote, Local). - -test_uses_same_version() -> - Remote = fun(Req) -> - "/uses_same_version" = Req:get(path), - {1, 0} = Req:get(version), - {ok, {200, [], "ok"}} - end, - Local = fun({ok, "200", _, "ok"}) -> true; (_) -> false end, - Req = #req{ - path="uses_same_version", - opts=[{http_vsn, {1, 0}}] - }, - check_request("Uses same version", Req, Remote, Local). - -test_passes_body() -> - Remote = fun(Req) -> - 'PUT' = Req:get(method), - "/passes_body" = Req:get(path), - <<"Hooray!">> = Req:recv_body(), - {ok, {201, [], "ok"}} - end, - Local = fun({ok, "201", _, "ok"}) -> true; (_) -> false end, - Req = #req{ - method=put, - path="passes_body", - body="Hooray!" - }, - check_request("Passes body", Req, Remote, Local). - -test_passes_eof_body_back() -> - BodyChunks = [<<"foo">>, <<"bar">>, <<"bazinga">>], - Remote = fun(Req) -> - 'GET' = Req:get(method), - "/passes_eof_body" = Req:get(path), - {raw, {200, [{"Connection", "close"}], BodyChunks}} - end, - Local = fun({ok, "200", _, "foobarbazinga"}) -> true; (_) -> false end, - Req = #req{path="passes_eof_body"}, - check_request("Passes eof body", Req, Remote, Local). - -test_passes_chunked_body() -> - BodyChunks = [<<"foo">>, <<"bar">>, <<"bazinga">>], - Remote = fun(Req) -> - 'POST' = Req:get(method), - "/passes_chunked_body" = Req:get(path), - RecvBody = fun - ({Length, Chunk}, [Chunk | Rest]) -> - Length = size(Chunk), - Rest; - ({0, []}, []) -> - ok - end, - ok = Req:stream_body(1024*1024, RecvBody, BodyChunks), - {ok, {201, [], "ok"}} - end, - Local = fun({ok, "201", _, "ok"}) -> true; (_) -> false end, - Req = #req{ - method=post, - path="passes_chunked_body", - headers=[{"Transfer-Encoding", "chunked"}], - body=mk_chunked_body(BodyChunks) - }, - check_request("Passes chunked body", Req, Remote, Local). - -test_passes_chunked_body_back() -> - Name = "Passes chunked body back", - Remote = fun(Req) -> - 'GET' = Req:get(method), - "/passes_chunked_body_back" = Req:get(path), - BodyChunks = [<<"foo">>, <<"bar">>, <<"bazinga">>], - {chunked, {200, [{"Transfer-Encoding", "chunked"}], BodyChunks}} - end, - Req = #req{ - path="passes_chunked_body_back", - opts=[{stream_to, self()}] - }, - - Resp = check_request(Name, Req, Remote, no_local), - - etap:fun_is( - fun({ibrowse_req_id, _}) -> true; (_) -> false end, - Resp, - "Received an ibrowse request id." - ), - {_, ReqId} = Resp, - - % Grab headers from response - receive - {ibrowse_async_headers, ReqId, "200", Headers} -> - etap:is( - proplists:get_value("Transfer-Encoding", Headers), - "chunked", - "Response included the Transfer-Encoding: chunked header" - ), - ibrowse:stream_next(ReqId) - after 1000 -> - throw({error, timeout}) - end, - - % Check body received - % TODO: When we upgrade to ibrowse >= 2.0.0 this check needs to - % check that the chunks returned are what we sent from the - % Remote test. - etap:diag("TODO: UPGRADE IBROWSE"), - etap:is(recv_body(ReqId, []), <<"foobarbazinga">>, "Decoded chunked body."), - - % Check test_web server. - etap:is(test_web:check_last(), was_ok, Name ++ " - request handled"). - -test_connect_error() -> - Local = fun({ok, "500", _Headers, _Body}) -> true; (_) -> false end, - Url = lists:concat([ - "http://127.0.0.1:", - mochiweb_socket_server:get(couch_httpd, port), - "/_error" - ]), - Req = #req{opts=[{url, Url}]}, - check_request("Connect error", Req, no_remote, Local). - - -mk_chunked_body(Chunks) -> - mk_chunked_body(Chunks, []). - -mk_chunked_body([], Acc) -> - iolist_to_binary(lists:reverse(Acc, "0\r\n\r\n")); -mk_chunked_body([Chunk | Rest], Acc) -> - Size = to_hex(size(Chunk)), - mk_chunked_body(Rest, ["\r\n", Chunk, "\r\n", Size | Acc]). - -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. - -recv_body(ReqId, Acc) -> - receive - {ibrowse_async_response, ReqId, Data} -> - recv_body(ReqId, [Data | Acc]); - {ibrowse_async_response_end, ReqId} -> - iolist_to_binary(lists:reverse(Acc)); - Else -> - throw({error, unexpected_mesg, Else}) - after 5000 -> - throw({error, timeout}) - end. diff --git a/test/etap/190-oauth.t b/test/etap/190-oauth.t deleted file mode 100755 index 09922049..00000000 --- a/test/etap/190-oauth.t +++ /dev/null @@ -1,31 +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. - -main(_) -> - test_util:init_code_path(), - etap:plan(1), - 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() -> - etap:is( - oauth_uri:params_from_string("realm=http://localhost:5984"), - [{"realm","http://localhost:5984"}], - "decode should handle non-percent encoded input."), - ok. diff --git a/test/etap/200-view-group-no-db-leaks.t b/test/etap/200-view-group-no-db-leaks.t deleted file mode 100755 index 9c77f1a8..00000000 --- a/test/etap/200-view-group-no-db-leaks.t +++ /dev/null @@ -1,262 +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 -}). - --define(LATEST_DISK_VERSION, 5). - --record(db_header, - {disk_version = ?LATEST_DISK_VERSION, - update_seq = 0, - unused = 0, - fulldocinfo_by_id_btree_state = nil, - docinfo_by_seq_btree_state = nil, - local_docs_btree_state = nil, - purge_seq = 0, - purged_docs = nil, - security_ptr = nil, - revs_limit = 1000 -}). - --record(db, { - main_pid = nil, - update_pid = nil, - compactor_pid = nil, - instance_start_time, % number of microsecs since jan 1 1970 as a binary string - fd, - fd_ref_counter, - header = #db_header{}, - committed_update_seq, - fulldocinfo_by_id_btree, - docinfo_by_seq_btree, - local_docs_btree, - update_seq, - name, - filepath, - validate_doc_funs = [], - security = [], - security_ptr = nil, - user_ctx = #user_ctx{}, - waiting_delayed_commit = nil, - revs_limit = 1000, - fsync_options = [], - is_sys_db = false -}). - -test_db_name() -> <<"couch_test_view_group_db_leaks">>. -ddoc_name() -> <<"foo">>. - -main(_) -> - test_util:init_code_path(), - - etap:plan(18), - case (catch test()) of - ok -> - etap:end_tests(); - Other -> - etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), - etap:bail(Other) - end, - ok. - -test() -> - couch_server_sup:start_link(test_util:config_files()), - timer:sleep(1000), - put(addr, couch_config:get("httpd", "bind_address", "127.0.0.1")), - put(port, integer_to_list(mochiweb_socket_server:get(couch_httpd, port))), - application:start(inets), - - delete_db(), - create_db(), - - create_docs(), - create_design_doc(), - - ViewGroup = couch_view:get_group_server( - test_db_name(), <<"_design/", (ddoc_name())/binary>>), - etap:is(is_pid(ViewGroup), true, "got view group pid"), - etap:is(is_process_alive(ViewGroup), true, "view group pid is alive"), - - query_view(), - check_db_ref_count(), - etap:is(is_process_alive(ViewGroup), true, "view group pid is alive"), - - create_new_doc(<<"doc1000">>), - query_view(), - check_db_ref_count(), - etap:is(is_process_alive(ViewGroup), true, "view group pid is alive"), - - Ref1 = get_db_ref_counter(), - compact_db(), - check_db_ref_count(), - Ref2 = get_db_ref_counter(), - etap:isnt(Ref1, Ref2, "DB ref counter changed"), - etap:is(false, is_process_alive(Ref1), "old DB ref counter is not alive"), - etap:is(is_process_alive(ViewGroup), true, "view group pid is alive"), - - compact_view_group(), - check_db_ref_count(), - Ref3 = get_db_ref_counter(), - etap:is(Ref3, Ref2, "DB ref counter didn't change"), - etap:is(is_process_alive(ViewGroup), true, "view group pid is alive"), - - create_new_doc(<<"doc1001">>), - query_view(), - check_db_ref_count(), - etap:is(is_process_alive(ViewGroup), true, "view group pid is alive"), - - MonRef = erlang:monitor(process, ViewGroup), - ok = couch_server:delete(test_db_name(), []), - receive - {'DOWN', MonRef, _, _, _} -> - etap:diag("view group is dead after DB deletion") - after 5000 -> - etap:bail("view group did not die after DB deletion") - end, - - ok = timer:sleep(1000), - delete_db(), - couch_server_sup:stop(), - ok. - -admin_user_ctx() -> - {user_ctx, #user_ctx{roles=[<<"_admin">>]}}. - -create_db() -> - {ok, Db} = couch_db:create(test_db_name(), [admin_user_ctx()]), - ok = couch_db:close(Db). - -delete_db() -> - couch_server:delete(test_db_name(), [admin_user_ctx()]). - -compact_db() -> - {ok, Db} = couch_db:open_int(test_db_name(), []), - ok = couch_db:start_compact(Db), - ok = couch_db:close(Db), - wait_db_compact_done(10). - -wait_db_compact_done(0) -> - etap:bail("DB compaction failed to finish."); -wait_db_compact_done(N) -> - {ok, Db} = couch_db:open_int(test_db_name(), []), - ok = couch_db:close(Db), - case is_pid(Db#db.compactor_pid) of - false -> - ok; - true -> - ok = timer:sleep(500), - wait_db_compact_done(N - 1) - end. - -compact_view_group() -> - ok = couch_view_compactor:start_compact(test_db_name(), ddoc_name()), - wait_view_compact_done(10). - -wait_view_compact_done(0) -> - etap:bail("View group compaction failed to finish."); -wait_view_compact_done(N) -> - {ok, {{_, Code, _}, _Headers, Body}} = http:request( - get, - {db_url() ++ "/_design/" ++ binary_to_list(ddoc_name()) ++ "/_info", []}, - [], - [{sync, true}]), - case Code of - 200 -> ok; - _ -> etap:bail("Invalid view group info.") - end, - {Info} = couch_util:json_decode(Body), - {IndexInfo} = couch_util:get_value(<<"view_index">>, Info), - CompactRunning = couch_util:get_value(<<"compact_running">>, IndexInfo), - case CompactRunning of - false -> - ok; - true -> - ok = timer:sleep(500), - wait_view_compact_done(N - 1) - end. - -get_db_ref_counter() -> - {ok, #db{fd_ref_counter = Ref} = Db} = couch_db:open_int(test_db_name(), []), - ok = couch_db:close(Db), - Ref. - -check_db_ref_count() -> - {ok, #db{fd_ref_counter = Ref} = Db} = couch_db:open_int(test_db_name(), []), - ok = couch_db:close(Db), - etap:is(couch_ref_counter:count(Ref), 2, - "DB ref counter is only held by couch_db and couch_db_updater"), - ok. - -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/", (ddoc_name())/binary>>}, - {<<"language">>, <<"javascript">>}, - {<<"views">>, {[ - {<<"bar">>, {[ - {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>} - ]}} - ]}} - ]}), - {ok, _} = couch_db:update_docs(Db, [DDoc]), - couch_db:ensure_full_commit(Db), - couch_db:close(Db). - -create_new_doc(Id) -> - {ok, Db} = couch_db:open(test_db_name(), [admin_user_ctx()]), - Doc666 = couch_doc:from_json_obj({[ - {<<"_id">>, Id}, - {<<"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() -> - {ok, {{_, Code, _}, _Headers, _Body}} = http:request( - get, - {db_url() ++ "/_design/" ++ binary_to_list(ddoc_name()) ++ - "/_view/bar", []}, - [], - [{sync, true}]), - etap:is(Code, 200, "got view response"), - ok. diff --git a/test/etap/Makefile.am b/test/etap/Makefile.am deleted file mode 100644 index ecbc3a93..00000000 --- a/test/etap/Makefile.am +++ /dev/null @@ -1,90 +0,0 @@ -## Licensed under the Apache License, Version 2.0 (the "License"); you may not -## use this file except in compliance with the License. You may obtain a copy of -## the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -## WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -## License for the specific language governing permissions and limitations under -## the License. - -noinst_SCRIPTS = run -noinst_DATA = test_util.beam test_web.beam - -noinst_PROGRAMS = test_cfg_register -test_cfg_register_SOURCES = test_cfg_register.c -test_cfg_register_CFLAGS = -D_BSD_SOURCE - -%.beam: %.erl - $(ERLC) $< - -run: run.tpl - sed -e "s|%abs_top_srcdir%|@abs_top_srcdir@|g" \ - -e "s|%abs_top_builddir%|@abs_top_builddir@|g" > \ - $@ < $< - chmod +x $@ - -CLEANFILES = run *.beam -DISTCLEANFILES = temp.* - -EXTRA_DIST = \ - run.tpl \ - test_web.erl \ - random_port.ini \ - 001-load.t \ - 002-icu-driver.t \ - 010-file-basics.t \ - 011-file-headers.t \ - 020-btree-basics.t \ - 021-btree-reductions.t \ - 030-doc-from-json.t \ - 031-doc-to-json.t \ - 040-util.t \ - 041-uuid-gen-seq.ini \ - 041-uuid-gen-utc.ini \ - 041-uuid-gen.t \ - 050-stream.t \ - 060-kt-merging.t \ - 061-kt-missing-leaves.t \ - 062-kt-remove-leaves.t \ - 063-kt-get-leaves.t \ - 064-kt-counting.t \ - 065-kt-stemming.t \ - 070-couch-db.t \ - 072-cleanup.t \ - 080-config-get-set.t \ - 081-config-override.1.ini \ - 081-config-override.2.ini \ - 081-config-override.t \ - 082-config-register.t \ - 083-config-no-files.t \ - 090-task-status.t \ - 100-ref-counter.t \ - 110-replication-httpc.t \ - 111-replication-changes-feed.t \ - 112-replication-missing-revs.t \ - 113-replication-attachment-comp.t \ - 120-stats-collect.t \ - 121-stats-aggregates.cfg \ - 121-stats-aggregates.ini \ - 121-stats-aggregates.t \ - 130-attachments-md5.t \ - 140-attachment-comp.t \ - 150-invalid-view-seq.t \ - 160-vhosts.t \ - 170-os-daemons.es \ - 170-os-daemons.t \ - 171-os-daemons-config.es \ - 171-os-daemons-config.t \ - 172-os-daemon-errors.1.sh \ - 172-os-daemon-errors.2.sh \ - 172-os-daemon-errors.3.sh \ - 172-os-daemon-errors.4.sh \ - 172-os-daemon-errors.t \ - 173-os-daemon-cfg-register.t \ - 180-http-proxy.ini \ - 180-http-proxy.t \ - 190-oauth.t \ - 200-view-group-no-db-leaks.t diff --git a/test/etap/random_port.ini b/test/etap/random_port.ini deleted file mode 100644 index ada3c13d..00000000 --- a/test/etap/random_port.ini +++ /dev/null @@ -1,19 +0,0 @@ -; Licensed to the Apache Software Foundation (ASF) under one -; or more contributor license agreements. See the NOTICE file -; distributed with this work for additional information -; regarding copyright ownership. The ASF licenses this file -; to you 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. - -[httpd] -port = 0 diff --git a/test/etap/run.tpl b/test/etap/run.tpl deleted file mode 100644 index faf0f456..00000000 --- a/test/etap/run.tpl +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh -e - -# 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. - -SRCDIR="%abs_top_srcdir%" -BUILDIR="%abs_top_builddir%" - -export ERL_FLAGS="$ERL_FLAGS -pa $BUILDIR/test/etap/" - -if test $# -gt 0; then - while [ $# -gt 0 ]; do - $1 - shift - done -else - prove $SRCDIR/test/etap/*.t -fi diff --git a/test/etap/test_cfg_register.c b/test/etap/test_cfg_register.c deleted file mode 100644 index 7161eb55..00000000 --- a/test/etap/test_cfg_register.c +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -#include <stdio.h> - -int -main(int argc, const char * argv[]) -{ - char c = '\0'; - size_t num = 1; - - fprintf(stdout, "[\"register\", \"s1\"]\n"); - fprintf(stdout, "[\"register\", \"s2\", \"k\"]\n"); - fflush(stdout); - - while(c != '\n' && num > 0) { - num = fread(&c, 1, 1, stdin); - } - - exit(0); -} diff --git a/test/etap/test_util.erl.in b/test/etap/test_util.erl.in deleted file mode 100644 index 460b0293..00000000 --- a/test/etap/test_util.erl.in +++ /dev/null @@ -1,42 +0,0 @@ -% Licensed under the Apache License, Version 2.0 (the "License"); you may not -% use this file except in compliance with the License. You may obtain a copy of -% the License at -% -% http://www.apache.org/licenses/LICENSE-2.0 -% -% Unless required by applicable law or agreed to in writing, software -% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -% License for the specific language governing permissions and limitations under -% the License. - --module(test_util). - --export([init_code_path/0]). --export([source_file/1, build_file/1, config_files/0]). - -srcdir() -> - "@abs_top_srcdir@". - -builddir() -> - "@abs_top_builddir@". - -init_code_path() -> - Paths = ["etap", "couchdb", "erlang-oauth", "ibrowse", "mochiweb"], - lists:foreach(fun(Name) -> - code:add_patha(filename:join([builddir(), "src", Name])) - end, Paths). - -source_file(Name) -> - filename:join([srcdir(), Name]). - -build_file(Name) -> - filename:join([builddir(), Name]). - -config_files() -> - [ - build_file("etc/couchdb/default_dev.ini"), - build_file("etc/couchdb/local_dev.ini"), - source_file("test/etap/random_port.ini") - ]. - diff --git a/test/etap/test_web.erl b/test/etap/test_web.erl deleted file mode 100644 index ed78651f..00000000 --- a/test/etap/test_web.erl +++ /dev/null @@ -1,99 +0,0 @@ -% Licensed under the Apache License, Version 2.0 (the "License"); you may not -% use this file except in compliance with the License. You may obtain a copy of -% the License at -% -% http://www.apache.org/licenses/LICENSE-2.0 -% -% Unless required by applicable law or agreed to in writing, software -% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -% License for the specific language governing permissions and limitations under -% the License. - --module(test_web). --behaviour(gen_server). - --export([start_link/0, loop/1, get_port/0, set_assert/1, check_last/0]). --export([init/1, terminate/2, code_change/3]). --export([handle_call/3, handle_cast/2, handle_info/2]). - --define(SERVER, test_web_server). --define(HANDLER, test_web_handler). - -start_link() -> - gen_server:start({local, ?HANDLER}, ?MODULE, [], []), - mochiweb_http:start([ - {name, ?SERVER}, - {loop, {?MODULE, loop}}, - {port, 0} - ]). - -loop(Req) -> - %etap:diag("Handling request: ~p", [Req]), - case gen_server:call(?HANDLER, {check_request, Req}) of - {ok, RespInfo} -> - {ok, Req:respond(RespInfo)}; - {raw, {Status, Headers, BodyChunks}} -> - Resp = Req:start_response({Status, Headers}), - lists:foreach(fun(C) -> Resp:send(C) end, BodyChunks), - erlang:put(mochiweb_request_force_close, true), - {ok, Resp}; - {chunked, {Status, Headers, BodyChunks}} -> - Resp = Req:respond({Status, Headers, chunked}), - timer:sleep(500), - lists:foreach(fun(C) -> Resp:write_chunk(C) end, BodyChunks), - Resp:write_chunk([]), - {ok, Resp}; - {error, Reason} -> - etap:diag("Error: ~p", [Reason]), - Body = lists:flatten(io_lib:format("Error: ~p", [Reason])), - {ok, Req:respond({200, [], Body})} - end. - -get_port() -> - mochiweb_socket_server:get(?SERVER, port). - -set_assert(Fun) -> - ok = gen_server:call(?HANDLER, {set_assert, Fun}). - -check_last() -> - gen_server:call(?HANDLER, last_status). - -init(_) -> - {ok, nil}. - -terminate(_Reason, _State) -> - ok. - -handle_call({check_request, Req}, _From, State) when is_function(State, 1) -> - Resp2 = case (catch State(Req)) of - {ok, Resp} -> {reply, {ok, Resp}, was_ok}; - {raw, Resp} -> {reply, {raw, Resp}, was_ok}; - {chunked, Resp} -> {reply, {chunked, Resp}, was_ok}; - Error -> {reply, {error, Error}, not_ok} - end, - Req:cleanup(), - Resp2; -handle_call({check_request, _Req}, _From, _State) -> - {reply, {error, no_assert_function}, not_ok}; -handle_call(last_status, _From, State) when is_atom(State) -> - {reply, State, nil}; -handle_call(last_status, _From, State) -> - {reply, {error, not_checked}, State}; -handle_call({set_assert, Fun}, _From, nil) -> - {reply, ok, Fun}; -handle_call({set_assert, _}, _From, State) -> - {reply, {error, assert_function_set}, State}; -handle_call(Msg, _From, State) -> - {reply, {ignored, Msg}, State}. - -handle_cast(Msg, State) -> - etap:diag("Ignoring cast message: ~p", [Msg]), - {noreply, State}. - -handle_info(Msg, State) -> - etap:diag("Ignoring info message: ~p", [Msg]), - {noreply, State}. - -code_change(_OldVsn, State, _Extra) -> - {ok, State}. |