http://git-wip-us.apache.org/repos/asf/couchdb/blob/0b7b43c9/test/etap/172-os-daemon-errors.3.sh ---------------------------------------------------------------------- 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 f5a1368..0000000 --- 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
http://git-wip-us.apache.org/repos/asf/couchdb/blob/0b7b43c9/test/etap/172-os-daemon-errors.4.sh ---------------------------------------------------------------------- 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 5bc10e8..0000000 --- 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 http://git-wip-us.apache.org/repos/asf/couchdb/blob/0b7b43c9/test/etap/172-os-daemon-errors.t ---------------------------------------------------------------------- diff --git a/test/etap/172-os-daemon-errors.t b/test/etap/172-os-daemon-errors.t deleted file mode 100755 index 1b1fc30..0000000 --- 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() -> - application:start(config), - 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) -> - 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), - config:delete("os_daemons", Name, false). - -test_runs(Name, Cmd) -> - 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."). - http://git-wip-us.apache.org/repos/asf/couchdb/blob/0b7b43c9/test/etap/173-os-daemon-cfg-register.t ---------------------------------------------------------------------- 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 065e999..0000000 --- a/test/etap/173-os-daemon-cfg-register.t +++ /dev/null @@ -1,116 +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() -> - application:start(config), - couch_os_daemons:start_link(), - - DaemonCmd = daemon_cmd() ++ " 2> /dev/null", - - etap:diag("Booting the daemon"), - config:set("os_daemons", daemon_name(), DaemonCmd, false), - wait_for_start(10), - {ok, [D1]} = couch_os_daemons:info([table]), - check_daemon(D1, running), - - etap:diag("Daemon restarts when section changes."), - config:set("s1", "k", "foo", false), - wait_for_restart(10), - {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."), - config:set("s2", "k2", "baz", false), - timer:sleep(1000), % Message travel time. - {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."), - config:set("s2", "k", "bingo", false), - wait_for_restart(10), - {ok, [D4]} = couch_os_daemons:info([table]), - check_daemon(D4, running), - etap:isnt(D4#daemon.kill, D3#daemon.kill, "Kill command changed again."), - - ok. - -wait_for_start(0) -> - throw({error, wait_for_start}); -wait_for_start(N) -> - case couch_os_daemons:info([table]) of - {ok, []} -> - timer:sleep(200), - wait_for_start(N-1); - _ -> - timer:sleep(1000) - end. - -wait_for_restart(0) -> - throw({error, wait_for_restart}); -wait_for_restart(N) -> - {ok, [D]} = couch_os_daemons:info([table]), - case D#daemon.status of - restarting -> - timer:sleep(200), - wait_for_restart(N-1); - _ -> - timer:sleep(1000) - end. - -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."). http://git-wip-us.apache.org/repos/asf/couchdb/blob/0b7b43c9/test/etap/180-http-proxy.ini ---------------------------------------------------------------------- diff --git a/test/etap/180-http-proxy.ini b/test/etap/180-http-proxy.ini deleted file mode 100644 index 3e2ba13..0000000 --- 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/">>} http://git-wip-us.apache.org/repos/asf/couchdb/blob/0b7b43c9/test/etap/180-http-proxy.t ---------------------------------------------------------------------- diff --git a/test/etap/180-http-proxy.t b/test/etap/180-http-proxy.t deleted file mode 100755 index 4897ad6..0000000 --- a/test/etap/180-http-proxy.t +++ /dev/null @@ -1,366 +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:run(61, fun() -> test() end). - -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() -> - ExtraConfig = [test_util:source_file("test/etap/180-http-proxy.ini")], - ok = test_util:start_couch(test_util:config_files() ++ ExtraConfig), - 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(), - "/\">>}" - ]), - 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. http://git-wip-us.apache.org/repos/asf/couchdb/blob/0b7b43c9/test/etap/190-json-stream-parse.t ---------------------------------------------------------------------- diff --git a/test/etap/190-json-stream-parse.t b/test/etap/190-json-stream-parse.t deleted file mode 100755 index 49ea58f..0000000 --- a/test/etap/190-json-stream-parse.t +++ /dev/null @@ -1,184 +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(99), - case (catch test()) of - ok -> - etap:end_tests(); - Other -> - etap:diag("Test died abnormally: ~p", [Other]), - etap:bail("Bad return value.") - end, - ok. - -test() -> - crypto:start(), - ok = test_raw_json_input(), - ok = test_1_byte_data_function(), - ok = test_multiple_bytes_data_function(). - - -test_raw_json_input() -> - etap:diag("Tests with raw JSON string as the input."), - lists:foreach( - fun({EJson, JsonString, Desc}) -> - etap:is( - equiv(EJson, json_stream_parse:to_ejson(JsonString)), - true, - Desc) - end, - cases()), - ok. - - -test_1_byte_data_function() -> - etap:diag("Tests with a 1 byte output data function as the input."), - lists:foreach( - fun({EJson, JsonString, Desc}) -> - DataFun = fun() -> single_byte_data_fun(JsonString) end, - etap:is( - equiv(EJson, json_stream_parse:to_ejson(DataFun)), - true, - Desc) - end, - cases()), - ok. - - -test_multiple_bytes_data_function() -> - etap:diag("Tests with a multiple bytes output data function as the input."), - lists:foreach( - fun({EJson, JsonString, Desc}) -> - DataFun = fun() -> multiple_bytes_data_fun(JsonString) end, - etap:is( - equiv(EJson, json_stream_parse:to_ejson(DataFun)), - true, - Desc) - end, - cases()), - ok. - - -cases() -> - [ - {1, "1", "integer numeric literial"}, - {3.1416, "3.14160", "float numeric literal"}, % text representation may truncate, trail zeroes - {-1, "-1", "negative integer numeric literal"}, - {-3.1416, "-3.14160", "negative float numeric literal"}, - {12.0e10, "1.20000e+11", "float literal in scientific notation"}, - {1.234E+10, "1.23400e+10", "another float literal in scientific notation"}, - {-1.234E-10, "-1.23400e-10", "negative float literal in scientific notation"}, - {10.0, "1.0e+01", "yet another float literal in scientific notation"}, - {123.456, "1.23456E+2", "yet another float literal in scientific notation"}, - {10.0, "1e1", "yet another float literal in scientific notation"}, - {<<"foo">>, "\"foo\"", "string literal"}, - {<<"foo", 5, "bar">>, "\"foo\\u0005bar\"", "string literal with \\u0005"}, - {<<"">>, "\"\"", "empty string literal"}, - {<<"\n\n\n">>, "\"\\n\\n\\n\"", "only new lines literal"}, - {<<"\" \b\f\r\n\t\"">>, "\"\\\" \\b\\f\\r\\n\\t\\\"\"", - "only white spaces string literal"}, - {null, "null", "null literal"}, - {true, "true", "true literal"}, - {false, "false", "false literal"}, - {<<"null">>, "\"null\"", "null string literal"}, - {<<"true">>, "\"true\"", "true string literal"}, - {<<"false">>, "\"false\"", "false string literal"}, - {{[]}, "{}", "empty object literal"}, - {{[{<<"foo">>, <<"bar">>}]}, "{\"foo\":\"bar\"}", - "simple object literal"}, - {{[{<<"foo">>, <<"bar">>}, {<<"baz">>, 123}]}, - "{\"foo\":\"bar\",\"baz\":123}", "another simple object literal"}, - {[], "[]", "empty array literal"}, - {[[]], "[[]]", "empty array literal inside a single element array literal"}, - {[1, <<"foo">>], "[1,\"foo\"]", "simple non-empty array literal"}, - {[1199344435545.0, 1], "[1199344435545.0,1]", - "another simple non-empty array literal"}, - {[false, true, 321, null], "[false, true, 321, null]", "array of literals"}, - {{[{<<"foo">>, [123]}]}, "{\"foo\":[123]}", - "object literal with an array valued property"}, - {{[{<<"foo">>, {[{<<"bar">>, true}]}}]}, - "{\"foo\":{\"bar\":true}}", "nested object literal"}, - {{[{<<"foo">>, []}, {<<"bar">>, {[{<<"baz">>, true}]}}, - {<<"alice">>, <<"bob">>}]}, - "{\"foo\":[],\"bar\":{\"baz\":true},\"alice\":\"bob\"}", - "complex object literal"}, - {[-123, <<"foo">>, {[{<<"bar">>, []}]}, null], - "[-123,\"foo\",{\"bar\":[]},null]", - "complex array literal"} - ]. - - -%% Test for equivalence of Erlang terms. -%% Due to arbitrary order of construction, equivalent objects might -%% compare unequal as erlang terms, so we need to carefully recurse -%% through aggregates (tuples and objects). -equiv({Props1}, {Props2}) -> - equiv_object(Props1, Props2); -equiv(L1, L2) when is_list(L1), is_list(L2) -> - equiv_list(L1, L2); -equiv(N1, N2) when is_number(N1), is_number(N2) -> - N1 == N2; -equiv(B1, B2) when is_binary(B1), is_binary(B2) -> - B1 == B2; -equiv(true, true) -> - true; -equiv(false, false) -> - true; -equiv(null, null) -> - true. - - -%% Object representation and traversal order is unknown. -%% Use the sledgehammer and sort property lists. -equiv_object(Props1, Props2) -> - L1 = lists:keysort(1, Props1), - L2 = lists:keysort(1, Props2), - Pairs = lists:zip(L1, L2), - true = lists:all( - fun({{K1, V1}, {K2, V2}}) -> - equiv(K1, K2) andalso equiv(V1, V2) - end, - Pairs). - - -%% Recursively compare tuple elements for equivalence. -equiv_list([], []) -> - true; -equiv_list([V1 | L1], [V2 | L2]) -> - equiv(V1, V2) andalso equiv_list(L1, L2). - - -single_byte_data_fun([]) -> - done; -single_byte_data_fun([H | T]) -> - {<<H>>, fun() -> single_byte_data_fun(T) end}. - - -multiple_bytes_data_fun([]) -> - done; -multiple_bytes_data_fun(L) -> - N = crypto:rand_uniform(0, 7), - {Part, Rest} = split(L, N), - {list_to_binary(Part), fun() -> multiple_bytes_data_fun(Rest) end}. - -split(L, N) when length(L) =< N -> - {L, []}; -split(L, N) -> - take(N, L, []). - -take(0, L, Acc) -> - {lists:reverse(Acc), L}; -take(N, [H|L], Acc) -> - take(N - 1, L, [H | Acc]). http://git-wip-us.apache.org/repos/asf/couchdb/blob/0b7b43c9/test/etap/200-view-group-no-db-leaks.t ---------------------------------------------------------------------- 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 4cf23b1..0000000 --- a/test/etap/200-view-group-no-db-leaks.t +++ /dev/null @@ -1,271 +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 -}). - --record(db, { - main_pid = nil, - compactor_pid = nil, - instance_start_time, % number of microsecs since jan 1 1970 as a binary string - fd, - fd_monitor, - header = nil, - committed_update_seq, - id_tree, - seq_tree, - local_tree, - update_seq, - name, - filepath, - validate_doc_funs = [], - security = [], - security_ptr = nil, - user_ctx = #user_ctx{}, - waiting_delayed_commit = nil, - revs_limit = 1000, - fsync_options = [], - options = [], - compression, - before_doc_update, - after_doc_read -}). - -test_db_name() -> <<"couch_test_view_group_db_leaks">>. -ddoc_name() -> <<"foo">>. - -main(_) -> - test_util:init_code_path(), - - etap:plan(25), - 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() -> - ok = test_util:start_couch(), - timer:sleep(1000), - put(addr, config:get("httpd", "bind_address", "127.0.0.1")), - put(port, integer_to_list(mochiweb_socket_server:get(couch_httpd, port))), - - delete_db(), - create_db(), - - create_docs(), - {ok, DDocRev} = create_design_doc(), - - {ok, IndexerPid} = couch_index_server:get_index( - couch_mrview_index, test_db_name(), <<"_design/", (ddoc_name())/binary>> - ), - etap:is(is_pid(IndexerPid), true, "got view group pid"), - etap:is(is_process_alive(IndexerPid), true, "view group pid is alive"), - - query_view(3, null, false), - check_db_monitor(), - etap:is(is_process_alive(IndexerPid), true, "view group pid is alive"), - - create_new_doc(<<"doc1000">>), - query_view(4, null, false), - check_db_monitor(), - etap:is(is_process_alive(IndexerPid), true, "view group pid is alive"), - - compact_db(), - check_db_monitor(), - etap:is(is_process_alive(IndexerPid), true, "view group pid is alive"), - - compact_view_group(), - check_db_monitor(), - etap:is(is_process_alive(IndexerPid), true, "view group pid is alive"), - - create_new_doc(<<"doc1001">>), - query_view(5, null, false), - check_db_monitor(), - etap:is(is_process_alive(IndexerPid), true, "view group pid is alive"), - - etap:diag("updating the design document with a new view definition"), - {ok, _NewDDocRev} = update_ddoc_view(DDocRev), - - {ok, NewIndexerPid} = couch_index_server:get_index( - couch_mrview_index, test_db_name(), <<"_design/", (ddoc_name())/binary>> - ), - etap:is(is_pid(NewIndexerPid), true, "got new view group pid"), - etap:is(is_process_alive(NewIndexerPid), true, "new view group pid is alive"), - etap:isnt(NewIndexerPid, IndexerPid, "new view group has a different pid"), - etap:diag("querying view with ?stale=ok, must return empty row set"), - query_view(0, foo, ok), - etap:diag("querying view (without stale), must return 5 rows with value 1"), - query_view(5, 1, false), - MonRef = erlang:monitor(process, IndexerPid), - receive - {'DOWN', MonRef, _, _, _} -> - etap:diag("old view group is dead after ddoc update") - after 5000 -> - etap:bail("old view group is not dead after ddoc update") - end, - - etap:diag("deleting database"), - MonRef2 = erlang:monitor(process, NewIndexerPid), - ok = couch_server:delete(test_db_name(), []), - receive - {'DOWN', MonRef2, _, _, _} -> - etap:diag("new view group is dead after DB deletion") - after 5000 -> - etap:bail("new view group did not die after DB deletion") - end, - - ok = timer:sleep(1000), - delete_db(), - ok = test_util:stop_couch(), - ok. - -admin_user_ctx() -> - {user_ctx, #user_ctx{roles=[<<"_admin">>]}}. - -create_db() -> - {ok, #db{main_pid = Pid} = Db} = couch_db:create( - test_db_name(), [admin_user_ctx()]), - put(db_main_pid, Pid), - 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), - couch_db:wait_for_compaction(Db, 5000), - ok = couch_db:close(Db). - -compact_view_group() -> - DDoc = list_to_binary("_design/" ++ binary_to_list(ddoc_name())), - {ok, Ref} = couch_mrview:compact(test_db_name(), DDoc, [monitor]), - receive {'DOWN', Ref, _, _, _} -> - ok - after 5000 -> - etap:bail("View group compaction failed to finish.") - end. - -check_db_monitor() -> - {ok, #db{fd=Fd} = Db} = couch_db:open_int(test_db_name(), []), - ok = couch_db:close(Db), - {monitored_by, Monitors} = process_info(Fd, monitored_by), - if length(Monitors) == 2 -> ok; true -> - etap:diag("Monitors: ~p ~p", [self(), Monitors]), - lists:foreach(fun(P) -> - etap:diag("~n~n======~n~p~n-----", [P]), - etap:diag("Stack:~n~s", [element(2, process_info(P, backtrace))]) - end, Monitors) - end, - etap:is(length(Monitors), 2, - "DB fd is only monitored by couch_db_updater and couch_stats_collector"), - 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, Rev} = couch_db:update_doc(Db, DDoc, []), - couch_db:ensure_full_commit(Db), - couch_db:close(Db), - {ok, Rev}. - -update_ddoc_view(DDocRev) -> - {ok, Db} = couch_db:open(test_db_name(), [admin_user_ctx()]), - DDoc = couch_doc:from_json_obj({[ - {<<"_id">>, <<"_design/", (ddoc_name())/binary>>}, - {<<"_rev">>, couch_doc:rev_to_str(DDocRev)}, - {<<"language">>, <<"javascript">>}, - {<<"views">>, {[ - {<<"bar">>, {[ - {<<"map">>, <<"function(doc) { emit(doc._id, 1); }">>} - ]}} - ]}} - ]}), - {ok, NewRev} = couch_db:update_doc(Db, DDoc, []), - couch_db:ensure_full_commit(Db), - couch_db:close(Db), - {ok, NewRev}. - -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(ExpectedRowCount, ExpectedRowValue, Stale) -> - {ok, Code, _Headers, Body} = test_util:request( - db_url() ++ "/_design/" ++ binary_to_list(ddoc_name()) ++ "/_view/bar" - ++ case Stale of - false -> []; - _ -> "?stale=" ++ atom_to_list(Stale) - end, - [{"Connection", "close"}], - get), - etap:is(Code, 200, "got view response"), - {Props} = ejson:decode(Body), - Rows = couch_util:get_value(<<"rows">>, Props, []), - etap:is(length(Rows), ExpectedRowCount, "result set has correct # of rows"), - lists:foreach( - fun({Row}) -> - case couch_util:get_value(<<"value">>, Row) of - ExpectedRowValue -> - ok; - _ -> - etap:bail("row has incorrect value") - end - end, - Rows). http://git-wip-us.apache.org/repos/asf/couchdb/blob/0b7b43c9/test/etap/201-view-group-shutdown.t ---------------------------------------------------------------------- diff --git a/test/etap/201-view-group-shutdown.t b/test/etap/201-view-group-shutdown.t deleted file mode 100755 index f374888..0000000 --- a/test/etap/201-view-group-shutdown.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. - --record(user_ctx, { - name = null, - roles = [], - handler -}). - --record(db, { - main_pid = nil, - compactor_pid = nil, - instance_start_time, % number of microsecs since jan 1 1970 as a binary string - fd, - fd_monitor, - header = nil, - committed_update_seq, - id_tree, - seq_tree, - local_tree, - update_seq, - name, - filepath, - validate_doc_funs = [], - security = [], - security_ptr = nil, - user_ctx = #user_ctx{}, - waiting_delayed_commit = nil, - revs_limit = 1000, - fsync_options = [], - options = [], - compression, - before_doc_update, - after_doc_read -}). - -main_db_name() -> <<"couch_test_view_group_shutdown">>. - - -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() -> - ok = test_util:start_couch(), - ok = config:set("couchdb", "max_dbs_open", "3", false), - ok = config:set("couchdb", "delayed_commits", "false", false), - crypto:start(), - - % Test that while a view group is being compacted its database can not - % be closed by the database LRU system. - test_view_group_compaction(), - - ok = test_util:stop_couch(), - ok. - - -test_view_group_compaction() -> - {ok, DbWriter3} = create_db(<<"couch_test_view_group_shutdown_w3">>), - ok = couch_db:close(DbWriter3), - - {ok, MainDb} = create_main_db(), - ok = couch_db:close(MainDb), - - {ok, DbWriter1} = create_db(<<"couch_test_view_group_shutdown_w1">>), - ok = couch_db:close(DbWriter1), - - {ok, DbWriter2} = create_db(<<"couch_test_view_group_shutdown_w2">>), - ok = couch_db:close(DbWriter2), - - Writer1 = spawn_writer(DbWriter1#db.name), - Writer2 = spawn_writer(DbWriter2#db.name), - etap:is(is_process_alive(Writer1), true, "Spawned writer 1"), - etap:is(is_process_alive(Writer2), true, "Spawned writer 2"), - - etap:is(get_writer_status(Writer1), ok, "Writer 1 opened his database"), - etap:is(get_writer_status(Writer2), ok, "Writer 2 opened his database"), - - {ok, MonRef} = couch_mrview:compact(MainDb#db.name, <<"_design/foo">>, [monitor]), - - % Add some more docs to database and trigger view update - {ok, MainDb2} = couch_db:open_int(MainDb#db.name, []), - ok = populate_main_db(MainDb2, 3, 3), - update_view(MainDb2#db.name, <<"_design/foo">>, <<"foo">>), - ok = couch_db:close(MainDb2), - - % Assuming the view compaction takes more than 50ms to complete - ok = timer:sleep(50), - Writer3 = spawn_writer(DbWriter3#db.name), - etap:is(is_process_alive(Writer3), true, "Spawned writer 3"), - - etap:is(get_writer_status(Writer3), {error, all_dbs_active}, - "Writer 3 got {error, all_dbs_active} when opening his database"), - - etap:is(is_process_alive(Writer1), true, "Writer 1 still alive"), - etap:is(is_process_alive(Writer2), true, "Writer 2 still alive"), - etap:is(is_process_alive(Writer3), true, "Writer 3 still alive"), - - receive - {'DOWN', MonRef, process, _, normal} -> - etap:diag("View group compaction successful"), - ok; - {'DOWN', MonRef, process, _, _Reason} -> - etap:bail("Failure compacting view group") - end, - - ok = timer:sleep(2000), - - etap:is(writer_try_again(Writer3), ok, - "Told writer 3 to try open his database again"), - etap:is(get_writer_status(Writer3), ok, - "Writer 3 was able to open his database"), - - etap:is(is_process_alive(Writer1), true, "Writer 1 still alive"), - etap:is(is_process_alive(Writer2), true, "Writer 2 still alive"), - etap:is(is_process_alive(Writer3), true, "Writer 3 still alive"), - - etap:is(stop_writer(Writer1), ok, "Stopped writer 1"), - etap:is(stop_writer(Writer2), ok, "Stopped writer 2"), - etap:is(stop_writer(Writer3), ok, "Stopped writer 3"), - - delete_db(MainDb), - delete_db(DbWriter1), - delete_db(DbWriter2), - delete_db(DbWriter3). - - -create_main_db() -> - {ok, Db} = create_db(main_db_name()), - DDoc = couch_doc:from_json_obj({[ - {<<"_id">>, <<"_design/foo">>}, - {<<"language">>, <<"javascript">>}, - {<<"views">>, {[ - {<<"foo">>, {[ - {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>} - ]}}, - {<<"foo2">>, {[ - {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>} - ]}}, - {<<"foo3">>, {[ - {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>} - ]}}, - {<<"foo4">>, {[ - {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>} - ]}}, - {<<"foo5">>, {[ - {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>} - ]}} - ]}} - ]}), - {ok, _} = couch_db:update_doc(Db, DDoc, []), - ok = populate_main_db(Db, 1000, 20000), - update_view(Db#db.name, <<"_design/foo">>, <<"foo">>), - {ok, Db}. - - -populate_main_db(Db, BatchSize, N) when N > 0 -> - Docs = lists:map( - fun(_) -> - couch_doc:from_json_obj({[ - {<<"_id">>, couch_uuids:new()}, - {<<"value">>, base64:encode(crypto:rand_bytes(1000))} - ]}) - end, - lists:seq(1, BatchSize)), - {ok, _} = couch_db:update_docs(Db, Docs, []), - populate_main_db(Db, BatchSize, N - length(Docs)); -populate_main_db(_Db, _, _) -> - ok. - - -update_view(DbName, DDocName, ViewName) -> - {ok, Db} = couch_db:open_int(DbName, []), - {ok, DDoc} = couch_db:open_doc(Db, DDocName, [ejson_body]), - couch_mrview:query_view(Db, DDoc, ViewName, [{stale, false}]), - ok = couch_db:close(Db), - etap:diag("View group updated"). - - -create_db(DbName) -> - {ok, Db} = couch_db:create( - DbName, - [{user_ctx, #user_ctx{roles = [<<"_admin">>]}}, overwrite]), - {ok, Db}. - - -delete_db(#db{name = DbName, main_pid = Pid}) -> - ok = couch_server:delete( - DbName, [{user_ctx, #user_ctx{roles = [<<"_admin">>]}}]), - MonRef = erlang:monitor(process, Pid), - receive - {'DOWN', MonRef, process, Pid, _Reason} -> - ok - after 30000 -> - etap:bail("Timeout deleting database") - end. - - -spawn_writer(DbName) -> - Parent = self(), - spawn(fun() -> - process_flag(priority, high), - writer_loop(DbName, Parent) - end). - - -get_writer_status(Writer) -> - Ref = make_ref(), - Writer ! {get_status, Ref}, - receive - {db_open, Ref} -> - ok; - {db_open_error, Error, Ref} -> - Error - after 5000 -> - timeout - end. - - -writer_try_again(Writer) -> - Ref = make_ref(), - Writer ! {try_again, Ref}, - receive - {ok, Ref} -> - ok - after 5000 -> - timeout - end. - - -stop_writer(Writer) -> - Ref = make_ref(), - Writer ! {stop, Ref}, - receive - {ok, Ref} -> - ok - after 5000 -> - etap:bail("Timeout stopping writer process") - end. - - -% Just keep the database open, no need to actually do something on it. -writer_loop(DbName, Parent) -> - case couch_db:open_int(DbName, []) of - {ok, Db} -> - writer_loop_1(Db, Parent); - Error -> - writer_loop_2(DbName, Parent, Error) - end. - -writer_loop_1(Db, Parent) -> - receive - {get_status, Ref} -> - Parent ! {db_open, Ref}, - writer_loop_1(Db, Parent); - {stop, Ref} -> - ok = couch_db:close(Db), - Parent ! {ok, Ref} - end. - -writer_loop_2(DbName, Parent, Error) -> - receive - {get_status, Ref} -> - Parent ! {db_open_error, Error, Ref}, - writer_loop_2(DbName, Parent, Error); - {try_again, Ref} -> - Parent ! {ok, Ref}, - writer_loop(DbName, Parent) - end. http://git-wip-us.apache.org/repos/asf/couchdb/blob/0b7b43c9/test/etap/210-os-proc-pool.t ---------------------------------------------------------------------- diff --git a/test/etap/210-os-proc-pool.t b/test/etap/210-os-proc-pool.t deleted file mode 100755 index 20c45e4..0000000 --- a/test/etap/210-os-proc-pool.t +++ /dev/null @@ -1,163 +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(21), - 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() -> - ok = test_util:start_couch(), - config:set("query_server_config", "os_process_limit", "3", false), - - test_pool_full(), - test_client_unexpected_exit(), - - ok = test_util:stop_couch(), - ok. - - -test_pool_full() -> - Client1 = spawn_client(), - Client2 = spawn_client(), - Client3 = spawn_client(), - - etap:diag("Check that we can spawn the max number of processes."), - etap:is(ping_client(Client1), ok, "Client 1 started ok."), - etap:is(ping_client(Client2), ok, "Client 2 started ok."), - etap:is(ping_client(Client3), ok, "Client 3 started ok."), - - Proc1 = get_client_proc(Client1, "1"), - Proc2 = get_client_proc(Client2, "2"), - Proc3 = get_client_proc(Client3, "3"), - etap:isnt(Proc1, Proc2, "Clients 1 and 2 got different procs."), - etap:isnt(Proc2, Proc3, "Clients 2 and 3 got different procs."), - etap:isnt(Proc1, Proc3, "Clients 1 and 3 got different procs."), - - etap:diag("Check that client 4 blocks waiting for a process."), - Client4 = spawn_client(), - etap:is(ping_client(Client4), timeout, "Client 4 blocked while waiting."), - - etap:diag("Check that stopping a client gives up its process."), - etap:is(stop_client(Client1), ok, "First client stopped."), - - etap:diag("And check that our blocked process has been unblocked."), - etap:is(ping_client(Client4), ok, "Client was unblocked."), - - Proc4 = get_client_proc(Client4, "4"), - etap:is(Proc4, Proc1, "Client 4 got proc that client 1 got before."), - - lists:map(fun(C) -> ok = stop_client(C) end, [Client2, Client3, Client4]). - - -test_client_unexpected_exit() -> - Client1 = spawn_client(), - Client2 = spawn_client(), - Client3 = spawn_client(), - - etap:diag("Check that up to os_process_limit clients started."), - etap:is(ping_client(Client1), ok, "Client 1 started ok."), - etap:is(ping_client(Client2), ok, "Client 2 started ok."), - etap:is(ping_client(Client3), ok, "Client 3 started ok."), - - Proc1 = get_client_proc(Client1, "1"), - Proc2 = get_client_proc(Client2, "2"), - Proc3 = get_client_proc(Client3, "3"), - etap:isnt(Proc1, Proc2, "Clients 1 and 2 got different procs."), - etap:isnt(Proc2, Proc3, "Clients 2 and 3 got different procs."), - etap:isnt(Proc1, Proc3, "Clients 1 and 3 got different procs."), - - etap:diag("Check that killing a client frees an os_process."), - etap:is(kill_client(Client1), ok, "Client 1 died all right."), - - etap:diag("Check that a new client is not blocked on boot."), - Client4 = spawn_client(), - etap:is(ping_client(Client4), ok, "New client booted without blocking."), - - Proc4 = get_client_proc(Client4, "4"), - etap:isnt(Proc4, Proc1, - "Client 4 got a proc different from the one client 1 got before."), - etap:isnt(Proc4, Proc2, "Client 4's proc different from client 2's proc."), - etap:isnt(Proc4, Proc3, "Client 4's proc different from client 3's proc."), - - lists:map(fun(C) -> ok = stop_client(C) end, [Client2, Client3, Client4]). - - -spawn_client() -> - Parent = self(), - Ref = make_ref(), - Pid = spawn(fun() -> - Proc = couch_query_servers:get_os_process(<<"javascript">>), - loop(Parent, Ref, Proc) - end), - {Pid, Ref}. - - -ping_client({Pid, Ref}) -> - Pid ! ping, - receive - {pong, Ref} -> ok - after 3000 -> timeout - end. - - -get_client_proc({Pid, Ref}, ClientName) -> - Pid ! get_proc, - receive - {proc, Ref, Proc} -> Proc - after 3000 -> - etap:bail("Timeout getting client " ++ ClientName ++ " proc.") - end. - - -stop_client({Pid, Ref}) -> - Pid ! stop, - receive - {stop, Ref} -> ok - after 3000 -> timeout - end. - - -kill_client({Pid, Ref}) -> - Pid ! die, - receive - {die, Ref} -> ok - after 3000 -> timeout - end. - - -loop(Parent, Ref, Proc) -> - receive - ping -> - Parent ! {pong, Ref}, - loop(Parent, Ref, Proc); - get_proc -> - Parent ! {proc, Ref, Proc}, - loop(Parent, Ref, Proc); - stop -> - couch_query_servers:ret_os_process(Proc), - Parent ! {stop, Ref}; - die -> - Parent ! {die, Ref}, - exit(some_error) - end. http://git-wip-us.apache.org/repos/asf/couchdb/blob/0b7b43c9/test/etap/220-compaction-daemon.t ---------------------------------------------------------------------- diff --git a/test/etap/220-compaction-daemon.t b/test/etap/220-compaction-daemon.t deleted file mode 100755 index 262113d..0000000 --- a/test/etap/220-compaction-daemon.t +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env escript -%% -*- erlang -*- - -% Licensed under the Apache License, Version 2.0 (the "License"); you may not -% use this file except in compliance with the License. You may obtain a copy of -% the License at -% -% http://www.apache.org/licenses/LICENSE-2.0 -% -% Unless required by applicable law or agreed to in writing, software -% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -% License for the specific language governing permissions and limitations under -% the License. - --record(user_ctx, { - name = null, - roles = [], - handler -}). - -test_db_name() -> - <<"couch_test_compaction_daemon">>. - -main(_) -> - test_util:init_code_path(), - - etap:plan(10), - case (catch test()) of - ok -> - etap:end_tests(); - Other -> - etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), - etap:bail(Other) - end, - ok. - -test() -> - ok = test_util:start_couch(), - timer:sleep(1000), - put(addr, config:get("httpd", "bind_address", "127.0.0.1")), - put(port, integer_to_list(mochiweb_socket_server:get(couch_httpd, port))), - - disable_compact_daemon(), - - delete_db(), - {ok, Db} = create_db(), - - add_design_doc(Db), - couch_db:close(Db), - populate(70, 70, 200 * 1024), - - {_, DbFileSize} = get_db_frag(), - {_, ViewFileSize} = get_view_frag(), - - % enable automatic compaction - ok = config:set("compaction_daemon", "check_interval", "3", false), - ok = config:set("compaction_daemon", "min_file_size", "100000", false), - ok = config:set( - "compactions", - binary_to_list(test_db_name()), - "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]", - false), - - ok = timer:sleep(4000), % something >= check_interval - wait_compaction_finished(), - - {DbFrag2, DbFileSize2} = get_db_frag(), - {ViewFrag2, ViewFileSize2} = get_view_frag(), - - etap:is(true, (DbFrag2 < 70), "Database fragmentation is < 70% after compaction"), - etap:is(true, (ViewFrag2 < 70), "View fragmentation is < 70% after compaction"), - etap:is(true, (DbFileSize2 < DbFileSize), "Database file size decreased"), - etap:is(true, (ViewFileSize2 < ViewFileSize), "View file size decreased"), - - disable_compact_daemon(), - ok = timer:sleep(6000), % 2 times check_interval - etap:is(couch_db:is_idle(Db), true, "Database is idle"), - populate(70, 70, 200 * 1024), - {_, DbFileSize3} = get_db_frag(), - {_, ViewFileSize3} = get_view_frag(), - - % enable automatic compaction - ok = config:set( - "compactions", - "_default", - "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]", - false), - - ok = timer:sleep(4000), % something >= check_interval - wait_compaction_finished(), - - {DbFrag4, DbFileSize4} = get_db_frag(), - {ViewFrag4, ViewFileSize4} = get_view_frag(), - - etap:is(true, (DbFrag4 < 70), "Database fragmentation is < 70% after compaction"), - etap:is(true, (ViewFrag4 < 70), "View fragmentation is < 70% after compaction"), - etap:is(true, (DbFileSize4 < DbFileSize3), "Database file size decreased again"), - etap:is(true, (ViewFileSize4 < ViewFileSize3), "View file size decreased again"), - - ok = timer:sleep(6000), % 2 times check_interval - etap:is(couch_db:is_idle(Db), true, "Database is idle"), - - delete_db(), - ok = test_util:stop_couch(), - ok. - -disable_compact_daemon() -> - Configs = config:get("compactions"), - lists:foreach( - fun({DbName, _}) -> - ok = config:delete("compactions", DbName, false) - end, - Configs). - -admin_user_ctx() -> - {user_ctx, #user_ctx{roles = [<<"_admin">>]}}. - -create_db() -> - {ok, _} = couch_db:create(test_db_name(), [admin_user_ctx()]). - -delete_db() -> - couch_server:delete(test_db_name(), [admin_user_ctx()]). - -add_design_doc(Db) -> - DDoc = couch_doc:from_json_obj({[ - {<<"_id">>, <<"_design/foo">>}, - {<<"language">>, <<"javascript">>}, - {<<"views">>, {[ - {<<"foo">>, {[ - {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>} - ]}}, - {<<"foo2">>, {[ - {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>} - ]}}, - {<<"foo3">>, {[ - {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>} - ]}} - ]}} - ]}), - {ok, _} = couch_db:update_docs(Db, [DDoc]), - {ok, _} = couch_db:ensure_full_commit(Db), - ok. - -populate(DbFrag, ViewFrag, MinFileSize) -> - {CurDbFrag, DbFileSize} = get_db_frag(), - {CurViewFrag, ViewFileSize} = get_view_frag(), - populate( - DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag, - lists:min([DbFileSize, ViewFileSize])). - -populate(DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag, FileSize) - when CurDbFrag >= DbFrag, CurViewFrag >= ViewFrag, FileSize >= MinFileSize -> - ok; -populate(DbFrag, ViewFrag, MinFileSize, _, _, _) -> - update(), - {CurDbFrag, DbFileSize} = get_db_frag(), - {CurViewFrag, ViewFileSize} = get_view_frag(), - populate( - DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag, - lists:min([DbFileSize, ViewFileSize])). - -update() -> - {ok, Db} = couch_db:open_int(test_db_name(), []), - lists:foreach(fun(_) -> - Doc = couch_doc:from_json_obj({[{<<"_id">>, couch_uuids:new()}]}), - {ok, _} = couch_db:update_docs(Db, [Doc]), - query_view() - end, lists:seq(1, 100)), - couch_db:close(Db). - -db_url() -> - "http://" ++ get(addr) ++ ":" ++ get(port) ++ "/" ++ - binary_to_list(test_db_name()). - -query_view() -> - {ok, Code, _Headers, _Body} = test_util:request( - db_url() ++ "/_design/foo/_view/foo", [], get), - case Code of - 200 -> - ok; - _ -> - etap:bail("error querying view") - end. - -get_db_frag() -> - {ok, Db} = couch_db:open_int(test_db_name(), []), - {ok, Info} = couch_db:get_db_info(Db), - couch_db:close(Db), - FileSize = couch_util:get_value(disk_size, Info), - DataSize = couch_util:get_value(data_size, Info), - {round((FileSize - DataSize) / FileSize * 100), FileSize}. - -get_view_frag() -> - {ok, Db} = couch_db:open_int(test_db_name(), []), - {ok, Info} = couch_mrview:get_info(Db, <<"_design/foo">>), - couch_db:close(Db), - FileSize = couch_util:get_value(disk_size, Info), - DataSize = couch_util:get_value(data_size, Info), - {round((FileSize - DataSize) / FileSize * 100), FileSize}. - - -wait_compaction_finished() -> - Parent = self(), - Loop = spawn_link(fun() -> wait_loop(Parent) end), - receive - {done, Loop} -> - etap:diag("Database and view compaction have finished") - after 60000 -> - etap:bail("Compaction not triggered") - end. - -wait_loop(Parent) -> - {ok, Db} = couch_db:open_int(test_db_name(), []), - {ok, DbInfo} = couch_db:get_db_info(Db), - {ok, ViewInfo} = couch_mrview:get_info(Db, <<"_design/foo">>), - couch_db:close(Db), - case (couch_util:get_value(compact_running, ViewInfo) =:= true) orelse - (couch_util:get_value(compact_running, DbInfo) =:= true) of - false -> - Parent ! {done, self()}; - true -> - ok = timer:sleep(500), - wait_loop(Parent) - end. http://git-wip-us.apache.org/repos/asf/couchdb/blob/0b7b43c9/test/etap/230-pbkfd2.t ---------------------------------------------------------------------- diff --git a/test/etap/230-pbkfd2.t b/test/etap/230-pbkfd2.t deleted file mode 100644 index d980ef6..0000000 --- a/test/etap/230-pbkfd2.t +++ /dev/null @@ -1,38 +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), - etap:is(couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 1, 20), - {ok, <<"0c60c80f961f0e71f3a9b524af6012062fe037a6">>}, - "test vector #1"), - etap:is(couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 2, 20), - {ok, <<"ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957">>}, - "test vector #2"), - etap:is(couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 4096, 20), - {ok, <<"4b007901b765489abead49d926f721d065a429c1">>}, - "test vector #3"), - etap:is(couch_passwords:pbkdf2(<<"passwordPASSWORDpassword">>, - <<"saltSALTsaltSALTsaltSALTsaltSALTsalt">>, 4096, 25), - {ok, <<"3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038">>}, - "test vector #4"), - etap:is(couch_passwords:pbkdf2(<<"pass\0word">>, <<"sa\0lt">>, 4096, 16), - {ok, <<"56fa6aa75548099dcc37d7f03425e0c3">>}, - "test vector #5"), - etap:is(couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 16777216, 20), - {ok, <<"eefe3d61cd4da4e4e9945b3d6ba2158c2634e984">>}, - "test vector #6"), - etap:end_tests(). http://git-wip-us.apache.org/repos/asf/couchdb/blob/0b7b43c9/test/etap/231-cors.t ---------------------------------------------------------------------- diff --git a/test/etap/231-cors.t b/test/etap/231-cors.t deleted file mode 100644 index 0eb0252..0000000 --- a/test/etap/231-cors.t +++ /dev/null @@ -1,430 +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(SUPPORTED_METHODS, "GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, COPY, OPTIONS"). -server() -> - lists:concat([ - "http://127.0.0.1:", - mochiweb_socket_server:get(couch_httpd, port), - "/" - ]). - - -main(_) -> - test_util:init_code_path(), - - etap:plan(29), - case (catch test()) of - ok -> - etap:end_tests(); - Other -> - etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), - etap:bail(Other) - end, - ok. - -dbname() -> "etap-test-db". -dbname1() -> "etap-test-db1". -dbname2() -> "etap-test-db2". - -admin_user_ctx() -> {user_ctx, #user_ctx{roles=[<<"_admin">>]}}. - -set_admin_password(UserName, Password) -> - Hashed = couch_passwords:hash_admin_password(Password), - config:set("admins", UserName, Hashed, false). - -cycle_db(DbName) -> - couch_server:delete(list_to_binary(DbName), [admin_user_ctx()]), - {ok, Db} = couch_db:create(list_to_binary(DbName), [admin_user_ctx()]), - Db. - -test() -> - %% launch couchdb - ok = test_util:start_couch(), - - %% initialize db - timer:sleep(1000), - Db = cycle_db(dbname()), - Db1 = cycle_db(dbname1()), - Db2 = cycle_db(dbname2()), - - % CORS is disabled by default - test_no_headers_server(), - test_no_headers_db(), - - % Now enable CORS - ok = config:set("httpd", "enable_cors", "true", false), - ok = config:set("cors", "origins", "http://example.com", false), - - %% do tests - test_incorrect_origin_simple_request(), - test_incorrect_origin_preflight_request(), - - test_preflight_request(), - test_db_request(), - test_doc_with_attachment_request(), - test_doc_with_attachment_range_request(), - test_db_preflight_request(), - test_db1_origin_request(), - test_preflight_with_port1(), - test_preflight_with_scheme1(), - test_if_none_match_header(), - - ok = config:set("cors", "origins", "http://example.com:5984", false), - test_preflight_with_port2(), - - ok = config:set("cors", "origins", "https://example.com:5984", false), - test_preflight_with_scheme2(), - - ok = config:set("cors", "origins", "*", false), - test_preflight_with_wildcard(), - - ok = config:set("cors", "origins", "http://example.com", false), - test_case_sensitive_mismatch_of_allowed_origins(), - - % http://www.w3.org/TR/cors/#supports-credentials - % 6.1.3 - % If the resource supports credentials add a single - % Access-Control-Allow-Origin header, with the value - % of the Origin header as value, and add a single - % Access-Control-Allow-Credentials header with the - % case-sensitive string "true" as value. - % Otherwise, add a single Access-Control-Allow-Origin - % header, with either the value of the Origin header - % or the string "*" as value. - % Note: The string "*" cannot be used for a resource - % that supports credentials. - test_db_request_credentials_header_off(), - ok = config:set("cors", "credentials", "true", false), - test_db_request_credentials_header_on(), - % We donât test wildcards & credentials as that would - % fall into the realm of validating config values - % which we donât do at all yet - - % test with vhosts - ok = config:set("vhosts", "example.com", "/", false), - test_preflight_request(true), - test_db_request(true), - test_db_preflight_request(true), - test_db1_origin_request(true), - test_preflight_with_port1(true), - test_preflight_with_scheme1(true), - - % TBD - % test multiple per-host configuration - - %% do tests with auth - ok = set_admin_password("test", <<"test">>), - - test_db_preflight_auth_request(), - test_db_origin_auth_request(), - - - %% restart boilerplate - catch couch_db:close(Db), - catch couch_db:close(Db1), - catch couch_db:close(Db2), - - couch_server:delete(list_to_binary(dbname()), [admin_user_ctx()]), - couch_server:delete(list_to_binary(dbname1()), [admin_user_ctx()]), - couch_server:delete(list_to_binary(dbname2()), [admin_user_ctx()]), - - timer:sleep(3000), - ok = test_util:stop_couch(), - ok. - -test_preflight_request() -> test_preflight_request(false). -test_db_request() -> test_db_request(false). -test_db_preflight_request() -> test_db_preflight_request(false). -test_db1_origin_request() -> test_db1_origin_request(false). -test_preflight_with_port1() -> test_preflight_with_port1(false). -test_preflight_with_scheme1() -> test_preflight_with_scheme1(false). - -%% Cors is disabled, should not return Access-Control-Allow-Origin -test_no_headers_server() -> - Headers = [{"Origin", "http://127.0.0.1"}], - {ok, _, Resp, _} = ibrowse:send_req(server(), Headers, get, []), - etap:is(proplists:get_value("Access-Control-Allow-Origin", Resp), - undefined, "No CORS Headers when disabled"). - -%% Cors is disabled, should not return Access-Control-Allow-Origin -test_no_headers_db() -> - Headers = [{"Origin", "http://127.0.0.1"}], - Url = server() ++ "etap-test-db", - {ok, _, Resp, _} = ibrowse:send_req(Url, Headers, get, []), - etap:is(proplists:get_value("Access-Control-Allow-Origin", Resp), - undefined, "No CORS Headers when disabled"). - -test_incorrect_origin_simple_request() -> - Headers = [{"Origin", "http://127.0.0.1"}], - {ok, _, RespHeaders, _} = ibrowse:send_req(server(), Headers, get, []), - etap:is(proplists:get_value("Access-Control-Allow-Origin", RespHeaders), - undefined, - "Specified invalid origin, no Access"). - -test_incorrect_origin_preflight_request() -> - Headers = [{"Origin", "http://127.0.0.1"}, - {"Access-Control-Request-Method", "GET"}], - {ok, _, RespHeaders, _} = ibrowse:send_req(server(), Headers, options, []), - etap:is(proplists:get_value("Access-Control-Allow-Origin", RespHeaders), - undefined, - "invalid origin"). - -test_preflight_request(VHost) -> - Headers = [{"Origin", "http://example.com"}, - {"Access-Control-Request-Method", "GET"}] - ++ maybe_append_vhost(VHost), - - case ibrowse:send_req(server(), Headers, options, []) of - {ok, _, RespHeaders, _} -> - etap:is(proplists:get_value("Access-Control-Allow-Methods", RespHeaders), - ?SUPPORTED_METHODS, - "test_preflight_request Access-Control-Allow-Methods ok"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - -test_db_request(VHost) -> - Headers = [{"Origin", "http://example.com"}] - ++ maybe_append_vhost(VHost), - Url = server() ++ "etap-test-db", - case ibrowse:send_req(Url, Headers, get, []) of - {ok, _, RespHeaders, _Body} -> - etap:is(proplists:get_value("Access-Control-Allow-Origin", RespHeaders), - "http://example.com", - "db Access-Control-Allow-Origin ok"), - etap:is(proplists:get_value("Access-Control-Expose-Headers", RespHeaders), - "Cache-Control, Content-Type, Server", - "db Access-Control-Expose-Headers ok"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - -% COUCHDB-1689 -test_doc_with_attachment_request() -> - DocUrl = server() ++ "etap-test-db/doc1", - ibrowse:send_req(DocUrl ++ "/attachment.txt", - [{"Content-Type", "text/plain"}], put, "this is a text attachment"), - - Headers = [{"Origin", "http://example.com"}], - Url = DocUrl ++ "?attachments=true", - case ibrowse:send_req(Url, Headers, get, []) of - {ok, Code, _RespHeaders, _Body} -> - etap:is(Code, "200", "Response without errors"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - -% COUCHDB-1689 -test_doc_with_attachment_range_request() -> - AttachmentUrl = server() ++ "etap-test-db/doc2/attachment.bin", - % Use a Content-Type that doesn't get compressed - ibrowse:send_req(AttachmentUrl, - [{"Content-Type", "application/octet-stream"}], put, - "this is an attachment"), - - Headers = [{"Origin", "http://example.com"}, {"Range", "bytes=0-6"}], - case ibrowse:send_req(AttachmentUrl, Headers, get, []) of - {ok, Code, _RespHeaders, _Body} -> - etap:is(Code, "206", "Response without errors"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - -% COUCHDB-1697 -test_if_none_match_header() -> - Url = server() ++ "etap-test-db/doc2", - Headers = [{"Origin", "http://example.com"}], - {ok, _, _RespHeaders, _} = ibrowse:send_req(Url, Headers, get, []), - ETag = proplists:get_value("ETag", _RespHeaders), - Headers2 = [{"Origin", "http://example.com"}, {"If-None-Match", ETag}], - case ibrowse:send_req(Url, Headers2, get, []) of - {ok, Code, _RespHeaders2, _} -> - etap:is(Code, "304", "Responded with Not Modified"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - -test_db_request_credentials_header_off() -> - Headers = [{"Origin", "http://example.com"}], - Url = server() ++ "etap-test-db", - case ibrowse:send_req(Url, Headers, get, []) of - {ok, _, RespHeaders, _Body} -> - etap:is(proplists:get_value("Access-Control-Allow-Credentials", RespHeaders), - undefined, - "db Access-Control-Allow-Credentials off"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - -test_db_request_credentials_header_on() -> - Headers = [{"Origin", "http://example.com"}], - Url = server() ++ "etap-test-db", - case ibrowse:send_req(Url, Headers, get, []) of - {ok, _, RespHeaders, _Body} -> - etap:is(proplists:get_value("Access-Control-Allow-Credentials", RespHeaders), - "true", - "db Access-Control-Allow-Credentials ok"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - -test_db_preflight_request(VHost) -> - Url = server() ++ "etap-test-db", - Headers = [{"Origin", "http://example.com"}, - {"Access-Control-Request-Method", "GET"}] - ++ maybe_append_vhost(VHost), - case ibrowse:send_req(Url, Headers, options, []) of - {ok, _, RespHeaders, _} -> - etap:is(proplists:get_value("Access-Control-Allow-Methods", RespHeaders), - ?SUPPORTED_METHODS, - "db Access-Control-Allow-Methods ok"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - - -test_db1_origin_request(VHost) -> - Headers = [{"Origin", "http://example.com"}] - ++ maybe_append_vhost(VHost), - Url = server() ++ "etap-test-db1", - case ibrowse:send_req(Url, Headers, get, [], [{host_header, "example.com"}]) of - {ok, _, RespHeaders, _Body} -> - etap:is(proplists:get_value("Access-Control-Allow-Origin", RespHeaders), - "http://example.com", - "db origin ok"); - _Else -> - io:format("else ~p~n", [_Else]), - etap:is(false, true, "ibrowse failed") - end. - -test_db_preflight_auth_request() -> - Url = server() ++ "etap-test-db2", - Headers = [{"Origin", "http://example.com"}, - {"Access-Control-Request-Method", "GET"}], - case ibrowse:send_req(Url, Headers, options, []) of - {ok, _Status, RespHeaders, _} -> - etap:is(proplists:get_value("Access-Control-Allow-Methods", RespHeaders), - ?SUPPORTED_METHODS, - "db Access-Control-Allow-Methods ok"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - - -test_db_origin_auth_request() -> - Headers = [{"Origin", "http://example.com"}], - Url = server() ++ "etap-test-db2", - - case ibrowse:send_req(Url, Headers, get, [], - [{basic_auth, {"test", "test"}}]) of - {ok, _, RespHeaders, _Body} -> - etap:is(proplists:get_value("Access-Control-Allow-Origin", RespHeaders), - "http://example.com", - "db origin ok"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - -test_preflight_with_wildcard() -> - Headers = [{"Origin", "http://example.com"}, - {"Access-Control-Request-Method", "GET"}], - case ibrowse:send_req(server(), Headers, options, []) of - {ok, _, RespHeaders, _} -> - % I would either expect the current origin or a wildcard to be returned - etap:is(proplists:get_value("Access-Control-Allow-Origin", RespHeaders), - "http://example.com", - "db origin ok"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - -test_preflight_with_port1(VHost) -> - Headers = [{"Origin", "http://example.com:5984"}, - {"Access-Control-Request-Method", "GET"}] - ++ maybe_append_vhost(VHost), - case ibrowse:send_req(server(), Headers, options, []) of - {ok, _, RespHeaders, _} -> - % I would either expect the current origin or a wildcard to be returned - etap:is(proplists:get_value("Access-Control-Allow-Origin", RespHeaders), - undefined, - "check non defined host:port in origin ok"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - -test_preflight_with_port2() -> - Headers = [{"Origin", "http://example.com:5984"}, - {"Access-Control-Request-Method", "GET"}], - case ibrowse:send_req(server(), Headers, options, []) of - {ok, _, RespHeaders, _} -> - % I would either expect the current origin or a wildcard to be returned - etap:is(proplists:get_value("Access-Control-Allow-Origin", RespHeaders), - "http://example.com:5984", - "check host:port in origin ok"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - -test_preflight_with_scheme1(VHost) -> - Headers = [{"Origin", "https://example.com:5984"}, - {"Access-Control-Request-Method", "GET"}] - ++ maybe_append_vhost(VHost), - case ibrowse:send_req(server(), Headers, options, []) of - {ok, _, RespHeaders, _} -> - % I would either expect the current origin or a wildcard to be returned - etap:is(proplists:get_value("Access-Control-Allow-Origin", RespHeaders), - undefined, - "check non defined scheme in origin ok"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - -test_preflight_with_scheme2() -> - Headers = [{"Origin", "https://example.com:5984"}, - {"Access-Control-Request-Method", "GET"}], - case ibrowse:send_req(server(), Headers, options, []) of - {ok, _, RespHeaders, _} -> - % I would either expect the current origin or a wildcard to be returned - etap:is(proplists:get_value("Access-Control-Allow-Origin", RespHeaders), - "https://example.com:5984", - "check scheme in origin ok"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - -test_case_sensitive_mismatch_of_allowed_origins() -> - Headers = [{"Origin", "http://EXAMPLE.COM"}], - Url = server() ++ "etap-test-db", - case ibrowse:send_req(Url, Headers, get, []) of - {ok, _, RespHeaders, _Body} -> - etap:is(proplists:get_value("Access-Control-Allow-Origin", RespHeaders), - undefined, - "db access config case mismatch"); - _ -> - etap:is(false, true, "ibrowse failed") - end. - -maybe_append_vhost(true) -> - [{"Host", "http://example.com"}]; -maybe_append_vhost(Else) -> - []. http://git-wip-us.apache.org/repos/asf/couchdb/blob/0b7b43c9/test/etap/232-csp.t ---------------------------------------------------------------------- diff --git a/test/etap/232-csp.t b/test/etap/232-csp.t deleted file mode 100644 index 6dbce6a..0000000 --- a/test/etap/232-csp.t +++ /dev/null @@ -1,85 +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. - -server() -> - lists:concat([ - "http://127.0.0.1:", - mochiweb_socket_server:get(couch_httpd, port), - "/_utils/" - ]). - - -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() -> - %% launch couchdb - couch_server_sup:start_link(test_util:config_files()), - - % CSP is disabled by default - test_no_csp_headers_server(), - - % Now enable CSP - ok = couch_config:set("csp", "enable", "true", false), - - test_default_header_value(), - - ok = couch_config:set("csp", "header_value", "default-src 'http://example.com';", false), - test_custom_header_value(), - - % Disabled on all other values than true - ok = couch_config:set("csp", "enable", "blerg", false), - test_all_other_values_for_enable(), - - timer:sleep(3000), - couch_server_sup:stop(), - ok. - -test_no_csp_headers_server() -> - Headers = [{"Origin", "http://127.0.0.1"}], - {ok, _, Resp, _} = ibrowse:send_req(server(), Headers, get, []), - etap:is(proplists:get_value("Content-Security-Policy", Resp), - undefined, "No CSP Headers when disabled"). - -test_default_header_value() -> - Headers = [{"Origin", "http://127.0.0.1"}], - {ok, _, Resp, _} = ibrowse:send_req(server(), Headers, get, []), - etap:is(proplists:get_value("Content-Security-Policy", Resp), - "default-src 'self'; img-src 'self'; font-src 'self'; " - "script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline';", - "Default CSP Headers when enabled"). - -test_custom_header_value() -> - Headers = [{"Origin", "http://127.0.0.1"}], - {ok, _, Resp, _} = ibrowse:send_req(server(), Headers, get, []), - etap:is(proplists:get_value("Content-Security-Policy", Resp), - "default-src 'http://example.com';", - "Custom CSP Headers possible"). - -test_all_other_values_for_enable() -> - Headers = [{"Origin", "http://127.0.0.1"}], - {ok, _, Resp, _} = ibrowse:send_req(server(), Headers, get, []), - etap:is(proplists:get_value("Content-Security-Policy", Resp), - undefined, "No CSP Headers when wrong value given").
