You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ch...@apache.org on 2014/08/15 22:24:28 UTC

[01/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Repository: couchdb-couch
Updated Branches:
  refs/heads/1963-eunit-bigcouch df926afac -> 95bfc0360 (forced update)


Port 100-ref-counter.t etap test suite to eunit


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/2795acd0
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/2795acd0
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/2795acd0

Branch: refs/heads/1963-eunit-bigcouch
Commit: 2795acd08615d63665e499397daa54a28ce29985
Parents: 4991988
Author: Alexander Shorin <kx...@apache.org>
Authored: Mon May 26 20:59:45 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:43 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couch_ref_counter_tests.erl | 107 ++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/2795acd0/test/couchdb/couch_ref_counter_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_ref_counter_tests.erl b/test/couchdb/couch_ref_counter_tests.erl
new file mode 100644
index 0000000..b7e97b4
--- /dev/null
+++ b/test/couchdb/couch_ref_counter_tests.erl
@@ -0,0 +1,107 @@
+% 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(couch_ref_counter_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(TIMEOUT, 1000).
+
+
+setup() ->
+    {ok, RefCtr} = couch_ref_counter:start([]),
+    ChildPid = spawn(fun() -> loop() end),
+    {RefCtr, ChildPid}.
+
+teardown({_, ChildPid}) ->
+    erlang:monitor(process, ChildPid),
+    ChildPid ! close,
+    wait().
+
+
+couch_ref_counter_test_() ->
+    {
+        "CouchDB reference counter tests",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_initialize_with_calling_process_as_referrer/1,
+                fun should_ignore_unknown_pid/1,
+                fun should_increment_counter_on_pid_add/1,
+                fun should_not_increase_counter_on_readding_same_pid/1,
+                fun should_drop_ref_for_double_added_pid/1,
+                fun should_decrement_counter_on_pid_drop/1,
+                fun should_add_after_drop/1,
+                fun should_decrement_counter_on_process_exit/1
+
+            ]
+        }
+    }.
+
+
+should_initialize_with_calling_process_as_referrer({RefCtr, _}) ->
+    ?_assertEqual(1, couch_ref_counter:count(RefCtr)).
+
+should_ignore_unknown_pid({RefCtr, ChildPid}) ->
+    ?_assertEqual(ok, couch_ref_counter:drop(RefCtr, ChildPid)).
+
+should_increment_counter_on_pid_add({RefCtr, ChildPid}) ->
+    couch_ref_counter:add(RefCtr, ChildPid),
+    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
+
+should_not_increase_counter_on_readding_same_pid({RefCtr, ChildPid}) ->
+    couch_ref_counter:add(RefCtr, ChildPid),
+    couch_ref_counter:add(RefCtr, ChildPid),
+    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
+
+should_drop_ref_for_double_added_pid({RefCtr, ChildPid}) ->
+    couch_ref_counter:add(RefCtr, ChildPid),
+    couch_ref_counter:add(RefCtr, ChildPid),
+    couch_ref_counter:drop(RefCtr, ChildPid),
+    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
+
+should_decrement_counter_on_pid_drop({RefCtr, ChildPid}) ->
+    couch_ref_counter:add(RefCtr, ChildPid),
+    couch_ref_counter:drop(RefCtr, ChildPid),
+    ?_assertEqual(1, couch_ref_counter:count(RefCtr)).
+
+should_add_after_drop({RefCtr, ChildPid}) ->
+    couch_ref_counter:add(RefCtr, ChildPid),
+    couch_ref_counter:drop(RefCtr, ChildPid),
+    couch_ref_counter:add(RefCtr, ChildPid),
+    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
+
+should_decrement_counter_on_process_exit({RefCtr, ChildPid}) ->
+    ?_assertEqual(1,
+        begin
+            couch_ref_counter:add(RefCtr, ChildPid),
+            erlang:monitor(process, ChildPid),
+            ChildPid ! close,
+            wait(),
+            couch_ref_counter:count(RefCtr)
+        end).
+
+
+loop() ->
+    receive
+        close -> ok
+    end.
+
+wait() ->
+    receive
+        {'DOWN', _, _, _, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw(timeout_error)
+    end.


[33/50] [abbrv] Move files out of test/couchdb into top level test/ folder

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couchdb_update_conflicts_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_update_conflicts_tests.erl b/test/couchdb/couchdb_update_conflicts_tests.erl
deleted file mode 100644
index 7226860..0000000
--- a/test/couchdb/couchdb_update_conflicts_tests.erl
+++ /dev/null
@@ -1,243 +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(couchdb_update_conflicts_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(i2l(I), integer_to_list(I)).
--define(ADMIN_USER, {userctx, #user_ctx{roles=[<<"_admin">>]}}).
--define(DOC_ID, <<"foobar">>).
--define(NUM_CLIENTS, [100, 500, 1000, 2000, 5000, 10000]).
--define(TIMEOUT, 10000).
-
-
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    couch_config:set("couchdb", "delayed_commits", "true", false),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
-setup() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER, overwrite]),
-    Doc = couch_doc:from_json_obj({[{<<"_id">>, ?DOC_ID},
-                                    {<<"value">>, 0}]}),
-    {ok, Rev} = couch_db:update_doc(Db, Doc, []),
-    ok = couch_db:close(Db),
-    RevStr = couch_doc:rev_to_str(Rev),
-    {DbName, RevStr}.
-setup(_) ->
-    setup().
-
-teardown({DbName, _}) ->
-    ok = couch_server:delete(DbName, []),
-    ok.
-teardown(_, {DbName, _RevStr}) ->
-    teardown({DbName, _RevStr}).
-
-
-view_indexes_cleanup_test_() ->
-    {
-        "Update conflicts",
-        {
-            setup,
-            fun start/0, fun stop/1,
-            [
-                concurrent_updates(),
-                couchdb_188()
-            ]
-        }
-    }.
-
-concurrent_updates()->
-    {
-        "Concurrent updates",
-        {
-            foreachx,
-            fun setup/1, fun teardown/2,
-            [{NumClients, fun should_concurrently_update_doc/2}
-             || NumClients <- ?NUM_CLIENTS]
-        }
-    }.
-
-couchdb_188()->
-    {
-        "COUCHDB-188",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [fun should_bulk_create_delete_doc/1]
-        }
-    }.
-
-
-should_concurrently_update_doc(NumClients, {DbName, InitRev})->
-     {?i2l(NumClients) ++ " clients",
-      {inorder,
-       [{"update doc",
-         {timeout, ?TIMEOUT div 1000,
-          ?_test(concurrent_doc_update(NumClients, DbName, InitRev))}},
-        {"ensure in single leaf",
-         ?_test(ensure_in_single_revision_leaf(DbName))}]}}.
-
-should_bulk_create_delete_doc({DbName, InitRev})->
-    ?_test(bulk_delete_create(DbName, InitRev)).
-
-
-concurrent_doc_update(NumClients, DbName, InitRev) ->
-    Clients = lists:map(
-        fun(Value) ->
-            ClientDoc = couch_doc:from_json_obj({[
-                {<<"_id">>, ?DOC_ID},
-                {<<"_rev">>, InitRev},
-                {<<"value">>, Value}
-            ]}),
-            Pid = spawn_client(DbName, ClientDoc),
-            {Value, Pid, erlang:monitor(process, Pid)}
-        end,
-        lists:seq(1, NumClients)),
-
-    lists:foreach(fun({_, Pid, _}) -> Pid ! go end, Clients),
-
-    {NumConflicts, SavedValue} = lists:foldl(
-        fun({Value, Pid, MonRef}, {AccConflicts, AccValue}) ->
-            receive
-                {'DOWN', MonRef, process, Pid, {ok, _NewRev}} ->
-                    {AccConflicts, Value};
-                {'DOWN', MonRef, process, Pid, conflict} ->
-                    {AccConflicts + 1, AccValue};
-                {'DOWN', MonRef, process, Pid, Error} ->
-                    erlang:error({assertion_failed,
-                         [{module, ?MODULE},
-                          {line, ?LINE},
-                          {reason, "Client " ++ ?i2l(Value)
-                                             ++ " got update error: "
-                                             ++ couch_util:to_list(Error)}]})
-            after ?TIMEOUT div 2 ->
-                 erlang:error({assertion_failed,
-                         [{module, ?MODULE},
-                          {line, ?LINE},
-                          {reason, "Timeout waiting for client "
-                                   ++ ?i2l(Value) ++ " to die"}]})
-            end
-        end, {0, nil}, Clients),
-    ?assertEqual(NumClients - 1, NumConflicts),
-
-    {ok, Db} = couch_db:open_int(DbName, []),
-    {ok, Leaves} = couch_db:open_doc_revs(Db, ?DOC_ID, all, []),
-    ok = couch_db:close(Db),
-    ?assertEqual(1, length(Leaves)),
-
-    [{ok, Doc2}] = Leaves,
-    {JsonDoc} = couch_doc:to_json_obj(Doc2, []),
-    ?assertEqual(SavedValue, couch_util:get_value(<<"value">>, JsonDoc)).
-
-ensure_in_single_revision_leaf(DbName) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    {ok, Leaves} = couch_db:open_doc_revs(Db, ?DOC_ID, all, []),
-    ok = couch_db:close(Db),
-    [{ok, Doc}] = Leaves,
-
-    %% FIXME: server restart won't work from test side
-    %% stop(ok),
-    %% start(),
-
-    {ok, Db2} = couch_db:open_int(DbName, []),
-    {ok, Leaves2} = couch_db:open_doc_revs(Db2, ?DOC_ID, all, []),
-    ok = couch_db:close(Db2),
-    ?assertEqual(1, length(Leaves2)),
-
-    [{ok, Doc2}] = Leaves,
-    ?assertEqual(Doc, Doc2).
-    
-bulk_delete_create(DbName, InitRev) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    
-    DeletedDoc = couch_doc:from_json_obj({[
-        {<<"_id">>, ?DOC_ID},
-        {<<"_rev">>, InitRev},
-        {<<"_deleted">>, true}
-    ]}),
-    NewDoc = couch_doc:from_json_obj({[
-        {<<"_id">>, ?DOC_ID},
-        {<<"value">>, 666}
-    ]}),
-
-    {ok, Results} = couch_db:update_docs(Db, [DeletedDoc, NewDoc], []),
-    ok = couch_db:close(Db),
-
-    ?assertEqual(2, length([ok || {ok, _} <- Results])),
-    [{ok, Rev1}, {ok, Rev2}] = Results,
-    
-    {ok, Db2} = couch_db:open_int(DbName, []),
-    {ok, [{ok, Doc1}]} = couch_db:open_doc_revs(
-        Db2, ?DOC_ID, [Rev1], [conflicts, deleted_conflicts]),
-    {ok, [{ok, Doc2}]} = couch_db:open_doc_revs(
-        Db2, ?DOC_ID, [Rev2], [conflicts, deleted_conflicts]),
-    ok = couch_db:close(Db2),
-
-    {Doc1Props} = couch_doc:to_json_obj(Doc1, []),
-    {Doc2Props} = couch_doc:to_json_obj(Doc2, []),
-
-    %% Document was deleted
-    ?assert(couch_util:get_value(<<"_deleted">>, Doc1Props)),
-    %% New document not flagged as deleted
-    ?assertEqual(undefined, couch_util:get_value(<<"_deleted">>,
-                                                 Doc2Props)),
-    %% New leaf revision has the right value
-    ?assertEqual(666, couch_util:get_value(<<"value">>,
-                                           Doc2Props)),
-    %% Deleted document has no conflicts
-    ?assertEqual(undefined, couch_util:get_value(<<"_conflicts">>,
-                                                 Doc1Props)),
-    %% Deleted document has no deleted conflicts
-    ?assertEqual(undefined, couch_util:get_value(<<"_deleted_conflicts">>,
-                                                 Doc1Props)),
-    %% New leaf revision doesn't have conflicts
-    ?assertEqual(undefined, couch_util:get_value(<<"_conflicts">>,
-                                                 Doc1Props)),
-    %% New leaf revision doesn't have deleted conflicts
-    ?assertEqual(undefined, couch_util:get_value(<<"_deleted_conflicts">>,
-                                                 Doc1Props)),
-
-    %% Deleted revision has position 2
-    ?assertEqual(2, element(1, Rev1)),
-    %% New leaf revision has position 1
-    ?assertEqual(1, element(1, Rev2)).
-
-
-spawn_client(DbName, Doc) ->
-    spawn(fun() ->
-        {ok, Db} = couch_db:open_int(DbName, []),
-        receive
-            go -> ok
-        end,
-        erlang:yield(),
-        Result = try
-            couch_db:update_doc(Db, Doc, [])
-        catch _:Error ->
-            Error
-        end,
-        ok = couch_db:close(Db),
-        exit(Result)
-    end).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couchdb_vhosts_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_vhosts_tests.erl b/test/couchdb/couchdb_vhosts_tests.erl
deleted file mode 100644
index 94b1957..0000000
--- a/test/couchdb/couchdb_vhosts_tests.erl
+++ /dev/null
@@ -1,441 +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(couchdb_vhosts_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
--define(TIMEOUT, 1000).
--define(iofmt(S, A), lists:flatten(io_lib:format(S, A))).
-
-
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
-setup() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
-    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),
-    couch_db:close(Db),
-
-    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
-    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
-    Url = "http://" ++ Addr ++ ":" ++ Port,
-    {Url, ?b2l(DbName)}.
-
-setup_oauth() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
-
-    couch_config:set("couch_httpd_auth", "authentication_db",
-                     ?b2l(?tempdb()), false),
-    couch_config:set("oauth_token_users", "otoksec1", "joe", false),
-    couch_config:set("oauth_consumer_secrets", "consec1", "foo", false),
-    couch_config:set("oauth_token_secrets", "otoksec1", "foobar", false),
-    couch_config:set("couch_httpd_auth", "require_valid_user", "true", false),
-
-    ok = couch_config:set(
-        "vhosts", "oauth-example.com",
-        "/" ++ ?b2l(DbName) ++ "/_design/test/_rewrite/foobar", false),
-
-    DDoc = couch_doc:from_json_obj({[
-        {<<"_id">>, <<"_design/test">>},
-        {<<"language">>, <<"javascript">>},
-        {<<"rewrites">>, [
-            {[
-                {<<"from">>, <<"foobar">>},
-                {<<"to">>, <<"_info">>}
-            ]}
-        ]}
-    ]}),
-    {ok, _} = couch_db:update_doc(Db, DDoc, []),
-
-    couch_db:ensure_full_commit(Db),
-    couch_db:close(Db),
-
-    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
-    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
-    Url = "http://" ++ Addr ++ ":" ++ Port,
-    {Url, ?b2l(DbName)}.
-
-teardown({_, DbName}) ->
-    ok = couch_server:delete(?l2b(DbName), []),
-    ok.
-
-
-vhosts_test_() ->
-    {
-        "Virtual Hosts rewrite tests",
-        {
-            setup,
-            fun start/0, fun stop/1,
-            {
-                foreach,
-                fun setup/0, fun teardown/1,
-                [
-                    fun should_return_database_info/1,
-                    fun should_return_revs_info/1,
-                    fun should_serve_utils_for_vhost/1,
-                    fun should_return_virtual_request_path_field_in_request/1,
-                    fun should_return_real_request_path_field_in_request/1,
-                    fun should_match_wildcard_vhost/1,
-                    fun should_return_db_info_for_wildcard_vhost_for_custom_db/1,
-                    fun should_replace_rewrite_variables_for_db_and_doc/1,
-                    fun should_return_db_info_for_vhost_with_resource/1,
-                    fun should_return_revs_info_for_vhost_with_resource/1,
-                    fun should_return_db_info_for_vhost_with_wildcard_resource/1,
-                    fun should_return_path_for_vhost_with_wildcard_host/1
-                ]
-            }
-        }
-    }.
-
-oauth_test_() ->
-    {
-        "Virtual Hosts OAuth tests",
-        {
-            setup,
-            fun start/0, fun stop/1,
-            {
-                foreach,
-                fun setup_oauth/0, fun teardown/1,
-                [
-                    fun should_require_auth/1,
-                    fun should_succeed_oauth/1,
-                    fun should_fail_oauth_with_wrong_credentials/1
-                ]
-            }
-        }
-    }.
-
-
-should_return_database_info({Url, DbName}) ->
-    ?_test(begin
-        ok = couch_config:set("vhosts", "example.com", "/" ++ DbName, false),
-        case test_request:get(Url, [], [{host_header, "example.com"}]) of
-            {ok, _, _, Body} ->
-                {JsonBody} = ejson:decode(Body),
-                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_return_revs_info({Url, DbName}) ->
-    ?_test(begin
-        ok = couch_config:set("vhosts", "example.com", "/" ++ DbName, false),
-        case test_request:get(Url ++ "/doc1?revs_info=true", [],
-                              [{host_header, "example.com"}]) of
-            {ok, _, _, Body} ->
-                {JsonBody} = ejson:decode(Body),
-                ?assert(proplists:is_defined(<<"_revs_info">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_serve_utils_for_vhost({Url, DbName}) ->
-    ?_test(begin
-        ok = couch_config:set("vhosts", "example.com", "/" ++ DbName, false),
-        case test_request:get(Url ++ "/_utils/index.html", [],
-                              [{host_header, "example.com"}]) of
-            {ok, _, _, Body} ->
-                ?assertMatch(<<"<!DOCTYPE html>", _/binary>>, Body);
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_return_virtual_request_path_field_in_request({Url, DbName}) ->
-    ?_test(begin
-        ok = couch_config:set("vhosts", "example1.com",
-                              "/" ++ DbName ++ "/_design/doc1/_rewrite/",
-                              false),
-        case test_request:get(Url, [], [{host_header, "example1.com"}]) of
-            {ok, _, _, Body} ->
-                {Json} = ejson:decode(Body),
-                ?assertEqual(<<"/">>,
-                             proplists:get_value(<<"requested_path">>, Json));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_return_real_request_path_field_in_request({Url, DbName}) ->
-    ?_test(begin
-        ok = couch_config:set("vhosts", "example1.com",
-                              "/" ++ DbName ++ "/_design/doc1/_rewrite/",
-                              false),
-        case test_request:get(Url, [], [{host_header, "example1.com"}]) of
-            {ok, _, _, Body} ->
-                {Json} = ejson:decode(Body),
-                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
-                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_match_wildcard_vhost({Url, DbName}) ->
-    ?_test(begin
-        ok = couch_config:set("vhosts", "*.example.com",
-                              "/" ++ DbName ++ "/_design/doc1/_rewrite", false),
-        case test_request:get(Url, [], [{host_header, "test.example.com"}]) of
-            {ok, _, _, Body} ->
-                {Json} = ejson:decode(Body),
-                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
-                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_return_db_info_for_wildcard_vhost_for_custom_db({Url, DbName}) ->
-    ?_test(begin
-        ok = couch_config:set("vhosts", ":dbname.example1.com",
-                              "/:dbname", false),
-        Host = DbName ++ ".example1.com",
-        case test_request:get(Url, [], [{host_header, Host}]) of
-            {ok, _, _, Body} ->
-                {JsonBody} = ejson:decode(Body),
-                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_replace_rewrite_variables_for_db_and_doc({Url, DbName}) ->
-    ?_test(begin
-        ok = couch_config:set("vhosts",":appname.:dbname.example1.com",
-                              "/:dbname/_design/:appname/_rewrite/", false),
-        Host = "doc1." ++ DbName ++ ".example1.com",
-        case test_request:get(Url, [], [{host_header, Host}]) of
-            {ok, _, _, Body} ->
-                {Json} = ejson:decode(Body),
-                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
-                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_return_db_info_for_vhost_with_resource({Url, DbName}) ->
-    ?_test(begin
-        ok = couch_config:set("vhosts",
-                              "example.com/test", "/" ++ DbName, false),
-        ReqUrl = Url ++ "/test",
-        case test_request:get(ReqUrl, [], [{host_header, "example.com"}]) of
-            {ok, _, _, Body} ->
-                {JsonBody} = ejson:decode(Body),
-                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-
-should_return_revs_info_for_vhost_with_resource({Url, DbName}) ->
-    ?_test(begin
-        ok = couch_config:set("vhosts",
-                              "example.com/test", "/" ++ DbName, false),
-        ReqUrl = Url ++ "/test/doc1?revs_info=true",
-        case test_request:get(ReqUrl, [], [{host_header, "example.com"}]) of
-            {ok, _, _, Body} ->
-                {JsonBody} = ejson:decode(Body),
-                ?assert(proplists:is_defined(<<"_revs_info">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_return_db_info_for_vhost_with_wildcard_resource({Url, DbName}) ->
-    ?_test(begin
-        ok = couch_config:set("vhosts", "*.example2.com/test", "/*", false),
-        ReqUrl = Url ++ "/test",
-        Host = DbName ++ ".example2.com",
-        case test_request:get(ReqUrl, [], [{host_header, Host}]) of
-            {ok, _, _, Body} ->
-                {JsonBody} = ejson:decode(Body),
-                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_return_path_for_vhost_with_wildcard_host({Url, DbName}) ->
-    ?_test(begin
-        ok = couch_config:set("vhosts", "*/test1",
-                              "/" ++ DbName ++ "/_design/doc1/_show/test",
-                              false),
-        case test_request:get(Url ++ "/test1") of
-            {ok, _, _, Body} ->
-                {Json} = ejson:decode(Body),
-                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
-                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_require_auth({Url, _}) ->
-    ?_test(begin
-        case test_request:get(Url, [], [{host_header, "oauth-example.com"}]) of
-            {ok, Code, _, Body} ->
-                ?assertEqual(401, Code),
-                {JsonBody} = ejson:decode(Body),
-                ?assertEqual(<<"unauthorized">>,
-                             couch_util:get_value(<<"error">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_succeed_oauth({Url, _}) ->
-    ?_test(begin
-        AuthDbName = couch_config:get("couch_httpd_auth", "authentication_db"),
-        JoeDoc = couch_doc:from_json_obj({[
-            {<<"_id">>, <<"org.couchdb.user:joe">>},
-            {<<"type">>, <<"user">>},
-            {<<"name">>, <<"joe">>},
-            {<<"roles">>, []},
-            {<<"password_sha">>, <<"fe95df1ca59a9b567bdca5cbaf8412abd6e06121">>},
-            {<<"salt">>, <<"4e170ffeb6f34daecfd814dfb4001a73">>}
-        ]}),
-        {ok, AuthDb} = couch_db:open_int(?l2b(AuthDbName), [?ADMIN_USER]),
-        {ok, _} = couch_db:update_doc(AuthDb, JoeDoc, [?ADMIN_USER]),
-
-        Host = "oauth-example.com",
-        Consumer = {"consec1", "foo", hmac_sha1},
-        SignedParams = oauth:sign(
-            "GET", "http://" ++ Host ++ "/", [], Consumer, "otoksec1", "foobar"),
-        OAuthUrl = oauth:uri(Url, SignedParams),
-
-        case test_request:get(OAuthUrl, [], [{host_header, Host}]) of
-            {ok, Code, _, Body} ->
-                ?assertEqual(200, Code),
-                {JsonBody} = ejson:decode(Body),
-                ?assertEqual(<<"test">>,
-                             couch_util:get_value(<<"name">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_fail_oauth_with_wrong_credentials({Url, _}) ->
-    ?_test(begin
-        AuthDbName = couch_config:get("couch_httpd_auth", "authentication_db"),
-        JoeDoc = couch_doc:from_json_obj({[
-            {<<"_id">>, <<"org.couchdb.user:joe">>},
-            {<<"type">>, <<"user">>},
-            {<<"name">>, <<"joe">>},
-            {<<"roles">>, []},
-            {<<"password_sha">>, <<"fe95df1ca59a9b567bdca5cbaf8412abd6e06121">>},
-            {<<"salt">>, <<"4e170ffeb6f34daecfd814dfb4001a73">>}
-        ]}),
-        {ok, AuthDb} = couch_db:open_int(?l2b(AuthDbName), [?ADMIN_USER]),
-        {ok, _} = couch_db:update_doc(AuthDb, JoeDoc, [?ADMIN_USER]),
-
-        Host = "oauth-example.com",
-        Consumer = {"consec1", "bad_secret", hmac_sha1},
-        SignedParams = oauth:sign(
-            "GET", "http://" ++ Host ++ "/", [], Consumer, "otoksec1", "foobar"),
-        OAuthUrl = oauth:uri(Url, SignedParams),
-
-        case test_request:get(OAuthUrl, [], [{host_header, Host}]) of
-            {ok, Code, _, Body} ->
-                ?assertEqual(401, Code),
-                {JsonBody} = ejson:decode(Body),
-                ?assertEqual(<<"unauthorized">>,
-                             couch_util:get_value(<<"error">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couchdb_views_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_views_tests.erl b/test/couchdb/couchdb_views_tests.erl
deleted file mode 100644
index 6d81f32..0000000
--- a/test/couchdb/couchdb_views_tests.erl
+++ /dev/null
@@ -1,669 +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(couchdb_views_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
--include_lib("couch_mrview/include/couch_mrview.hrl").
-
--define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
--define(DELAY, 100).
--define(TIMEOUT, 1000).
-
-
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
-setup() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
-    ok = couch_db:close(Db),
-    FooRev = create_design_doc(DbName, <<"_design/foo">>, <<"bar">>),
-    query_view(DbName, "foo", "bar"),
-    BooRev = create_design_doc(DbName, <<"_design/boo">>, <<"baz">>),
-    query_view(DbName, "boo", "baz"),
-    {DbName, {FooRev, BooRev}}.
-
-setup_with_docs() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
-    ok = couch_db:close(Db),
-    create_docs(DbName),
-    create_design_doc(DbName, <<"_design/foo">>, <<"bar">>),
-    DbName.
-
-teardown({DbName, _}) ->
-    teardown(DbName);
-teardown(DbName) when is_binary(DbName) ->
-    couch_server:delete(DbName, [?ADMIN_USER]),
-    ok.
-
-
-view_indexes_cleanup_test_() ->
-    {
-        "View indexes cleanup",
-        {
-            setup,
-            fun start/0, fun stop/1,
-            {
-                foreach,
-                fun setup/0, fun teardown/1,
-                [
-                    fun should_have_two_indexes_alive_before_deletion/1,
-                    fun should_cleanup_index_file_after_ddoc_deletion/1,
-                    fun should_cleanup_all_index_files/1
-                ]
-            }
-        }
-    }.
-
-view_group_db_leaks_test_() ->
-    {
-        "View group db leaks",
-        {
-            setup,
-            fun start/0, fun stop/1,
-            {
-                foreach,
-                fun setup_with_docs/0, fun teardown/1,
-                [
-                    fun couchdb_1138/1,
-                    fun couchdb_1309/1
-                ]
-            }
-        }
-    }.
-
-view_group_shutdown_test_() ->
-    {
-        "View group shutdown",
-        {
-            setup,
-            fun start/0, fun stop/1,
-            [couchdb_1283()]
-        }
-    }.
-
-
-should_not_remember_docs_in_index_after_backup_restore_test() ->
-    %% COUCHDB-640
-    start(),
-    DbName = setup_with_docs(),
-
-    ok = backup_db_file(DbName),
-    create_doc(DbName, "doc666"),
-
-    Rows0 = query_view(DbName, "foo", "bar"),
-    ?assert(has_doc("doc1", Rows0)),
-    ?assert(has_doc("doc2", Rows0)),
-    ?assert(has_doc("doc3", Rows0)),
-    ?assert(has_doc("doc666", Rows0)),
-
-    restore_backup_db_file(DbName),
-
-    Rows1 = query_view(DbName, "foo", "bar"),
-    ?assert(has_doc("doc1", Rows1)),
-    ?assert(has_doc("doc2", Rows1)),
-    ?assert(has_doc("doc3", Rows1)),
-    ?assertNot(has_doc("doc666", Rows1)),
-
-    teardown(DbName),
-    stop(whereis(couch_server_sup)).
-
-
-should_upgrade_legacy_view_files_test() ->
-    start(),
-
-    ok = couch_config:set("query_server_config", "commit_freq", "0", false),
-
-    DbName = <<"test">>,
-    DbFileName = "test.couch",
-    DbFilePath = filename:join([?FIXTURESDIR, DbFileName]),
-    OldViewName = "3b835456c235b1827e012e25666152f3.view",
-    FixtureViewFilePath = filename:join([?FIXTURESDIR, OldViewName]),
-    NewViewName = "a1c5929f912aca32f13446122cc6ce50.view",
-
-    DbDir = couch_config:get("couchdb", "database_dir"),
-    ViewDir = couch_config:get("couchdb", "view_index_dir"),
-    OldViewFilePath = filename:join([ViewDir, ".test_design", OldViewName]),
-    NewViewFilePath = filename:join([ViewDir, ".test_design", "mrview",
-                                     NewViewName]),
-
-    % cleanup
-    Files = [
-        filename:join([DbDir, DbFileName]),
-        OldViewFilePath,
-        NewViewFilePath
-    ],
-    lists:foreach(fun(File) -> file:delete(File) end, Files),
-
-    % copy old db file into db dir
-    {ok, _} = file:copy(DbFilePath, filename:join([DbDir, DbFileName])),
-
-    % copy old view file into view dir
-    ok = filelib:ensure_dir(filename:join([ViewDir, ".test_design"])),
-    {ok, _} = file:copy(FixtureViewFilePath, OldViewFilePath),
-
-    % ensure old header
-    OldHeader = read_header(OldViewFilePath),
-    ?assertMatch(#index_header{}, OldHeader),
-
-    % query view for expected results
-    Rows0 = query_view(DbName, "test", "test"),
-    ?assertEqual(2, length(Rows0)),
-
-    % ensure old file gone
-    ?assertNot(filelib:is_regular(OldViewFilePath)),
-
-    % add doc to trigger update
-    DocUrl = db_url(DbName) ++ "/boo",
-    {ok, _, _, _} = test_request:put(
-        DocUrl, [{"Content-Type", "application/json"}], <<"{\"a\":3}">>),
-
-    % query view for expected results
-    Rows1 = query_view(DbName, "test", "test"),
-    ?assertEqual(3, length(Rows1)),
-
-    % ensure new header
-    timer:sleep(2000),  % have to wait for awhile to upgrade the index
-    NewHeader = read_header(NewViewFilePath),
-    ?assertMatch(#mrheader{}, NewHeader),
-
-    teardown(DbName),
-    stop(whereis(couch_server_sup)).
-
-
-should_have_two_indexes_alive_before_deletion({DbName, _}) ->
-    view_cleanup(DbName),
-    ?_assertEqual(2, count_index_files(DbName)).
-
-should_cleanup_index_file_after_ddoc_deletion({DbName, {FooRev, _}}) ->
-    delete_design_doc(DbName, <<"_design/foo">>, FooRev),
-    view_cleanup(DbName),
-    ?_assertEqual(1, count_index_files(DbName)).
-
-should_cleanup_all_index_files({DbName, {FooRev, BooRev}})->
-    delete_design_doc(DbName, <<"_design/foo">>, FooRev),
-    delete_design_doc(DbName, <<"_design/boo">>, BooRev),
-    view_cleanup(DbName),
-    ?_assertEqual(0, count_index_files(DbName)).
-
-couchdb_1138(DbName) ->
-    ?_test(begin
-        {ok, IndexerPid} = couch_index_server:get_index(
-            couch_mrview_index, DbName, <<"_design/foo">>),
-        ?assert(is_pid(IndexerPid)),
-        ?assert(is_process_alive(IndexerPid)),
-        ?assertEqual(2, count_db_refs(DbName)),
-
-        Rows0 = query_view(DbName, "foo", "bar"),
-        ?assertEqual(3, length(Rows0)),
-        ?assertEqual(2, count_db_refs(DbName)),
-        ?assert(is_process_alive(IndexerPid)),
-
-        create_doc(DbName, "doc1000"),
-        Rows1 = query_view(DbName, "foo", "bar"),
-        ?assertEqual(4, length(Rows1)),
-        ?assertEqual(2, count_db_refs(DbName)),
-        ?assert(is_process_alive(IndexerPid)),
-
-        Ref1 = get_db_ref_counter(DbName),
-        compact_db(DbName),
-        Ref2 = get_db_ref_counter(DbName),
-        ?assertEqual(2, couch_ref_counter:count(Ref2)),
-        ?assertNotEqual(Ref2, Ref1),
-        ?assertNot(is_process_alive(Ref1)),
-        ?assert(is_process_alive(IndexerPid)),
-
-        compact_view_group(DbName, "foo"),
-        ?assertEqual(2, count_db_refs(DbName)),
-        Ref3 = get_db_ref_counter(DbName),
-        ?assertEqual(Ref3, Ref2),
-        ?assert(is_process_alive(IndexerPid)),
-
-        create_doc(DbName, "doc1001"),
-        Rows2 = query_view(DbName, "foo", "bar"),
-        ?assertEqual(5, length(Rows2)),
-        ?assertEqual(2, count_db_refs(DbName)),
-        ?assert(is_process_alive(IndexerPid))
-    end).
-
-couchdb_1309(DbName) ->
-    ?_test(begin
-        {ok, IndexerPid} = couch_index_server:get_index(
-            couch_mrview_index, DbName, <<"_design/foo">>),
-        ?assert(is_pid(IndexerPid)),
-        ?assert(is_process_alive(IndexerPid)),
-        ?assertEqual(2, count_db_refs(DbName)),
-
-        create_doc(DbName, "doc1001"),
-        Rows0 = query_view(DbName, "foo", "bar"),
-        check_rows_value(Rows0, null),
-        ?assertEqual(4, length(Rows0)),
-        ?assertEqual(2, count_db_refs(DbName)),
-        ?assert(is_process_alive(IndexerPid)),
-
-        update_design_doc(DbName,  <<"_design/foo">>, <<"bar">>),
-        {ok, NewIndexerPid} = couch_index_server:get_index(
-            couch_mrview_index, DbName, <<"_design/foo">>),
-        ?assert(is_pid(NewIndexerPid)),
-        ?assert(is_process_alive(NewIndexerPid)),
-        ?assertNotEqual(IndexerPid, NewIndexerPid),
-        ?assertEqual(2, count_db_refs(DbName)),
-
-        Rows1 = query_view(DbName, "foo", "bar", ok),
-        ?assertEqual(0, length(Rows1)),
-        Rows2 = query_view(DbName, "foo", "bar"),
-        check_rows_value(Rows2, 1),
-        ?assertEqual(4, length(Rows2)),
-
-        MonRef0 = erlang:monitor(process, IndexerPid),
-        receive
-            {'DOWN', MonRef0, _, _, _} ->
-                ok
-        after ?TIMEOUT ->
-            erlang:error(
-                {assertion_failed,
-                 [{module, ?MODULE}, {line, ?LINE},
-                  {reason, "old view group is not dead after ddoc update"}]})
-        end,
-
-        MonRef1 = erlang:monitor(process, NewIndexerPid),
-        ok = couch_server:delete(DbName, [?ADMIN_USER]),
-        receive
-            {'DOWN', MonRef1, _, _, _} ->
-                ok
-        after ?TIMEOUT ->
-            erlang:error(
-                {assertion_failed,
-                 [{module, ?MODULE}, {line, ?LINE},
-                  {reason, "new view group did not die after DB deletion"}]})
-        end
-    end).
-
-couchdb_1283() ->
-    ?_test(begin
-        ok = couch_config:set("couchdb", "max_dbs_open", "3", false),
-        ok = couch_config:set("couchdb", "delayed_commits", "false", false),
-
-        {ok, MDb1} = couch_db:create(?tempdb(), [?ADMIN_USER]),
-        DDoc = couch_doc:from_json_obj({[
-            {<<"_id">>, <<"_design/foo">>},
-            {<<"language">>, <<"javascript">>},
-            {<<"views">>, {[
-                {<<"foo">>, {[
-                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
-                ]}},
-                {<<"foo2">>, {[
-                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
-                ]}},
-                {<<"foo3">>, {[
-                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
-                ]}},
-                {<<"foo4">>, {[
-                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
-                ]}},
-                {<<"foo5">>, {[
-                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
-                ]}}
-            ]}}
-        ]}),
-        {ok, _} = couch_db:update_doc(MDb1, DDoc, []),
-        ok = populate_db(MDb1, 100, 100),
-        query_view(MDb1#db.name, "foo", "foo"),
-        ok = couch_db:close(MDb1),
-
-        {ok, Db1} = couch_db:create(?tempdb(), [?ADMIN_USER]),
-        ok = couch_db:close(Db1),
-        {ok, Db2} = couch_db:create(?tempdb(), [?ADMIN_USER]),
-        ok = couch_db:close(Db2),
-        {ok, Db3} = couch_db:create(?tempdb(), [?ADMIN_USER]),
-        ok = couch_db:close(Db3),
-
-        Writer1 = spawn_writer(Db1#db.name),
-        Writer2 = spawn_writer(Db2#db.name),
-
-        ?assert(is_process_alive(Writer1)),
-        ?assert(is_process_alive(Writer2)),
-
-        ?assertEqual(ok, get_writer_status(Writer1)),
-        ?assertEqual(ok, get_writer_status(Writer2)),
-
-        {ok, MonRef} = couch_mrview:compact(MDb1#db.name, <<"_design/foo">>,
-                                            [monitor]),
-
-        Writer3 = spawn_writer(Db3#db.name),
-        ?assert(is_process_alive(Writer3)),
-        ?assertEqual({error, all_dbs_active}, get_writer_status(Writer3)),
-
-        ?assert(is_process_alive(Writer1)),
-        ?assert(is_process_alive(Writer2)),
-        ?assert(is_process_alive(Writer3)),
-
-        receive
-            {'DOWN', MonRef, process, _, Reason} ->
-                ?assertEqual(normal, Reason)
-        after ?TIMEOUT ->
-            erlang:error(
-                {assertion_failed,
-                 [{module, ?MODULE}, {line, ?LINE},
-                  {reason, "Failure compacting view group"}]})
-        end,
-
-        ?assertEqual(ok, writer_try_again(Writer3)),
-        ?assertEqual(ok, get_writer_status(Writer3)),
-
-        ?assert(is_process_alive(Writer1)),
-        ?assert(is_process_alive(Writer2)),
-        ?assert(is_process_alive(Writer3)),
-
-        ?assertEqual(ok, stop_writer(Writer1)),
-        ?assertEqual(ok, stop_writer(Writer2)),
-        ?assertEqual(ok, stop_writer(Writer3))
-    end).
-
-create_doc(DbName, DocId) when is_list(DocId) ->
-    create_doc(DbName, ?l2b(DocId));
-create_doc(DbName, DocId) when is_binary(DocId) ->
-    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
-    Doc666 = couch_doc:from_json_obj({[
-        {<<"_id">>, DocId},
-        {<<"value">>, 999}
-    ]}),
-    {ok, _} = couch_db:update_docs(Db, [Doc666]),
-    couch_db:ensure_full_commit(Db),
-    couch_db:close(Db).
-
-create_docs(DbName) ->
-    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
-    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).
-
-populate_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_db(Db, BatchSize, N - length(Docs));
-populate_db(_Db, _, _) ->
-    ok.
-
-create_design_doc(DbName, DDName, ViewName) ->
-    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
-    DDoc = couch_doc:from_json_obj({[
-        {<<"_id">>, DDName},
-        {<<"language">>, <<"javascript">>},
-        {<<"views">>, {[
-            {ViewName, {[
-                {<<"map">>, <<"function(doc) { emit(doc.value, null); }">>}
-            ]}}
-        ]}}
-    ]}),
-    {ok, Rev} = couch_db:update_doc(Db, DDoc, []),
-    couch_db:ensure_full_commit(Db),
-    couch_db:close(Db),
-    Rev.
-
-update_design_doc(DbName, DDName, ViewName) ->
-    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
-    {ok, Doc} = couch_db:open_doc(Db, DDName, [?ADMIN_USER]),
-    {Props} = couch_doc:to_json_obj(Doc, []),
-    Rev = couch_util:get_value(<<"_rev">>, Props),
-    DDoc = couch_doc:from_json_obj({[
-        {<<"_id">>, DDName},
-        {<<"_rev">>, Rev},
-        {<<"language">>, <<"javascript">>},
-        {<<"views">>, {[
-            {ViewName, {[
-                {<<"map">>, <<"function(doc) { emit(doc.value, 1); }">>}
-            ]}}
-        ]}}
-    ]}),
-    {ok, NewRev} = couch_db:update_doc(Db, DDoc, [?ADMIN_USER]),
-    couch_db:ensure_full_commit(Db),
-    couch_db:close(Db),
-    NewRev.
-
-delete_design_doc(DbName, DDName, Rev) ->
-    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
-    DDoc = couch_doc:from_json_obj({[
-        {<<"_id">>, DDName},
-        {<<"_rev">>, couch_doc:rev_to_str(Rev)},
-        {<<"_deleted">>, true}
-    ]}),
-    {ok, _} = couch_db:update_doc(Db, DDoc, [Rev]),
-    couch_db:close(Db).
-
-db_url(DbName) ->
-    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
-    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
-    "http://" ++ Addr ++ ":" ++ Port ++ "/" ++ ?b2l(DbName).
-
-query_view(DbName, DDoc, View) ->
-    query_view(DbName, DDoc, View, false).
-
-query_view(DbName, DDoc, View, Stale) ->
-    {ok, Code, _Headers, Body} = test_request:get(
-        db_url(DbName) ++ "/_design/" ++ DDoc ++ "/_view/" ++ View
-        ++ case Stale of
-               false -> [];
-               _ -> "?stale=" ++ atom_to_list(Stale)
-           end),
-    ?assertEqual(200, Code),
-    {Props} = ejson:decode(Body),
-    couch_util:get_value(<<"rows">>, Props, []).
-
-check_rows_value(Rows, Value) ->
-    lists:foreach(
-        fun({Row}) ->
-            ?assertEqual(Value, couch_util:get_value(<<"value">>, Row))
-        end, Rows).
-
-view_cleanup(DbName) ->
-    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
-    couch_mrview:cleanup(Db),
-    couch_db:close(Db).
-
-get_db_ref_counter(DbName) ->
-    {ok, #db{fd_ref_counter = Ref} = Db} = couch_db:open_int(DbName, []),
-    ok = couch_db:close(Db),
-    Ref.
-
-count_db_refs(DbName) ->
-    Ref = get_db_ref_counter(DbName),
-    % have to sleep a bit to let couchdb cleanup all refs and leave only
-    % active ones. otherwise the related tests will randomly fail due to
-    % count number mismatch
-    timer:sleep(200),
-    couch_ref_counter:count(Ref).
-
-count_index_files(DbName) ->
-    % call server to fetch the index files
-    RootDir = couch_config:get("couchdb", "view_index_dir"),
-    length(filelib:wildcard(RootDir ++ "/." ++
-        binary_to_list(DbName) ++ "_design"++"/mrview/*")).
-
-has_doc(DocId1, Rows) ->
-    DocId = iolist_to_binary(DocId1),
-    lists:any(fun({R}) -> lists:member({<<"id">>, DocId}, R) end, Rows).
-
-backup_db_file(DbName) ->
-    DbDir = couch_config:get("couchdb", "database_dir"),
-    DbFile = filename:join([DbDir, ?b2l(DbName) ++ ".couch"]),
-    {ok, _} = file:copy(DbFile, DbFile ++ ".backup"),
-    ok.
-
-restore_backup_db_file(DbName) ->
-    DbDir = couch_config:get("couchdb", "database_dir"),
-    stop(whereis(couch_server_sup)),
-    DbFile = filename:join([DbDir, ?b2l(DbName) ++ ".couch"]),
-    ok = file:delete(DbFile),
-    ok = file:rename(DbFile ++ ".backup", DbFile),
-    start(),
-    ok.
-
-compact_db(DbName) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    {ok, _} = couch_db:start_compact(Db),
-    ok = couch_db:close(Db),
-    wait_db_compact_done(DbName, 10).
-
-wait_db_compact_done(_DbName, 0) ->
-    erlang:error({assertion_failed,
-                  [{module, ?MODULE},
-                   {line, ?LINE},
-                   {reason, "DB compaction failed to finish"}]});
-wait_db_compact_done(DbName, N) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    ok = couch_db:close(Db),
-    case is_pid(Db#db.compactor_pid) of
-    false ->
-        ok;
-    true ->
-        ok = timer:sleep(?DELAY),
-        wait_db_compact_done(DbName, N - 1)
-    end.
-
-compact_view_group(DbName, DDocId) when is_list(DDocId) ->
-    compact_view_group(DbName, ?l2b("_design/" ++ DDocId));
-compact_view_group(DbName, DDocId) when is_binary(DDocId) ->
-    ok = couch_mrview:compact(DbName, DDocId),
-    wait_view_compact_done(DbName, DDocId, 10).
-
-wait_view_compact_done(_DbName, _DDocId, 0) ->
-    erlang:error({assertion_failed,
-                  [{module, ?MODULE},
-                   {line, ?LINE},
-                   {reason, "DB compaction failed to finish"}]});
-wait_view_compact_done(DbName, DDocId, N) ->
-    {ok, Code, _Headers, Body} = test_request:get(
-        db_url(DbName) ++ "/" ++ ?b2l(DDocId) ++ "/_info"),
-    ?assertEqual(200, Code),
-    {Info} = ejson: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(?DELAY),
-            wait_view_compact_done(DbName, DDocId, N - 1)
-    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 ?TIMEOUT ->
-        timeout
-    end.
-
-writer_try_again(Writer) ->
-    Ref = make_ref(),
-    Writer ! {try_again, Ref},
-    receive
-        {ok, Ref} ->
-            ok
-    after ?TIMEOUT ->
-        timeout
-    end.
-
-stop_writer(Writer) ->
-    Ref = make_ref(),
-    Writer ! {stop, Ref},
-    receive
-        {ok, Ref} ->
-            ok
-    after ?TIMEOUT ->
-        erlang:error({assertion_failed,
-                      [{module, ?MODULE},
-                       {line, ?LINE},
-                       {reason, "Timeout on stopping process"}]})
-    end.
-
-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.
-
-read_header(File) ->
-    {ok, Fd} = couch_file:open(File),
-    {ok, {_Sig, Header}} = couch_file:read_header(Fd),
-    couch_file:close(Fd),
-    Header.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/fixtures/3b835456c235b1827e012e25666152f3.view
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/3b835456c235b1827e012e25666152f3.view b/test/couchdb/fixtures/3b835456c235b1827e012e25666152f3.view
deleted file mode 100644
index 9c67648..0000000
Binary files a/test/couchdb/fixtures/3b835456c235b1827e012e25666152f3.view and /dev/null differ

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/fixtures/couch_config_tests_1.ini
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/couch_config_tests_1.ini b/test/couchdb/fixtures/couch_config_tests_1.ini
deleted file mode 100644
index 55451da..0000000
--- a/test/couchdb/fixtures/couch_config_tests_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

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/fixtures/couch_config_tests_2.ini
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/couch_config_tests_2.ini b/test/couchdb/fixtures/couch_config_tests_2.ini
deleted file mode 100644
index 5f46357..0000000
--- a/test/couchdb/fixtures/couch_config_tests_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

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/fixtures/couch_stats_aggregates.cfg
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/couch_stats_aggregates.cfg b/test/couchdb/fixtures/couch_stats_aggregates.cfg
deleted file mode 100644
index 30e475d..0000000
--- a/test/couchdb/fixtures/couch_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"}.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/fixtures/couch_stats_aggregates.ini
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/couch_stats_aggregates.ini b/test/couchdb/fixtures/couch_stats_aggregates.ini
deleted file mode 100644
index cc5cd21..0000000
--- a/test/couchdb/fixtures/couch_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]

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/fixtures/logo.png
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/logo.png b/test/couchdb/fixtures/logo.png
deleted file mode 100644
index d21ac02..0000000
Binary files a/test/couchdb/fixtures/logo.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/fixtures/os_daemon_bad_perm.sh
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/os_daemon_bad_perm.sh b/test/couchdb/fixtures/os_daemon_bad_perm.sh
deleted file mode 100644
index 345c8b4..0000000
--- a/test/couchdb/fixtures/os_daemon_bad_perm.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

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/fixtures/os_daemon_can_reboot.sh
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/os_daemon_can_reboot.sh b/test/couchdb/fixtures/os_daemon_can_reboot.sh
deleted file mode 100755
index 5bc10e8..0000000
--- a/test/couchdb/fixtures/os_daemon_can_reboot.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-couch/blob/dfad673e/test/couchdb/fixtures/os_daemon_configer.escript
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/os_daemon_configer.escript b/test/couchdb/fixtures/os_daemon_configer.escript
deleted file mode 100755
index d437423..0000000
--- a/test/couchdb/fixtures/os_daemon_configer.escript
+++ /dev/null
@@ -1,101 +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.
-
--include("../couch_eunit.hrl").
-
-
-read() ->
-    case io:get_line('') of
-        eof ->
-            stop;
-        Data ->
-            ejson:decode(Data)
-    end.
-
-write(Mesg) ->
-    Data = iolist_to_binary(ejson: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() ->
-    Path = list_to_binary(?FILE),
-    FileName = list_to_binary(filename:basename(?FILE)),
-    {[{FileName, Path}]} = get_cfg(<<"os_daemons">>).
-
-test_get_cfg2() ->
-    Path = list_to_binary(?FILE),
-    FileName = list_to_binary(filename:basename(?FILE)),
-    Path = get_cfg(<<"os_daemons">>, FileName),
-    <<"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([]) ->
-    init_code_path(),
-    couch_config:start_link(?CONFIG_CHAIN),
-    couch_drv:start_link(),
-    do_tests().
-
-init_code_path() ->
-    Paths = [
-        "couchdb",
-        "ejson",
-        "erlang-oauth",
-        "ibrowse",
-        "mochiweb",
-        "snappy"
-    ],
-    lists:foreach(fun(Name) ->
-        code:add_patha(filename:join([?BUILDDIR, "src", Name]))
-    end, Paths).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/fixtures/os_daemon_die_on_boot.sh
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/os_daemon_die_on_boot.sh b/test/couchdb/fixtures/os_daemon_die_on_boot.sh
deleted file mode 100755
index 256ee79..0000000
--- a/test/couchdb/fixtures/os_daemon_die_on_boot.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

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/fixtures/os_daemon_die_quickly.sh
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/os_daemon_die_quickly.sh b/test/couchdb/fixtures/os_daemon_die_quickly.sh
deleted file mode 100755
index f5a1368..0000000
--- a/test/couchdb/fixtures/os_daemon_die_quickly.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-couch/blob/dfad673e/test/couchdb/fixtures/os_daemon_looper.escript
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/os_daemon_looper.escript b/test/couchdb/fixtures/os_daemon_looper.escript
deleted file mode 100755
index 73974e9..0000000
--- a/test/couchdb/fixtures/os_daemon_looper.escript
+++ /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().

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/fixtures/test.couch
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/test.couch b/test/couchdb/fixtures/test.couch
deleted file mode 100644
index 32c79af..0000000
Binary files a/test/couchdb/fixtures/test.couch and /dev/null differ

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/json_stream_parse_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/json_stream_parse_tests.erl b/test/couchdb/json_stream_parse_tests.erl
deleted file mode 100644
index 92303b6..0000000
--- a/test/couchdb/json_stream_parse_tests.erl
+++ /dev/null
@@ -1,151 +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(json_stream_parse_tests).
-
--include("couch_eunit.hrl").
-
--define(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"}
-    ]
-).
-
-
-raw_json_input_test_() ->
-    Tests = lists:map(
-        fun({EJson, JsonString, Desc}) ->
-            {Desc,
-             ?_assert(equiv(EJson, json_stream_parse:to_ejson(JsonString)))}
-        end, ?CASES),
-    {"Tests with raw JSON string as the input", Tests}.
-
-one_byte_data_fun_test_() ->
-    Tests = lists:map(
-        fun({EJson, JsonString, Desc}) ->
-            DataFun = fun() -> single_byte_data_fun(JsonString) end,
-            {Desc,
-             ?_assert(equiv(EJson, json_stream_parse:to_ejson(DataFun)))}
-        end, ?CASES),
-    {"Tests with a 1 byte output data function as the input", Tests}.
-
-test_multiple_bytes_data_fun_test_() ->
-    Tests = lists:map(
-        fun({EJson, JsonString, Desc}) ->
-            DataFun = fun() -> multiple_bytes_data_fun(JsonString) end,
-            {Desc,
-             ?_assert(equiv(EJson, json_stream_parse:to_ejson(DataFun)))}
-        end, ?CASES),
-    {"Tests with a multiple bytes output data function as the input", Tests}.
-
-
-%% 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-couch/blob/dfad673e/test/couchdb/test_request.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/test_request.erl b/test/couchdb/test_request.erl
deleted file mode 100644
index 68e4956..0000000
--- a/test/couchdb/test_request.erl
+++ /dev/null
@@ -1,75 +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_request).
-
--export([get/1, get/2, get/3]).
--export([put/2, put/3]).
--export([options/1, options/2, options/3]).
--export([request/3, request/4]).
-
-get(Url) ->
-    request(get, Url, []).
-
-get(Url, Headers) ->
-    request(get, Url, Headers).
-get(Url, Headers, Opts) ->
-    request(get, Url, Headers, [], Opts).
-
-
-put(Url, Body) ->
-    request(put, Url, [], Body).
-
-put(Url, Headers, Body) ->
-    request(put, Url, Headers, Body).
-
-
-options(Url) ->
-    request(options, Url, []).
-
-options(Url, Headers) ->
-    request(options, Url, Headers).
-
-options(Url, Headers, Opts) ->
-    request(options, Url, Headers, [], Opts).
-
-
-request(Method, Url, Headers) ->
-    request(Method, Url, Headers, []).
-
-request(Method, Url, Headers, Body) ->
-    request(Method, Url, Headers, Body, [], 3).
-
-request(Method, Url, Headers, Body, Opts) ->
-    request(Method, Url, Headers, Body, Opts, 3).
-
-request(_Method, _Url, _Headers, _Body, _Opts, 0) ->
-    {error, request_failed};
-request(Method, Url, Headers, Body, Opts, N) ->
-    case code:is_loaded(ibrowse) of
-        false ->
-            {ok, _} = ibrowse:start();
-        _ ->
-            ok
-    end,
-    case ibrowse:send_req(Url, Headers, Method, Body, Opts) of
-        {ok, Code0, RespHeaders, RespBody0} ->
-            Code = list_to_integer(Code0),
-            RespBody = iolist_to_binary(RespBody0),
-            {ok, Code, RespHeaders, RespBody};
-        {error, {'EXIT', {normal, _}}} ->
-            % Connection closed right after a successful request that
-            % used the same connection.
-            request(Method, Url, Headers, Body, N - 1);
-        Error ->
-            Error
-    end.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/test_web.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/test_web.erl b/test/couchdb/test_web.erl
deleted file mode 100644
index 1de2cd1..0000000
--- a/test/couchdb/test_web.erl
+++ /dev/null
@@ -1,112 +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).
-
--include("couch_eunit.hrl").
-
--export([start_link/0, stop/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).
--define(DELAY, 500).
-
-start_link() ->
-    gen_server:start({local, ?HANDLER}, ?MODULE, [], []),
-    mochiweb_http:start([
-        {name, ?SERVER},
-        {loop, {?MODULE, loop}},
-        {port, 0}
-    ]).
-
-loop(Req) ->
-    %?debugFmt("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(?DELAY),
-            lists:foreach(fun(C) -> Resp:write_chunk(C) end, BodyChunks),
-            Resp:write_chunk([]),
-            {ok, Resp};
-        {error, Reason} ->
-            ?debugFmt("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) ->
-    ?assertEqual(ok, gen_server:call(?HANDLER, {set_assert, Fun})).
-
-check_last() ->
-    gen_server:call(?HANDLER, last_status).
-
-init(_) ->
-    {ok, nil}.
-
-terminate(_Reason, _State) ->
-    ok.
-
-stop() ->
-    gen_server:cast(?SERVER, stop).
-
-
-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(stop, State) ->
-    {stop, normal, State};
-handle_cast(Msg, State) ->
-    ?debugFmt("Ignoring cast message: ~p", [Msg]),
-    {noreply, State}.
-
-handle_info(Msg, State) ->
-    ?debugFmt("Ignoring info message: ~p", [Msg]),
-    {noreply, State}.
-
-code_change(_OldVsn, State, _Extra) ->
-    {ok, State}.


[17/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 130-attachments-md5.t etap test suite to eunit

Add random document id generator macros.
Have to use handmade http client instead of ibrowse since it makes too
complicated sending chunked requests.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/60ed2923
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/60ed2923
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/60ed2923

Branch: refs/heads/1963-eunit-bigcouch
Commit: 60ed2923fa5aba794f224140011b35eb3f6fb8ba
Parents: c124007
Author: Alexander Shorin <kx...@apache.org>
Authored: Wed May 28 05:32:11 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:44 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_attachments_tests.erl | 264 ++++++++++++++++++++++++
 1 file changed, 264 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/60ed2923/test/couchdb/couchdb_attachments_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_attachments_tests.erl b/test/couchdb/couchdb_attachments_tests.erl
new file mode 100644
index 0000000..aef1873
--- /dev/null
+++ b/test/couchdb/couchdb_attachments_tests.erl
@@ -0,0 +1,264 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_attachments_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(TIMEOUT, 1000).
+-define(TIMEWAIT, 100).
+-define(i2l(I), integer_to_list(I)).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    Pid.
+
+stop(Pid) ->
+    erlang:monitor(process, Pid),
+    couch_server_sup:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, []),
+    ok = couch_db:close(Db),
+    Addr = couch_config:get("httpd", "bind_address", any),
+    Port = mochiweb_socket_server:get(couch_httpd, port),
+    Host = Addr ++ ":" ++ ?i2l(Port),
+    {Host, ?b2l(DbName)}.
+
+teardown({_, DbName}) ->
+    ok = couch_server:delete(?l2b(DbName), []),
+    ok.
+
+
+attachments_test_() ->
+    {
+        "Attachments tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            [
+                attachments_md5_tests()
+            ]
+        }
+    }.
+
+attachments_md5_tests() ->
+    {
+        "Attachments MD5 tests",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_upload_attachment_without_md5/1,
+                fun should_upload_attachment_by_chunks_without_md5/1,
+                fun should_upload_attachment_with_valid_md5_header/1,
+                fun should_upload_attachment_by_chunks_with_valid_md5_header/1,
+                fun should_upload_attachment_by_chunks_with_valid_md5_trailer/1,
+                fun should_reject_attachment_with_invalid_md5/1,
+                fun should_reject_chunked_attachment_with_invalid_md5/1,
+                fun should_reject_chunked_attachment_with_invalid_md5_trailer/1
+            ]
+        }
+    }.
+
+
+should_upload_attachment_without_md5({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        Body = "We all live in a yellow submarine!",
+        Headers = [
+            {"Content-Length", "34"},
+            {"Content-Type", "text/plain"},
+            {"Host", Host}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(201, Code),
+        ?assertEqual(true, get_json(Json, [<<"ok">>]))
+    end).
+
+should_upload_attachment_by_chunks_without_md5({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        AttData = <<"We all live in a yellow submarine!">>,
+        <<Part1:21/binary, Part2:13/binary>> = AttData,
+        Body = chunked_body([Part1, Part2]),
+        Headers = [
+            {"Content-Type", "text/plain"},
+            {"Transfer-Encoding", "chunked"},
+            {"Host", Host}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(201, Code),
+        ?assertEqual(true, get_json(Json, [<<"ok">>]))
+    end).
+
+should_upload_attachment_with_valid_md5_header({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        Body = "We all live in a yellow submarine!",
+        Headers = [
+            {"Content-Length", "34"},
+            {"Content-Type", "text/plain"},
+            {"Content-MD5", ?b2l(base64:encode(couch_util:md5(Body)))},
+            {"Host", Host}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(201, Code),
+        ?assertEqual(true, get_json(Json, [<<"ok">>]))
+    end).
+
+should_upload_attachment_by_chunks_with_valid_md5_header({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        AttData = <<"We all live in a yellow submarine!">>,
+        <<Part1:21/binary, Part2:13/binary>> = AttData,
+        Body = chunked_body([Part1, Part2]),
+        Headers = [
+            {"Content-Type", "text/plain"},
+            {"Content-MD5", ?b2l(base64:encode(couch_util:md5(AttData)))},
+            {"Host", Host},
+            {"Transfer-Encoding", "chunked"}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(201, Code),
+        ?assertEqual(true, get_json(Json, [<<"ok">>]))
+    end).
+
+should_upload_attachment_by_chunks_with_valid_md5_trailer({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        AttData = <<"We all live in a yellow submarine!">>,
+        <<Part1:21/binary, Part2:13/binary>> = AttData,
+        Body = [chunked_body([Part1, Part2]),
+                "Content-MD5: ", base64:encode(couch_util:md5(AttData)),
+                "\r\n"],
+        Headers = [
+            {"Content-Type", "text/plain"},
+            {"Host", Host},
+            {"Trailer", "Content-MD5"},
+            {"Transfer-Encoding", "chunked"}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(201, Code),
+        ?assertEqual(true, get_json(Json, [<<"ok">>]))
+    end).
+
+should_reject_attachment_with_invalid_md5({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        Body = "We all live in a yellow submarine!",
+        Headers = [
+            {"Content-Length", "34"},
+            {"Content-Type", "text/plain"},
+            {"Content-MD5", ?b2l(base64:encode(<<"foobar!">>))},
+            {"Host", Host}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(400, Code),
+        ?assertEqual(<<"content_md5_mismatch">>,
+                     get_json(Json, [<<"error">>]))
+    end).
+
+
+should_reject_chunked_attachment_with_invalid_md5({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        AttData = <<"We all live in a yellow submarine!">>,
+        <<Part1:21/binary, Part2:13/binary>> = AttData,
+        Body = chunked_body([Part1, Part2]),
+        Headers = [
+            {"Content-Type", "text/plain"},
+            {"Content-MD5", ?b2l(base64:encode(<<"foobar!">>))},
+            {"Host", Host},
+            {"Transfer-Encoding", "chunked"}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(400, Code),
+        ?assertEqual(<<"content_md5_mismatch">>,
+                     get_json(Json, [<<"error">>]))
+    end).
+
+should_reject_chunked_attachment_with_invalid_md5_trailer({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        AttData = <<"We all live in a yellow submarine!">>,
+        <<Part1:21/binary, Part2:13/binary>> = AttData,
+        Body = [chunked_body([Part1, Part2]),
+                "Content-MD5: ", base64:encode(<<"foobar!">>),
+                "\r\n"],
+        Headers = [
+            {"Content-Type", "text/plain"},
+            {"Host", Host},
+            {"Trailer", "Content-MD5"},
+            {"Transfer-Encoding", "chunked"}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(400, Code),
+        ?assertEqual(<<"content_md5_mismatch">>,
+                     get_json(Json, [<<"error">>]))
+    end).
+
+
+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.
+
+chunked_body(Chunks) ->
+    chunked_body(Chunks, []).
+
+chunked_body([], Acc) ->
+    iolist_to_binary(lists:reverse(Acc, "0\r\n"));
+chunked_body([Chunk | Rest], Acc) ->
+    Size = to_hex(size(Chunk)),
+    chunked_body(Rest, ["\r\n", Chunk, "\r\n", Size | Acc]).
+
+get_socket() ->
+    Options = [binary, {packet, 0}, {active, false}],
+    Addr = couch_config:get("httpd", "bind_address", any),
+    Port = mochiweb_socket_server:get(couch_httpd, port),
+    {ok, Sock} = gen_tcp:connect(Addr, Port, Options),
+    Sock.
+
+request(Method, Url, Headers, Body) ->
+    RequestHead = [Method, " ", Url, " HTTP/1.1"],
+    RequestHeaders = [[string:join([Key, Value], ": "), "\r\n"]
+                      || {Key, Value} <- Headers],
+    Request = [RequestHead, "\r\n", RequestHeaders, "\r\n", Body, "\r\n"],
+    Sock = get_socket(),
+    gen_tcp:send(Sock, list_to_binary(lists:flatten(Request))),
+    timer:sleep(?TIMEWAIT),  % must wait to receive complete response
+    {ok, R} = gen_tcp:recv(Sock, 0),
+    gen_tcp:close(Sock),
+    [Header, Body1] = re:split(R, "\r\n\r\n", [{return, binary}]),
+    {ok, {http_response, _, Code, _}, _} =
+        erlang:decode_packet(http, Header, []),
+    Json = ejson:decode(Body1),
+    {ok, Code, Json}.


[20/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 160-vhosts.t etap test suite to eunit

Split Rewrite and OAuth tests.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/ab99d568
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/ab99d568
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/ab99d568

Branch: refs/heads/1963-eunit-bigcouch
Commit: ab99d56852a31e0218bd3b9fabb2f49f0f433dd7
Parents: b294eb2
Author: Alexander Shorin <kx...@apache.org>
Authored: Tue Jun 3 10:58:58 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:44 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_vhosts_tests.erl | 441 +++++++++++++++++++++++++++++
 test/couchdb/test_request.erl         |  15 +-
 2 files changed, 451 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/ab99d568/test/couchdb/couchdb_vhosts_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_vhosts_tests.erl b/test/couchdb/couchdb_vhosts_tests.erl
new file mode 100644
index 0000000..94b1957
--- /dev/null
+++ b/test/couchdb/couchdb_vhosts_tests.erl
@@ -0,0 +1,441 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_vhosts_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
+-define(TIMEOUT, 1000).
+-define(iofmt(S, A), lists:flatten(io_lib:format(S, A))).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    Pid.
+
+stop(Pid) ->
+    erlang:monitor(process, Pid),
+    couch_server_sup:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+    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),
+    couch_db:close(Db),
+
+    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+    Url = "http://" ++ Addr ++ ":" ++ Port,
+    {Url, ?b2l(DbName)}.
+
+setup_oauth() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+
+    couch_config:set("couch_httpd_auth", "authentication_db",
+                     ?b2l(?tempdb()), false),
+    couch_config:set("oauth_token_users", "otoksec1", "joe", false),
+    couch_config:set("oauth_consumer_secrets", "consec1", "foo", false),
+    couch_config:set("oauth_token_secrets", "otoksec1", "foobar", false),
+    couch_config:set("couch_httpd_auth", "require_valid_user", "true", false),
+
+    ok = couch_config:set(
+        "vhosts", "oauth-example.com",
+        "/" ++ ?b2l(DbName) ++ "/_design/test/_rewrite/foobar", false),
+
+    DDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, <<"_design/test">>},
+        {<<"language">>, <<"javascript">>},
+        {<<"rewrites">>, [
+            {[
+                {<<"from">>, <<"foobar">>},
+                {<<"to">>, <<"_info">>}
+            ]}
+        ]}
+    ]}),
+    {ok, _} = couch_db:update_doc(Db, DDoc, []),
+
+    couch_db:ensure_full_commit(Db),
+    couch_db:close(Db),
+
+    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+    Url = "http://" ++ Addr ++ ":" ++ Port,
+    {Url, ?b2l(DbName)}.
+
+teardown({_, DbName}) ->
+    ok = couch_server:delete(?l2b(DbName), []),
+    ok.
+
+
+vhosts_test_() ->
+    {
+        "Virtual Hosts rewrite tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    fun should_return_database_info/1,
+                    fun should_return_revs_info/1,
+                    fun should_serve_utils_for_vhost/1,
+                    fun should_return_virtual_request_path_field_in_request/1,
+                    fun should_return_real_request_path_field_in_request/1,
+                    fun should_match_wildcard_vhost/1,
+                    fun should_return_db_info_for_wildcard_vhost_for_custom_db/1,
+                    fun should_replace_rewrite_variables_for_db_and_doc/1,
+                    fun should_return_db_info_for_vhost_with_resource/1,
+                    fun should_return_revs_info_for_vhost_with_resource/1,
+                    fun should_return_db_info_for_vhost_with_wildcard_resource/1,
+                    fun should_return_path_for_vhost_with_wildcard_host/1
+                ]
+            }
+        }
+    }.
+
+oauth_test_() ->
+    {
+        "Virtual Hosts OAuth tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup_oauth/0, fun teardown/1,
+                [
+                    fun should_require_auth/1,
+                    fun should_succeed_oauth/1,
+                    fun should_fail_oauth_with_wrong_credentials/1
+                ]
+            }
+        }
+    }.
+
+
+should_return_database_info({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "example.com", "/" ++ DbName, false),
+        case test_request:get(Url, [], [{host_header, "example.com"}]) of
+            {ok, _, _, Body} ->
+                {JsonBody} = ejson:decode(Body),
+                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_return_revs_info({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "example.com", "/" ++ DbName, false),
+        case test_request:get(Url ++ "/doc1?revs_info=true", [],
+                              [{host_header, "example.com"}]) of
+            {ok, _, _, Body} ->
+                {JsonBody} = ejson:decode(Body),
+                ?assert(proplists:is_defined(<<"_revs_info">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_serve_utils_for_vhost({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "example.com", "/" ++ DbName, false),
+        case test_request:get(Url ++ "/_utils/index.html", [],
+                              [{host_header, "example.com"}]) of
+            {ok, _, _, Body} ->
+                ?assertMatch(<<"<!DOCTYPE html>", _/binary>>, Body);
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_return_virtual_request_path_field_in_request({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "example1.com",
+                              "/" ++ DbName ++ "/_design/doc1/_rewrite/",
+                              false),
+        case test_request:get(Url, [], [{host_header, "example1.com"}]) of
+            {ok, _, _, Body} ->
+                {Json} = ejson:decode(Body),
+                ?assertEqual(<<"/">>,
+                             proplists:get_value(<<"requested_path">>, Json));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_return_real_request_path_field_in_request({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "example1.com",
+                              "/" ++ DbName ++ "/_design/doc1/_rewrite/",
+                              false),
+        case test_request:get(Url, [], [{host_header, "example1.com"}]) of
+            {ok, _, _, Body} ->
+                {Json} = ejson:decode(Body),
+                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
+                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_match_wildcard_vhost({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "*.example.com",
+                              "/" ++ DbName ++ "/_design/doc1/_rewrite", false),
+        case test_request:get(Url, [], [{host_header, "test.example.com"}]) of
+            {ok, _, _, Body} ->
+                {Json} = ejson:decode(Body),
+                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
+                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_return_db_info_for_wildcard_vhost_for_custom_db({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", ":dbname.example1.com",
+                              "/:dbname", false),
+        Host = DbName ++ ".example1.com",
+        case test_request:get(Url, [], [{host_header, Host}]) of
+            {ok, _, _, Body} ->
+                {JsonBody} = ejson:decode(Body),
+                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_replace_rewrite_variables_for_db_and_doc({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts",":appname.:dbname.example1.com",
+                              "/:dbname/_design/:appname/_rewrite/", false),
+        Host = "doc1." ++ DbName ++ ".example1.com",
+        case test_request:get(Url, [], [{host_header, Host}]) of
+            {ok, _, _, Body} ->
+                {Json} = ejson:decode(Body),
+                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
+                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_return_db_info_for_vhost_with_resource({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts",
+                              "example.com/test", "/" ++ DbName, false),
+        ReqUrl = Url ++ "/test",
+        case test_request:get(ReqUrl, [], [{host_header, "example.com"}]) of
+            {ok, _, _, Body} ->
+                {JsonBody} = ejson:decode(Body),
+                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+
+should_return_revs_info_for_vhost_with_resource({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts",
+                              "example.com/test", "/" ++ DbName, false),
+        ReqUrl = Url ++ "/test/doc1?revs_info=true",
+        case test_request:get(ReqUrl, [], [{host_header, "example.com"}]) of
+            {ok, _, _, Body} ->
+                {JsonBody} = ejson:decode(Body),
+                ?assert(proplists:is_defined(<<"_revs_info">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_return_db_info_for_vhost_with_wildcard_resource({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "*.example2.com/test", "/*", false),
+        ReqUrl = Url ++ "/test",
+        Host = DbName ++ ".example2.com",
+        case test_request:get(ReqUrl, [], [{host_header, Host}]) of
+            {ok, _, _, Body} ->
+                {JsonBody} = ejson:decode(Body),
+                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_return_path_for_vhost_with_wildcard_host({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "*/test1",
+                              "/" ++ DbName ++ "/_design/doc1/_show/test",
+                              false),
+        case test_request:get(Url ++ "/test1") of
+            {ok, _, _, Body} ->
+                {Json} = ejson:decode(Body),
+                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
+                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_require_auth({Url, _}) ->
+    ?_test(begin
+        case test_request:get(Url, [], [{host_header, "oauth-example.com"}]) of
+            {ok, Code, _, Body} ->
+                ?assertEqual(401, Code),
+                {JsonBody} = ejson:decode(Body),
+                ?assertEqual(<<"unauthorized">>,
+                             couch_util:get_value(<<"error">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_succeed_oauth({Url, _}) ->
+    ?_test(begin
+        AuthDbName = couch_config:get("couch_httpd_auth", "authentication_db"),
+        JoeDoc = couch_doc:from_json_obj({[
+            {<<"_id">>, <<"org.couchdb.user:joe">>},
+            {<<"type">>, <<"user">>},
+            {<<"name">>, <<"joe">>},
+            {<<"roles">>, []},
+            {<<"password_sha">>, <<"fe95df1ca59a9b567bdca5cbaf8412abd6e06121">>},
+            {<<"salt">>, <<"4e170ffeb6f34daecfd814dfb4001a73">>}
+        ]}),
+        {ok, AuthDb} = couch_db:open_int(?l2b(AuthDbName), [?ADMIN_USER]),
+        {ok, _} = couch_db:update_doc(AuthDb, JoeDoc, [?ADMIN_USER]),
+
+        Host = "oauth-example.com",
+        Consumer = {"consec1", "foo", hmac_sha1},
+        SignedParams = oauth:sign(
+            "GET", "http://" ++ Host ++ "/", [], Consumer, "otoksec1", "foobar"),
+        OAuthUrl = oauth:uri(Url, SignedParams),
+
+        case test_request:get(OAuthUrl, [], [{host_header, Host}]) of
+            {ok, Code, _, Body} ->
+                ?assertEqual(200, Code),
+                {JsonBody} = ejson:decode(Body),
+                ?assertEqual(<<"test">>,
+                             couch_util:get_value(<<"name">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_fail_oauth_with_wrong_credentials({Url, _}) ->
+    ?_test(begin
+        AuthDbName = couch_config:get("couch_httpd_auth", "authentication_db"),
+        JoeDoc = couch_doc:from_json_obj({[
+            {<<"_id">>, <<"org.couchdb.user:joe">>},
+            {<<"type">>, <<"user">>},
+            {<<"name">>, <<"joe">>},
+            {<<"roles">>, []},
+            {<<"password_sha">>, <<"fe95df1ca59a9b567bdca5cbaf8412abd6e06121">>},
+            {<<"salt">>, <<"4e170ffeb6f34daecfd814dfb4001a73">>}
+        ]}),
+        {ok, AuthDb} = couch_db:open_int(?l2b(AuthDbName), [?ADMIN_USER]),
+        {ok, _} = couch_db:update_doc(AuthDb, JoeDoc, [?ADMIN_USER]),
+
+        Host = "oauth-example.com",
+        Consumer = {"consec1", "bad_secret", hmac_sha1},
+        SignedParams = oauth:sign(
+            "GET", "http://" ++ Host ++ "/", [], Consumer, "otoksec1", "foobar"),
+        OAuthUrl = oauth:uri(Url, SignedParams),
+
+        case test_request:get(OAuthUrl, [], [{host_header, Host}]) of
+            {ok, Code, _, Body} ->
+                ?assertEqual(401, Code),
+                {JsonBody} = ejson:decode(Body),
+                ?assertEqual(<<"unauthorized">>,
+                             couch_util:get_value(<<"error">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/ab99d568/test/couchdb/test_request.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/test_request.erl b/test/couchdb/test_request.erl
index d6725ea..36871b4 100644
--- a/test/couchdb/test_request.erl
+++ b/test/couchdb/test_request.erl
@@ -12,7 +12,7 @@
 
 -module(test_request).
 
--export([get/1, get/2, put/2, put/3]).
+-export([get/1, get/2, get/3, put/2, put/3]).
 -export([request/3, request/4]).
 
 get(Url) ->
@@ -20,6 +20,8 @@ get(Url) ->
 
 get(Url, Headers) ->
     request(get, Url, Headers).
+get(Url, Headers, Opts) ->
+    request(get, Url, Headers, [], Opts).
 
 
 put(Url, Body) ->
@@ -33,18 +35,21 @@ request(Method, Url, Headers) ->
     request(Method, Url, Headers, []).
 
 request(Method, Url, Headers, Body) ->
-    request(Method, Url, Headers, Body, 3).
+    request(Method, Url, Headers, Body, [], 3).
 
-request(_Method, _Url, _Headers, _Body, 0) ->
+request(Method, Url, Headers, Body, Opts) ->
+    request(Method, Url, Headers, Body, Opts, 3).
+
+request(_Method, _Url, _Headers, _Body, _Opts, 0) ->
     {error, request_failed};
-request(Method, Url, Headers, Body, N) ->
+request(Method, Url, Headers, Body, Opts, N) ->
     case code:is_loaded(ibrowse) of
         false ->
             {ok, _} = ibrowse:start();
         _ ->
             ok
     end,
-    case ibrowse:send_req(Url, Headers, Method, Body) of
+    case ibrowse:send_req(Url, Headers, Method, Body, Opts) of
         {ok, Code0, RespHeaders, RespBody0} ->
             Code = list_to_integer(Code0),
             RespBody = iolist_to_binary(RespBody0),


[29/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 232-csp.t etap test suite to eunit


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/013730c6
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/013730c6
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/013730c6

Branch: refs/heads/1963-eunit-bigcouch
Commit: 013730c610aab1a02ad63e99a40a3616f00344d2
Parents: 44e2c26
Author: Alexander Shorin <kx...@apache.org>
Authored: Tue Jun 10 19:54:20 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:45 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_csp_tests.erl | 96 +++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/013730c6/test/couchdb/couchdb_csp_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_csp_tests.erl b/test/couchdb/couchdb_csp_tests.erl
new file mode 100644
index 0000000..adb0e6d
--- /dev/null
+++ b/test/couchdb/couchdb_csp_tests.erl
@@ -0,0 +1,96 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_csp_tests).
+
+-include("couch_eunit.hrl").
+
+-define(TIMEOUT, 1000).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    Pid.
+
+stop(Pid) ->
+    couch_server_sup:stop(),
+    erlang:monitor(process, Pid),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    ok = couch_config:set("csp", "enable", "true", false),
+    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+    lists:concat(["http://", Addr, ":", Port, "/_utils/"]).
+
+teardown(_) ->
+    ok.
+
+
+csp_test_() ->
+    {
+        "Content Security Policy tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    fun should_not_return_any_csp_headers_when_disabled/1,
+                    fun should_apply_default_policy/1,
+                    fun should_return_custom_policy/1,
+                    fun should_only_enable_csp_when_true/1
+                ]
+            }
+        }
+    }.
+
+
+should_not_return_any_csp_headers_when_disabled(Url) ->
+    ?_assertEqual(undefined,
+        begin
+            ok = couch_config:set("csp", "enable", "false", false),
+            {ok, _, Headers, _} = test_request:get(Url),
+            proplists:get_value("Content-Security-Policy", Headers)
+        end).
+
+should_apply_default_policy(Url) ->
+    ?_assertEqual(
+        "default-src 'self'; img-src 'self'; font-src 'self'; "
+        "script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline';",
+        begin
+            {ok, _, Headers, _} = test_request:get(Url),
+            proplists:get_value("Content-Security-Policy", Headers)
+        end).
+
+should_return_custom_policy(Url) ->
+    ?_assertEqual("default-src 'http://example.com';",
+        begin
+            ok = couch_config:set("csp", "header_value",
+                                  "default-src 'http://example.com';", false),
+            {ok, _, Headers, _} = test_request:get(Url),
+            proplists:get_value("Content-Security-Policy", Headers)
+        end).
+
+should_only_enable_csp_when_true(Url) ->
+    ?_assertEqual(undefined,
+        begin
+            ok = couch_config:set("csp", "enable", "tru", false),
+            {ok, _, Headers, _} = test_request:get(Url),
+            proplists:get_value("Content-Security-Policy", Headers)
+        end).


[22/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 172-os-daemons-errors.t etap test suite to eunit

Merged into couchdb_os_daemons_tests suite.
Removed errors redirection to /dev/null to explicitly signal that
permissions are set correctly.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/49de105d
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/49de105d
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/49de105d

Branch: refs/heads/1963-eunit-bigcouch
Commit: 49de105d4d2f11b213431e3f1287a776914ea4fd
Parents: a8a38c9
Author: Alexander Shorin <kx...@apache.org>
Authored: Tue Jun 3 15:54:33 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:44 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_os_daemons_tests.erl      | 64 ++++++++++++++++++++-
 test/couchdb/fixtures/os_daemon_bad_perm.sh    | 17 ++++++
 test/couchdb/fixtures/os_daemon_can_reboot.sh  | 15 +++++
 test/couchdb/fixtures/os_daemon_die_on_boot.sh | 15 +++++
 test/couchdb/fixtures/os_daemon_die_quickly.sh | 15 +++++
 5 files changed, 125 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/49de105d/test/couchdb/couchdb_os_daemons_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_os_daemons_tests.erl b/test/couchdb/couchdb_os_daemons_tests.erl
index dd07e82..aa949c9 100644
--- a/test/couchdb/couchdb_os_daemons_tests.erl
+++ b/test/couchdb/couchdb_os_daemons_tests.erl
@@ -28,6 +28,10 @@
 
 -define(DAEMON_CONFIGER, "os_daemon_configer.escript").
 -define(DAEMON_LOOPER, "os_daemon_looper.escript").
+-define(DAEMON_BAD_PERM, "os_daemon_bad_perm.sh").
+-define(DAEMON_CAN_REBOOT, "os_daemon_can_reboot.sh").
+-define(DAEMON_DIE_ON_BOOT, "os_daemon_die_on_boot.sh").
+-define(DAEMON_DIE_QUICKLY, "os_daemon_die_quickly.sh").
 -define(DELAY, 100).
 -define(TIMEOUT, 1000).
 
@@ -84,6 +88,20 @@ configuration_reader_test_() ->
             fun setup/1, fun teardown/2,
             [{?DAEMON_CONFIGER,
               fun should_read_write_config_settings_by_daemon/2}]
+
+        }
+    }.
+
+error_test_() ->
+    {
+        "OS Daemon process error tests",
+        {
+            foreachx,
+            fun setup/1, fun teardown/2,
+            [{?DAEMON_BAD_PERM, fun should_fail_due_to_lack_of_permissions/2},
+             {?DAEMON_DIE_ON_BOOT, fun should_die_on_boot/2},
+             {?DAEMON_DIE_QUICKLY, fun should_die_quickly/2},
+             {?DAEMON_CAN_REBOOT, fun should_not_being_halted/2}]
         }
     }.
 
@@ -154,13 +172,57 @@ should_read_write_config_settings_by_daemon(DName, _) ->
         check_daemon(D, DName)
     end).
 
+should_fail_due_to_lack_of_permissions(DName, _) ->
+    ?_test(should_halts(DName, 1000)).
+
+should_die_on_boot(DName, _) ->
+    ?_test(should_halts(DName, 1000)).
+
+should_die_quickly(DName, _) ->
+    ?_test(should_halts(DName, 4000)).
+
+should_not_being_halted(DName, _) ->
+    ?_test(begin
+        timer:sleep(1000),
+        {ok, [D1]} = couch_os_daemons:info([table]),
+        check_daemon(D1, DName, 0),
+
+        % Should reboot every two seconds. We're at 1s, so wait
+        % until 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, DName, 1),
+
+        % If the kill command changed, that means we rebooted the process.
+        ?assertNotEqual(D1#daemon.kill, D2#daemon.kill)
+    end).
+
+should_halts(DName, Time) ->
+    timer:sleep(Time),
+    {ok, [D]} = couch_os_daemons:info([table]),
+    check_dead(D, DName),
+    couch_config:delete("os_daemons", DName, false).
 
 check_daemon(D) ->
     check_daemon(D, D#daemon.name).
 
 check_daemon(D, Name) ->
+    check_daemon(D, Name, 0).
+
+check_daemon(D, Name, Errs) ->
     ?assert(is_port(D#daemon.port)),
     ?assertEqual(Name, D#daemon.name),
     ?assertNotEqual(undefined, D#daemon.kill),
-    ?assertEqual([], D#daemon.errors),
+    ?assertEqual(running, D#daemon.status),
+    ?assertEqual(Errs, length(D#daemon.errors)),
     ?assertEqual([], D#daemon.buf).
+
+check_dead(D, Name) ->
+    ?assert(is_port(D#daemon.port)),
+    ?assertEqual(Name, D#daemon.name),
+    ?assertNotEqual(undefined, D#daemon.kill),
+    ?assertEqual(halted, D#daemon.status),
+    ?assertEqual(nil, D#daemon.errors),
+    ?assertEqual(nil, D#daemon.buf).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/49de105d/test/couchdb/fixtures/os_daemon_bad_perm.sh
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/os_daemon_bad_perm.sh b/test/couchdb/fixtures/os_daemon_bad_perm.sh
new file mode 100644
index 0000000..345c8b4
--- /dev/null
+++ b/test/couchdb/fixtures/os_daemon_bad_perm.sh
@@ -0,0 +1,17 @@
+#!/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

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/49de105d/test/couchdb/fixtures/os_daemon_can_reboot.sh
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/os_daemon_can_reboot.sh b/test/couchdb/fixtures/os_daemon_can_reboot.sh
new file mode 100755
index 0000000..5bc10e8
--- /dev/null
+++ b/test/couchdb/fixtures/os_daemon_can_reboot.sh
@@ -0,0 +1,15 @@
+#!/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-couch/blob/49de105d/test/couchdb/fixtures/os_daemon_die_on_boot.sh
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/os_daemon_die_on_boot.sh b/test/couchdb/fixtures/os_daemon_die_on_boot.sh
new file mode 100755
index 0000000..256ee79
--- /dev/null
+++ b/test/couchdb/fixtures/os_daemon_die_on_boot.sh
@@ -0,0 +1,15 @@
+#!/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

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/49de105d/test/couchdb/fixtures/os_daemon_die_quickly.sh
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/os_daemon_die_quickly.sh b/test/couchdb/fixtures/os_daemon_die_quickly.sh
new file mode 100755
index 0000000..f5a1368
--- /dev/null
+++ b/test/couchdb/fixtures/os_daemon_die_quickly.sh
@@ -0,0 +1,15 @@
+#!/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


[49/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Config set requires a value as a list, not a binary


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/71146669
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/71146669
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/71146669

Branch: refs/heads/1963-eunit-bigcouch
Commit: 7114666951b1f1d6e2f83143294a51c84e935457
Parents: bdc3ea7
Author: Russell Branca <ch...@apache.org>
Authored: Fri Aug 15 12:31:59 2014 -0700
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:24:06 2014 -0700

----------------------------------------------------------------------
 test/couchdb_cors_tests.erl | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71146669/test/couchdb_cors_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_cors_tests.erl b/test/couchdb_cors_tests.erl
index 02f9da9..52d1797 100644
--- a/test/couchdb_cors_tests.erl
+++ b/test/couchdb_cors_tests.erl
@@ -244,7 +244,7 @@ should_make_origin_request_with_auth(_, {_, _, Url, DefaultHeaders}) ->
     ?_assertEqual("http://example.com",
         begin
             Hashed = couch_passwords:hash_admin_password(<<"test">>),
-            config:set("admins", "test", Hashed, false),
+            config:set("admins", "test", ?b2l(Hashed), false),
             {ok, _, Resp, _} = test_request:get(
                 Url, DefaultHeaders, [{basic_auth, {"test", "test"}}]),
             config:delete("admins", "test", false),
@@ -255,7 +255,7 @@ should_make_preflight_request_with_auth(_, {_, _, Url, DefaultHeaders}) ->
     ?_assertEqual(?SUPPORTED_METHODS,
         begin
             Hashed = couch_passwords:hash_admin_password(<<"test">>),
-            config:set("admins", "test", Hashed, false),
+            config:set("admins", "test", ?b2l(Hashed), false),
             Headers = DefaultHeaders
                       ++ [{"Access-Control-Request-Method", "GET"}],
             {ok, _, Resp, _} = test_request:options(


[16/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 180-http-proxy.t etap test suite to eunit


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/102d8e06
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/102d8e06
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/102d8e06

Branch: refs/heads/1963-eunit-bigcouch
Commit: 102d8e06bd679d90549d864883f7ee3b65a85759
Parents: 49de105
Author: Alexander Shorin <kx...@apache.org>
Authored: Wed Jun 4 12:54:44 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:44 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_http_proxy_tests.erl | 462 +++++++++++++++++++++++++
 test/couchdb/test_web.erl                 | 112 ++++++
 2 files changed, 574 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/102d8e06/test/couchdb/couchdb_http_proxy_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_http_proxy_tests.erl b/test/couchdb/couchdb_http_proxy_tests.erl
new file mode 100644
index 0000000..acb1974
--- /dev/null
+++ b/test/couchdb/couchdb_http_proxy_tests.erl
@@ -0,0 +1,462 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_http_proxy_tests).
+
+-include("couch_eunit.hrl").
+
+-record(req, {method=get, path="", headers=[], body="", opts=[]}).
+
+-define(CONFIG_FIXTURE_TEMP,
+    begin
+        FileName = filename:join([?TEMPDIR, ?tempfile() ++ ".ini"]),
+        {ok, Fd} = file:open(FileName, write),
+        ok = file:truncate(Fd),
+        ok = file:close(Fd),
+        FileName
+    end).
+-define(TIMEOUT, 5000).
+
+
+start() ->
+    % we have to write any config changes to temp ini file to not loose them
+    % when supervisor will kill all children due to reaching restart threshold
+    % (each httpd_global_handlers changes causes couch_httpd restart)
+    couch_server_sup:start_link(?CONFIG_CHAIN ++ [?CONFIG_FIXTURE_TEMP]),
+    % 49151 is IANA Reserved, let's assume no one is listening there
+    couch_config:set("httpd_global_handlers", "_error",
+        "{couch_httpd_proxy, handle_proxy_req, <<\"http://127.0.0.1:49151/\">>}"
+    ),
+    ok.
+
+stop(_) ->
+    couch_server_sup:stop(),
+    ok.
+
+setup() ->
+    {ok, Pid} = test_web:start_link(),
+    Value = lists:flatten(io_lib:format(
+        "{couch_httpd_proxy, handle_proxy_req, ~p}",
+        [list_to_binary(proxy_url())])),
+    couch_config:set("httpd_global_handlers", "_test", Value),
+    % let couch_httpd restart
+    timer:sleep(100),
+    Pid.
+
+teardown(Pid) ->
+    erlang:monitor(process, Pid),
+    test_web:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, test_web_stop})
+    end.
+
+
+http_proxy_test_() ->
+    {
+        "HTTP Proxy handler tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    fun should_proxy_basic_request/1,
+                    fun should_return_alternative_status/1,
+                    fun should_respect_trailing_slash/1,
+                    fun should_proxy_headers/1,
+                    fun should_proxy_host_header/1,
+                    fun should_pass_headers_back/1,
+                    fun should_use_same_protocol_version/1,
+                    fun should_proxy_body/1,
+                    fun should_proxy_body_back/1,
+                    fun should_proxy_chunked_body/1,
+                    fun should_proxy_chunked_body_back/1,
+                    fun should_rewrite_location_header/1,
+                    fun should_not_rewrite_external_locations/1,
+                    fun should_rewrite_relative_location/1,
+                    fun should_refuse_connection_to_backend/1
+                ]
+            }
+
+        }
+    }.
+
+
+should_proxy_basic_request(_) ->
+    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,
+    ?_test(check_request(#req{}, Remote, Local)).
+
+should_return_alternative_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"},
+    ?_test(check_request(Req, Remote, Local)).
+
+should_respect_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/"},
+    ?_test(check_request(Req, Remote, Local)).
+
+should_proxy_headers(_) ->
+    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"}]
+    },
+    ?_test(check_request(Req, Remote, Local)).
+
+should_proxy_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"}]
+    },
+    ?_test(check_request(Req, Remote, Local)).
+
+should_pass_headers_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"},
+    ?_test(check_request(Req, Remote, Local)).
+
+should_use_same_protocol_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}}]
+    },
+    ?_test(check_request(Req, Remote, Local)).
+
+should_proxy_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!"
+    },
+    ?_test(check_request(Req, Remote, Local)).
+
+should_proxy_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"},
+    ?_test(check_request(Req, Remote, Local)).
+
+should_proxy_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=chunked_body(BodyChunks)
+    },
+    ?_test(check_request(Req, Remote, Local)).
+
+should_proxy_chunked_body_back(_) ->
+    ?_test(begin
+        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(Req, Remote, no_local),
+        ?assertMatch({ibrowse_req_id, _}, Resp),
+        {_, ReqId} = Resp,
+
+        % Grab headers from response
+        receive
+            {ibrowse_async_headers, ReqId, "200", Headers} ->
+                ?assertEqual("chunked",
+                             proplists:get_value("Transfer-Encoding", Headers)),
+            ibrowse:stream_next(ReqId)
+        after 1000 ->
+            throw({error, timeout})
+        end,
+
+        ?assertEqual(<<"foobarbazinga">>, recv_body(ReqId, [])),
+        ?assertEqual(was_ok, test_web:check_last())
+    end).
+
+should_refuse_connection_to_backend(_) ->
+    Local = fun
+        ({ok, "500", _, _}) ->
+            true;
+        (_) ->
+            false
+    end,
+    Req = #req{opts=[{url, server_url("/_error")}]},
+    ?_test(check_request(Req, no_remote, Local)).
+
+should_rewrite_location_header(_) ->
+    {
+        "Testing location header rewrites",
+        do_rewrite_tests([
+            {"Location", proxy_url() ++ "/foo/bar",
+                         server_url() ++ "/foo/bar"},
+            {"Content-Location", proxy_url() ++ "/bing?q=2",
+                                 server_url() ++ "/bing?q=2"},
+            {"Uri", proxy_url() ++ "/zip#frag",
+                    server_url() ++ "/zip#frag"},
+            {"Destination", proxy_url(),
+                            server_url() ++ "/"}
+        ])
+    }.
+
+should_not_rewrite_external_locations(_) ->
+    {
+        "Testing no rewrite of external locations",
+        do_rewrite_tests([
+            {"Location", external_url() ++ "/search",
+                         external_url() ++ "/search"},
+            {"Content-Location", external_url() ++ "/s?q=2",
+                                 external_url() ++ "/s?q=2"},
+            {"Uri", external_url() ++ "/f#f",
+                    external_url() ++ "/f#f"},
+            {"Destination", external_url() ++ "/f?q=2#f",
+                            external_url() ++ "/f?q=2#f"}
+        ])
+    }.
+
+should_rewrite_relative_location(_) ->
+    {
+        "Testing relative rewrites",
+        do_rewrite_tests([
+            {"Location", "/foo",
+                         server_url() ++ "/foo"},
+            {"Content-Location", "bar",
+                                 server_url() ++ "/bar"},
+            {"Uri", "/zing?q=3",
+                    server_url() ++ "/zing?q=3"},
+            {"Destination", "bing?q=stuff#yay",
+                            server_url() ++ "/bing?q=stuff#yay"}
+        ])
+    }.
+
+
+do_rewrite_tests(Tests) ->
+    lists:map(fun({Header, Location, Url}) ->
+        should_rewrite_header(Header, Location, Url)
+    end, Tests).
+
+should_rewrite_header(Header, Location, Url) ->
+    Remote = fun(Req) ->
+        "/rewrite_test" = Req:get(path),
+        {ok, {302, [{Header, Location}], "ok"}}
+    end,
+    Local = fun
+        ({ok, "302", Headers, "ok"}) ->
+            ?assertEqual(Url, couch_util:get_value(Header, Headers)),
+            true;
+        (E) ->
+            ?debugFmt("~p", [E]),
+            false
+    end,
+    Req = #req{path="/rewrite_test"},
+    {Header, ?_test(check_request(Req, Remote, Local))}.
+
+
+server_url() ->
+    server_url("/_test").
+
+server_url(Resource) ->
+    Addr = couch_config:get("httpd", "bind_address"),
+    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+    lists:concat(["http://", Addr, ":", Port, Resource]).
+
+proxy_url() ->
+    "http://127.0.0.1:" ++ integer_to_list(test_web:get_port()).
+
+external_url() ->
+    "https://google.com".
+
+check_request(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_url() ++ 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
+    ),
+    %?debugFmt("ibrowse response: ~p", [Resp]),
+    case Local of
+        no_local ->
+            ok;
+        _ ->
+            ?assert(Local(Resp))
+    end,
+    case {Remote, Local} of
+        {no_remote, _} ->
+            ok;
+        {_, no_local} ->
+            ok;
+        _ ->
+            ?assertEqual(was_ok, test_web:check_last())
+    end,
+    Resp.
+
+chunked_body(Chunks) ->
+    chunked_body(Chunks, []).
+
+chunked_body([], Acc) ->
+    iolist_to_binary(lists:reverse(Acc, "0\r\n\r\n"));
+chunked_body([Chunk | Rest], Acc) ->
+    Size = to_hex(size(Chunk)),
+    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 ?TIMEOUT ->
+        throw({error, timeout})
+    end.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/102d8e06/test/couchdb/test_web.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/test_web.erl b/test/couchdb/test_web.erl
new file mode 100644
index 0000000..1de2cd1
--- /dev/null
+++ b/test/couchdb/test_web.erl
@@ -0,0 +1,112 @@
+% 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).
+
+-include("couch_eunit.hrl").
+
+-export([start_link/0, stop/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).
+-define(DELAY, 500).
+
+start_link() ->
+    gen_server:start({local, ?HANDLER}, ?MODULE, [], []),
+    mochiweb_http:start([
+        {name, ?SERVER},
+        {loop, {?MODULE, loop}},
+        {port, 0}
+    ]).
+
+loop(Req) ->
+    %?debugFmt("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(?DELAY),
+            lists:foreach(fun(C) -> Resp:write_chunk(C) end, BodyChunks),
+            Resp:write_chunk([]),
+            {ok, Resp};
+        {error, Reason} ->
+            ?debugFmt("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) ->
+    ?assertEqual(ok, gen_server:call(?HANDLER, {set_assert, Fun})).
+
+check_last() ->
+    gen_server:call(?HANDLER, last_status).
+
+init(_) ->
+    {ok, nil}.
+
+terminate(_Reason, _State) ->
+    ok.
+
+stop() ->
+    gen_server:cast(?SERVER, stop).
+
+
+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(stop, State) ->
+    {stop, normal, State};
+handle_cast(Msg, State) ->
+    ?debugFmt("Ignoring cast message: ~p", [Msg]),
+    {noreply, State}.
+
+handle_info(Msg, State) ->
+    ?debugFmt("Ignoring info message: ~p", [Msg]),
+    {noreply, State}.
+
+code_change(_OldVsn, State, _Extra) ->
+    {ok, State}.


[18/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 150-invalid-view-seq.t etap test suite to eunit

Merged into couchdb_views_tests suite.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/b294eb20
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/b294eb20
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/b294eb20

Branch: refs/heads/1963-eunit-bigcouch
Commit: b294eb2029165f357eca8a582d2686b6b28273ad
Parents: 31b7676
Author: Alexander Shorin <kx...@apache.org>
Authored: Tue Jun 3 08:49:32 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:44 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_views_tests.erl | 102 ++++++++++++++++++++++++++++--
 1 file changed, 96 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/b294eb20/test/couchdb/couchdb_views_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_views_tests.erl b/test/couchdb/couchdb_views_tests.erl
index e44cef6..d10b567 100644
--- a/test/couchdb/couchdb_views_tests.erl
+++ b/test/couchdb/couchdb_views_tests.erl
@@ -36,13 +36,22 @@ setup() ->
     DbName = ?tempdb(),
     {ok, _} = couch_db:create(DbName, [?ADMIN_USER]),
     FooRev = create_design_doc(DbName, <<"_design/foo">>, <<"bar">>),
-    ok = query_view(DbName, "foo", "bar"),
+    query_view(DbName, "foo", "bar"),
     BooRev = create_design_doc(DbName, <<"_design/boo">>, <<"baz">>),
-    ok = query_view(DbName, "boo", "baz"),
+    query_view(DbName, "boo", "baz"),
     {DbName, {FooRev, BooRev}}.
 
+setup_with_docs() ->
+    DbName = ?tempdb(),
+    {ok, _} = couch_db:create(DbName, [?ADMIN_USER]),
+    create_docs(DbName),
+    create_design_doc(DbName, <<"_design/foo">>, <<"bar">>),
+    DbName.
+
 teardown({DbName, _}) ->
-    ok = couch_server:delete(DbName, []),
+    teardown(DbName);
+teardown(DbName) when is_binary(DbName) ->
+    ok = couch_server:delete(DbName, [?ADMIN_USER]),
     ok.
 
 
@@ -64,6 +73,36 @@ view_indexes_cleanup_test_() ->
         }
     }.
 
+should_not_remember_docs_in_index_after_backup_restore_test() ->
+    %% COUCHDB-640
+    start(),
+    DbName = setup_with_docs(),
+
+    ok = backup_db_file(DbName),
+    create_doc(DbName),
+
+    Body0 = query_view(DbName, "foo", "bar"),
+    ViewJson0 = ejson:decode(Body0),
+    Rows0 = couch_util:get_nested_json_value(ViewJson0, [<<"rows">>]),
+    ?assert(has_doc("doc1", Rows0)),
+    ?assert(has_doc("doc2", Rows0)),
+    ?assert(has_doc("doc3", Rows0)),
+    ?assert(has_doc("doc666", Rows0)),
+
+    restore_backup_db_file(DbName),
+
+    Body1 = query_view(DbName, "foo", "bar"),
+    ViewJson1 = ejson:decode(Body1),
+    Rows1 = couch_util:get_nested_json_value(ViewJson1, [<<"rows">>]),
+    ?assert(has_doc("doc1", Rows1)),
+    ?assert(has_doc("doc2", Rows1)),
+    ?assert(has_doc("doc3", Rows1)),
+    ?assertNot(has_doc("doc666", Rows1)),
+
+    teardown(DbName),
+    stop(whereis(couch_server_sup)).
+
+
 should_have_two_indexes_alive_before_deletion({DbName, _}) ->
     view_cleanup(DbName),
     ?_assertEqual(2, count_index_files(DbName)).
@@ -80,6 +119,38 @@ should_cleanup_all_index_files({DbName, {FooRev, BooRev}})->
     ?_assertEqual(0, count_index_files(DbName)).
 
 
+create_doc(DbName) ->
+    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
+    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).
+
+create_docs(DbName) ->
+    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
+    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(DbName, DDName, ViewName) ->
     {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
     DDoc = couch_doc:from_json_obj({[
@@ -109,13 +180,13 @@ delete_design_doc(DbName, DDName, Rev) ->
 db_url(DbName) ->
     Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
     Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
-    "http://" ++ Addr ++ ":" ++ Port ++ "/" ++ binary_to_list(DbName).
+    "http://" ++ Addr ++ ":" ++ Port ++ "/" ++ ?b2l(DbName).
 
 query_view(DbName, DDoc, View) ->
-    {ok, Code, _Headers, _Body} = test_request:get(
+    {ok, Code, _Headers, Body} = test_request:get(
         db_url(DbName) ++ "/_design/" ++ DDoc ++ "/_view/" ++ View),
     ?assertEqual(200, Code),
-    ok.
+    Body.
 
 view_cleanup(DbName) ->
     {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
@@ -127,3 +198,22 @@ count_index_files(DbName) ->
     RootDir = couch_config:get("couchdb", "view_index_dir"),
     length(filelib:wildcard(RootDir ++ "/." ++
         binary_to_list(DbName) ++ "_design"++"/mrview/*")).
+
+has_doc(DocId1, Rows) ->
+    DocId = iolist_to_binary(DocId1),
+    lists:any(fun({R}) -> lists:member({<<"id">>, DocId}, R) end, Rows).
+
+backup_db_file(DbName) ->
+    DbDir = couch_config:get("couchdb", "database_dir"),
+    DbFile = filename:join([DbDir, ?b2l(DbName) ++ ".couch"]),
+    {ok, _} = file:copy(DbFile, DbFile ++ ".backup"),
+    ok.
+
+restore_backup_db_file(DbName) ->
+    DbDir = couch_config:get("couchdb", "database_dir"),
+    stop(whereis(couch_server_sup)),
+    DbFile = filename:join([DbDir, ?b2l(DbName) ++ ".couch"]),
+    ok = file:delete(DbFile),
+    ok = file:rename(DbFile ++ ".backup", DbFile),
+    start(),
+    ok.


[02/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 120-stats-collect.t etap test suite to eunit


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/d441903c
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/d441903c
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/d441903c

Branch: refs/heads/1963-eunit-bigcouch
Commit: d441903cd74ba98d69f72cbaa1a87a540cdd9bd5
Parents: 2795acd
Author: Alexander Shorin <kx...@apache.org>
Authored: Mon May 26 23:57:38 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:43 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couch_stats_tests.erl | 193 ++++++++++++++++++++++++++++++++
 1 file changed, 193 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/d441903c/test/couchdb/couch_stats_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_stats_tests.erl b/test/couchdb/couch_stats_tests.erl
new file mode 100644
index 0000000..aaaa687
--- /dev/null
+++ b/test/couchdb/couch_stats_tests.erl
@@ -0,0 +1,193 @@
+% 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(couch_stats_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(TIMEOUT, 1000).
+-define(SLEEPTIME, 100).
+
+
+setup_collector() ->
+    couch_stats_collector:start(),
+    ok.
+
+teardown_collector(_) ->
+    couch_stats_collector:stop(),
+    ok.
+
+
+couch_stats_collector_test_() ->
+    {
+        "CouchDB stats collector tests",
+        {
+            foreach,
+            fun setup_collector/0, fun teardown_collector/1,
+            [
+                should_increment_counter(),
+                should_decrement_counter(),
+                should_increment_and_decrement_counter(),
+                should_record_absolute_values(),
+                should_clear_absolute_values(),
+                should_track_process_count(),
+                should_increment_counter_multiple_times_per_pid(),
+                should_decrement_counter_on_process_exit(),
+                should_decrement_for_each_track_process_count_call_on_exit(),
+                should_return_all_counters_and_absolute_values(),
+                should_return_incremental_counters(),
+                should_return_absolute_values()
+            ]
+        }
+    }.
+
+
+should_increment_counter() ->
+    ?_assertEqual(100,
+        begin
+            AddCount = fun() -> couch_stats_collector:increment(foo) end,
+            repeat(AddCount, 100),
+            couch_stats_collector:get(foo)
+        end).
+
+should_decrement_counter() ->
+    ?_assertEqual(67,
+        begin
+            AddCount = fun() -> couch_stats_collector:increment(foo) end,
+            RemCount = fun() -> couch_stats_collector:decrement(foo) end,
+            repeat(AddCount, 100),
+            repeat(RemCount, 33),
+            couch_stats_collector:get(foo)
+        end).
+
+should_increment_and_decrement_counter() ->
+    ?_assertEqual(0,
+        begin
+            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),
+            repeat(RemCount, 80),
+            couch_stats_collector:get(foo)
+        end).
+
+should_record_absolute_values() ->
+    ?_assertEqual(lists:seq(1, 15),
+        begin
+            lists:map(fun(Val) ->
+                couch_stats_collector:record(bar, Val)
+            end, lists:seq(1, 15)),
+            couch_stats_collector:get(bar)
+        end).
+
+should_clear_absolute_values() ->
+    ?_assertEqual(nil,
+        begin
+            lists:map(fun(Val) ->
+                couch_stats_collector:record(bar, Val)
+            end, lists:seq(1, 15)),
+            couch_stats_collector:clear(bar),
+            couch_stats_collector:get(bar)
+        end).
+
+should_track_process_count() ->
+    ?_assertMatch({_, 1}, spawn_and_count(1)).
+
+should_increment_counter_multiple_times_per_pid() ->
+    ?_assertMatch({_, 3}, spawn_and_count(3)).
+
+should_decrement_counter_on_process_exit() ->
+    ?_assertEqual(2,
+        begin
+            {Pid, 1} = spawn_and_count(1),
+            spawn_and_count(2),
+            RefMon = erlang:monitor(process, Pid),
+            Pid ! sepuku,
+            receive
+                {'DOWN', RefMon, _, _, _} -> ok
+            after ?TIMEOUT ->
+                throw(timeout)
+            end,
+            % sleep for awhile to let collector handle the updates
+            % suddenly, it couldn't notice process death instantly
+            timer:sleep(?SLEEPTIME),
+            couch_stats_collector:get(hoopla)
+        end).
+
+should_decrement_for_each_track_process_count_call_on_exit() ->
+    ?_assertEqual(2,
+        begin
+            {_, 2} = spawn_and_count(2),
+            {Pid, 6} = spawn_and_count(4),
+            RefMon = erlang:monitor(process, Pid),
+            Pid ! sepuku,
+            receive
+                {'DOWN', RefMon, _, _, _} -> ok
+            after ?TIMEOUT ->
+                throw(timeout)
+            end,
+            timer:sleep(?SLEEPTIME),
+            couch_stats_collector:get(hoopla)
+        end).
+
+should_return_all_counters_and_absolute_values() ->
+    ?_assertEqual([{bar,[1.0,0.0]}, {foo,1}],
+        begin
+            couch_stats_collector:record(bar, 0.0),
+            couch_stats_collector:record(bar, 1.0),
+            couch_stats_collector:increment(foo),
+            lists:sort(couch_stats_collector:all())
+        end).
+
+should_return_incremental_counters() ->
+    ?_assertEqual([{foo,1}],
+        begin
+            couch_stats_collector:record(bar, 0.0),
+            couch_stats_collector:record(bar, 1.0),
+            couch_stats_collector:increment(foo),
+            lists:sort(couch_stats_collector:all(incremental))
+        end).
+
+should_return_absolute_values() ->
+    ?_assertEqual([{bar,[1.0,0.0]}, {zing, "Z"}],
+        begin
+            couch_stats_collector:record(bar, 0.0),
+            couch_stats_collector:record(bar, 1.0),
+            couch_stats_collector:record(zing, 90),
+            couch_stats_collector:increment(foo),
+            lists:sort(couch_stats_collector:all(absolute))
+        end).
+
+
+spawn_and_count(N) ->
+    Self = self(),
+    Pid = spawn(fun() ->
+        lists:foreach(
+            fun(_) ->
+                couch_stats_collector:track_process_count(hoopla)
+            end, lists:seq(1,N)),
+        Self ! reporting,
+        receive
+            sepuku -> ok
+        end
+    end),
+    receive reporting -> ok end,
+    {Pid, couch_stats_collector:get(hoopla)}.
+
+repeat(_, 0) ->
+    ok;
+repeat(Fun, Count) ->
+    Fun(),
+    repeat(Fun, Count-1).


[19/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 140-attachments-comp.t etap test suite to eunit

- Merge into couchdb_attachments_tests suite;
- Add PUT requests to test_request util;
- Remove dependency from files outside fixtures directory;
- Group test cases to reduce amount of duplicate code;
- Fix hidden issue with gzip encoding: for encoding_length stub info
  check using zlib:gzip on 2KiB+ files leads to mismatch by 2-4 bytes
  and this difference grows with file size. Using gzip fun code from
  couch_stream solves the issue.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/31b76762
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/31b76762
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/31b76762

Branch: refs/heads/1963-eunit-bigcouch
Commit: 31b76762682011c6b52067437cb380705f7eeb31
Parents: 60ed292
Author: Alexander Shorin <kx...@apache.org>
Authored: Tue Jun 3 01:51:46 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:44 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_attachments_tests.erl | 380 +++++++++++++++++++++++-
 test/couchdb/fixtures/logo.png             | Bin 0 -> 3010 bytes
 test/couchdb/test_request.erl              |   9 +-
 3 files changed, 385 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/31b76762/test/couchdb/couchdb_attachments_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_attachments_tests.erl b/test/couchdb/couchdb_attachments_tests.erl
index aef1873..cf59785 100644
--- a/test/couchdb/couchdb_attachments_tests.erl
+++ b/test/couchdb/couchdb_attachments_tests.erl
@@ -15,13 +15,23 @@
 -include("couch_eunit.hrl").
 -include_lib("couchdb/couch_db.hrl").
 
+-define(COMPRESSION_LEVEL, 8).
+-define(ATT_BIN_NAME, <<"logo.png">>).
+-define(ATT_TXT_NAME, <<"file.erl">>).
+-define(FIXTURE_PNG, filename:join([?FIXTURESDIR, "logo.png"])).
+-define(FIXTURE_TXT, ?FILE).
 -define(TIMEOUT, 1000).
+-define(TIMEOUT_EUNIT, 10).
 -define(TIMEWAIT, 100).
 -define(i2l(I), integer_to_list(I)).
 
 
 start() ->
     {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    % ensure in default compression settings for attachments_compression_tests
+    couch_config:set("attachments", "compression_level",
+                     ?i2l(?COMPRESSION_LEVEL), false),
+    couch_config:set("attachments", "compressible_types", "text/*", false),
     Pid.
 
 stop(Pid) ->
@@ -43,7 +53,35 @@ setup() ->
     Host = Addr ++ ":" ++ ?i2l(Port),
     {Host, ?b2l(DbName)}.
 
+setup({binary, standalone}) ->
+    {Host, DbName} = setup(),
+        setup_att(fun create_standalone_png_att/2, Host, DbName, ?FIXTURE_PNG);
+setup({text, standalone}) ->
+    {Host, DbName} = setup(),
+    setup_att(fun create_standalone_text_att/2, Host, DbName, ?FIXTURE_TXT);
+setup({binary, inline}) ->
+    {Host, DbName} = setup(),
+    setup_att(fun create_inline_png_att/2, Host, DbName, ?FIXTURE_PNG);
+setup({text, inline}) ->
+    {Host, DbName} = setup(),
+    setup_att(fun create_inline_text_att/2, Host, DbName, ?FIXTURE_TXT);
+setup(compressed) ->
+    {Host, DbName} = setup(),
+    setup_att(fun create_already_compressed_att/2, Host, DbName, ?FIXTURE_TXT).
+setup_att(Fun, Host, DbName, File) ->
+    HttpHost = "http://" ++ Host,
+    AttUrl = Fun(HttpHost, DbName),
+    {ok, Data} = file:read_file(File),
+    DocUrl = string:join([HttpHost, DbName, "doc"], "/"),
+    Helpers = {DbName, DocUrl, AttUrl},
+    {Data, Helpers}.
+
+teardown(_, {_, {DbName, _, _}}) ->
+    teardown(DbName).
+
 teardown({_, DbName}) ->
+    teardown(DbName);
+teardown(DbName) ->
     ok = couch_server:delete(?l2b(DbName), []),
     ok.
 
@@ -55,7 +93,8 @@ attachments_test_() ->
             setup,
             fun start/0, fun stop/1,
             [
-                attachments_md5_tests()
+                attachments_md5_tests(),
+                attachments_compression_tests()
             ]
         }
     }.
@@ -79,6 +118,67 @@ attachments_md5_tests() ->
         }
     }.
 
+attachments_compression_tests() ->
+    Funs = [
+         fun should_get_att_without_accept_gzip_encoding/2,
+         fun should_get_att_with_accept_gzip_encoding/2,
+         fun should_get_att_with_accept_deflate_encoding/2,
+         fun should_return_406_response_on_unsupported_encoding/2,
+         fun should_get_doc_with_att_data/2,
+         fun should_get_doc_with_att_data_stub/2
+    ],
+    {
+        "Attachments compression tests",
+        [
+            {
+                "Created via Attachments API",
+                created_attachments_compression_tests(standalone, Funs)
+            },
+            {
+                "Created inline via Document API",
+                created_attachments_compression_tests(inline, Funs)
+            },
+            {
+                "Created already been compressed via Attachments API",
+                {
+                    foreachx,
+                    fun setup/1, fun teardown/2,
+                    [{compressed, Fun} || Fun <- Funs]
+                }
+            },
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    fun should_not_create_compressed_att_with_deflate_encoding/1,
+                    fun should_not_create_compressed_att_with_compress_encoding/1,
+                    fun should_create_compressible_att_with_ctype_params/1
+                ]
+            }
+        ]
+    }.
+
+created_attachments_compression_tests(Mod, Funs) ->
+    [
+        {
+            "Compressiable attachments",
+            {
+                foreachx,
+                fun setup/1, fun teardown/2,
+                [{{text, Mod}, Fun} || Fun <- Funs]
+            }
+        },
+        {
+            "Uncompressiable attachments",
+            {
+                foreachx,
+                fun setup/1, fun teardown/2,
+                [{{binary, Mod}, Fun} || Fun <- Funs]
+            }
+        }
+    ].
+
+
 
 should_upload_attachment_without_md5({Host, DbName}) ->
     ?_test(begin
@@ -212,10 +312,218 @@ should_reject_chunked_attachment_with_invalid_md5_trailer({Host, DbName}) ->
         ],
         {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
         ?assertEqual(400, Code),
-        ?assertEqual(<<"content_md5_mismatch">>,
-                     get_json(Json, [<<"error">>]))
+        ?assertEqual(<<"content_md5_mismatch">>, get_json(Json, [<<"error">>]))
+    end).
+
+should_get_att_without_accept_gzip_encoding(_, {Data, {_, _, AttUrl}}) ->
+    ?_test(begin
+        {ok, Code, Headers, Body} = test_request:get(AttUrl),
+        ?assertEqual(200, Code),
+        ?assertNot(lists:member({"Content-Encoding", "gzip"}, Headers)),
+        ?assertEqual(Data, iolist_to_binary(Body))
+    end).
+
+should_get_att_with_accept_gzip_encoding(compressed, {Data, {_, _, AttUrl}}) ->
+    ?_test(begin
+        {ok, Code, Headers, Body} = test_request:get(
+            AttUrl, [{"Accept-Encoding", "gzip"}]),
+        ?assertEqual(200, Code),
+        ?assert(lists:member({"Content-Encoding", "gzip"}, Headers)),
+        ?assertEqual(Data, zlib:gunzip(iolist_to_binary(Body)))
+    end);
+should_get_att_with_accept_gzip_encoding({text, _}, {Data, {_, _, AttUrl}}) ->
+    ?_test(begin
+        {ok, Code, Headers, Body} = test_request:get(
+            AttUrl, [{"Accept-Encoding", "gzip"}]),
+        ?assertEqual(200, Code),
+        ?assert(lists:member({"Content-Encoding", "gzip"}, Headers)),
+        ?assertEqual(Data, zlib:gunzip(iolist_to_binary(Body)))
+    end);
+should_get_att_with_accept_gzip_encoding({binary, _}, {Data, {_, _, AttUrl}}) ->
+    ?_test(begin
+        {ok, Code, Headers, Body} = test_request:get(
+            AttUrl, [{"Accept-Encoding", "gzip"}]),
+        ?assertEqual(200, Code),
+        ?assertEqual(undefined,
+                     couch_util:get_value("Content-Encoding", Headers)),
+        ?assertEqual(Data, iolist_to_binary(Body))
+    end).
+
+should_get_att_with_accept_deflate_encoding(_, {Data, {_, _, AttUrl}}) ->
+    ?_test(begin
+        {ok, Code, Headers, Body} = test_request:get(
+            AttUrl, [{"Accept-Encoding", "deflate"}]),
+        ?assertEqual(200, Code),
+        ?assertEqual(undefined,
+                     couch_util:get_value("Content-Encoding", Headers)),
+        ?assertEqual(Data, iolist_to_binary(Body))
+    end).
+
+should_return_406_response_on_unsupported_encoding(_, {_, {_, _, AttUrl}}) ->
+    ?_assertEqual(406,
+        begin
+            {ok, Code, _, _} = test_request:get(
+                AttUrl, [{"Accept-Encoding", "deflate, *;q=0"}]),
+            Code
+        end).
+
+should_get_doc_with_att_data(compressed, {Data, {_, DocUrl, _}}) ->
+    ?_test(begin
+        Url = DocUrl ++ "?attachments=true",
+        {ok, Code, _, Body} = test_request:get(
+            Url, [{"Accept", "application/json"}]),
+        ?assertEqual(200, Code),
+        Json = ejson:decode(Body),
+        AttJson = couch_util:get_nested_json_value(
+            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+        AttData = couch_util:get_nested_json_value(
+            AttJson, [<<"data">>]),
+        ?assertEqual(
+            <<"text/plain">>,
+            couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
+        ?assertEqual(Data, base64:decode(AttData))
+    end);
+should_get_doc_with_att_data({text, _}, {Data, {_, DocUrl, _}}) ->
+    ?_test(begin
+        Url = DocUrl ++ "?attachments=true",
+        {ok, Code, _, Body} = test_request:get(
+            Url, [{"Accept", "application/json"}]),
+        ?assertEqual(200, Code),
+        Json = ejson:decode(Body),
+        AttJson = couch_util:get_nested_json_value(
+            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+        AttData = couch_util:get_nested_json_value(
+            AttJson, [<<"data">>]),
+        ?assertEqual(
+            <<"text/plain">>,
+            couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
+        ?assertEqual(Data, base64:decode(AttData))
+    end);
+should_get_doc_with_att_data({binary, _}, {Data, {_, DocUrl, _}}) ->
+    ?_test(begin
+        Url = DocUrl ++ "?attachments=true",
+        {ok, Code, _, Body} = test_request:get(
+            Url, [{"Accept", "application/json"}]),
+        ?assertEqual(200, Code),
+        Json = ejson:decode(Body),
+        AttJson = couch_util:get_nested_json_value(
+            Json, [<<"_attachments">>, ?ATT_BIN_NAME]),
+        AttData = couch_util:get_nested_json_value(
+            AttJson, [<<"data">>]),
+        ?assertEqual(
+            <<"image/png">>,
+            couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
+        ?assertEqual(Data, base64:decode(AttData))
+    end).
+
+should_get_doc_with_att_data_stub(compressed, {Data, {_, DocUrl, _}}) ->
+    ?_test(begin
+        Url = DocUrl ++ "?att_encoding_info=true",
+        {ok, Code, _, Body} = test_request:get(
+            Url, [{"Accept", "application/json"}]),
+        ?assertEqual(200, Code),
+        Json = ejson:decode(Body),
+        {AttJson} = couch_util:get_nested_json_value(
+            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+        ?assertEqual(<<"gzip">>,
+                     couch_util:get_value(<<"encoding">>, AttJson)),
+        AttLength = couch_util:get_value(<<"length">>, AttJson),
+        EncLength = couch_util:get_value(<<"encoded_length">>, AttJson),
+        ?assertEqual(AttLength, EncLength),
+        ?assertEqual(iolist_size(zlib:gzip(Data)), AttLength)
+    end);
+should_get_doc_with_att_data_stub({text, _}, {Data, {_, DocUrl, _}}) ->
+    ?_test(begin
+        Url = DocUrl ++ "?att_encoding_info=true",
+        {ok, Code, _, Body} = test_request:get(
+            Url, [{"Accept", "application/json"}]),
+        ?assertEqual(200, Code),
+        Json = ejson:decode(Body),
+        {AttJson} = couch_util:get_nested_json_value(
+            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+        ?assertEqual(<<"gzip">>,
+                     couch_util:get_value(<<"encoding">>, AttJson)),
+        AttEncLength = iolist_size(gzip(Data)),
+        ?assertEqual(AttEncLength,
+                     couch_util:get_value(<<"encoded_length">>, AttJson)),
+        ?assertEqual(byte_size(Data),
+                     couch_util:get_value(<<"length">>, AttJson))
+    end);
+should_get_doc_with_att_data_stub({binary, _}, {Data, {_, DocUrl, _}}) ->
+    ?_test(begin
+        Url = DocUrl ++ "?att_encoding_info=true",
+        {ok, Code, _, Body} = test_request:get(
+            Url, [{"Accept", "application/json"}]),
+        ?assertEqual(200, Code),
+        Json = ejson:decode(Body),
+        {AttJson} = couch_util:get_nested_json_value(
+            Json, [<<"_attachments">>, ?ATT_BIN_NAME]),
+        ?assertEqual(undefined,
+                     couch_util:get_value(<<"encoding">>, AttJson)),
+        ?assertEqual(undefined,
+                     couch_util:get_value(<<"encoded_length">>, AttJson)),
+        ?assertEqual(byte_size(Data),
+                     couch_util:get_value(<<"length">>, AttJson))
     end).
 
+should_not_create_compressed_att_with_deflate_encoding({Host, DbName}) ->
+    ?_assertEqual(415,
+        begin
+            HttpHost = "http://" ++ Host,
+            AttUrl = string:join([HttpHost, DbName, ?docid(), "file.txt"], "/"),
+            {ok, Data} = file:read_file(?FIXTURE_TXT),
+            Body = zlib:compress(Data),
+            Headers = [
+                {"Content-Encoding", "deflate"},
+                {"Content-Type", "text/plain"}
+            ],
+            {ok, Code, _, _} = test_request:put(AttUrl, Headers, Body),
+            Code
+        end).
+
+should_not_create_compressed_att_with_compress_encoding({Host, DbName}) ->
+    % 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
+    ?_assertEqual(415,
+        begin
+            HttpHost = "http://" ++ Host,
+            AttUrl = string:join([HttpHost, DbName, ?docid(), "file.txt"], "/"),
+            {ok, Data} = file:read_file(?FIXTURE_TXT),
+            Headers = [
+                {"Content-Encoding", "compress"},
+                {"Content-Type", "text/plain"}
+            ],
+            {ok, Code, _, _} = test_request:put(AttUrl, Headers, Data),
+            Code
+        end).
+
+should_create_compressible_att_with_ctype_params({Host, DbName}) ->
+    {timeout, ?TIMEOUT_EUNIT, ?_test(begin
+        HttpHost = "http://" ++ Host,
+        DocUrl = string:join([HttpHost, DbName, ?docid()], "/"),
+        AttUrl = string:join([DocUrl, ?b2l(?ATT_TXT_NAME)], "/"),
+        {ok, Data} = file:read_file(?FIXTURE_TXT),
+        Headers = [{"Content-Type", "text/plain; charset=UTF-8"}],
+        {ok, Code0, _, _} = test_request:put(AttUrl, Headers, Data),
+        ?assertEqual(201, Code0),
+
+        {ok, Code1, _, Body} = test_request:get(
+            DocUrl ++ "?att_encoding_info=true"),
+        ?assertEqual(200, Code1),
+        Json = ejson:decode(Body),
+        {AttJson} = couch_util:get_nested_json_value(
+            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+        ?assertEqual(<<"gzip">>,
+                     couch_util:get_value(<<"encoding">>, AttJson)),
+        AttEncLength = iolist_size(gzip(Data)),
+        ?assertEqual(AttEncLength,
+                     couch_util:get_value(<<"encoded_length">>, AttJson)),
+        ?assertEqual(byte_size(Data),
+                     couch_util:get_value(<<"length">>, AttJson))
+    end)}.
+
 
 get_json(Json, Path) ->
     couch_util:get_nested_json_value(Json, Path).
@@ -262,3 +570,69 @@ request(Method, Url, Headers, Body) ->
         erlang:decode_packet(http, Header, []),
     Json = ejson:decode(Body1),
     {ok, Code, Json}.
+
+create_standalone_text_att(Host, DbName) ->
+    {ok, Data} = file:read_file(?FIXTURE_TXT),
+    Url = string:join([Host, DbName, "doc", ?b2l(?ATT_TXT_NAME)], "/"),
+    {ok, Code, _Headers, _Body} = test_request:put(
+        Url, [{"Content-Type", "text/plain"}], Data),
+    ?assertEqual(201, Code),
+    Url.
+
+create_standalone_png_att(Host, DbName) ->
+    {ok, Data} = file:read_file(?FIXTURE_PNG),
+    Url = string:join([Host, DbName, "doc", ?b2l(?ATT_BIN_NAME)], "/"),
+    {ok, Code, _Headers, _Body} = test_request:put(
+        Url, [{"Content-Type", "image/png"}], Data),
+    ?assertEqual(201, Code),
+    Url.
+
+create_inline_text_att(Host, DbName) ->
+    {ok, Data} = file:read_file(?FIXTURE_TXT),
+    Url = string:join([Host, DbName, "doc"], "/"),
+    Doc = {[
+        {<<"_attachments">>, {[
+            {?ATT_TXT_NAME, {[
+                {<<"content_type">>, <<"text/plain">>},
+                {<<"data">>, base64:encode(Data)}
+            ]}
+        }]}}
+    ]},
+    {ok, Code, _Headers, _Body} = test_request:put(
+        Url, [{"Content-Type", "application/json"}], ejson:encode(Doc)),
+    ?assertEqual(201, Code),
+    string:join([Url, ?b2l(?ATT_TXT_NAME)], "/").
+
+create_inline_png_att(Host, DbName) ->
+    {ok, Data} = file:read_file(?FIXTURE_PNG),
+    Url = string:join([Host, DbName, "doc"], "/"),
+    Doc = {[
+        {<<"_attachments">>, {[
+            {?ATT_BIN_NAME, {[
+                {<<"content_type">>, <<"image/png">>},
+                {<<"data">>, base64:encode(Data)}
+            ]}
+        }]}}
+    ]},
+    {ok, Code, _Headers, _Body} = test_request:put(
+        Url, [{"Content-Type", "application/json"}], ejson:encode(Doc)),
+    ?assertEqual(201, Code),
+    string:join([Url, ?b2l(?ATT_BIN_NAME)], "/").
+
+create_already_compressed_att(Host, DbName) ->
+    {ok, Data} = file:read_file(?FIXTURE_TXT),
+    Url = string:join([Host, DbName, "doc", ?b2l(?ATT_TXT_NAME)], "/"),
+    {ok, Code, _Headers, _Body} = test_request:put(
+        Url, [{"Content-Type", "text/plain"}, {"Content-Encoding", "gzip"}],
+        zlib:gzip(Data)),
+    ?assertEqual(201, Code),
+    Url.
+
+gzip(Data) ->
+    Z = zlib:open(),
+    ok = zlib:deflateInit(Z, ?COMPRESSION_LEVEL, deflated, 16 + 15, 8, default),
+    zlib:deflate(Z, Data),
+    Last = zlib:deflate(Z, [], finish),
+    ok = zlib:deflateEnd(Z),
+    ok = zlib:close(Z),
+    Last.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/31b76762/test/couchdb/fixtures/logo.png
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/logo.png b/test/couchdb/fixtures/logo.png
new file mode 100644
index 0000000..d21ac02
Binary files /dev/null and b/test/couchdb/fixtures/logo.png differ

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/31b76762/test/couchdb/test_request.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/test_request.erl b/test/couchdb/test_request.erl
index 7abb92f..d6725ea 100644
--- a/test/couchdb/test_request.erl
+++ b/test/couchdb/test_request.erl
@@ -12,7 +12,7 @@
 
 -module(test_request).
 
--export([get/1, get/2]).
+-export([get/1, get/2, put/2, put/3]).
 -export([request/3, request/4]).
 
 get(Url) ->
@@ -22,6 +22,13 @@ get(Url, Headers) ->
     request(get, Url, Headers).
 
 
+put(Url, Body) ->
+    request(put, Url, [], Body).
+
+put(Url, Headers, Body) ->
+    request(put, Url, Headers, Body).
+
+
 request(Method, Url, Headers) ->
     request(Method, Url, Headers, []).
 


[44/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
WIP: add couch_eunit.hrl


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/95bfc036
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/95bfc036
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/95bfc036

Branch: refs/heads/1963-eunit-bigcouch
Commit: 95bfc0360eddaddfe82061fa66c2189f1e260bc5
Parents: 6179af6
Author: Russell Branca <ch...@apache.org>
Authored: Fri Aug 15 13:12:06 2014 -0700
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:24:06 2014 -0700

----------------------------------------------------------------------
 include/couch_eunit.hrl | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/95bfc036/include/couch_eunit.hrl
----------------------------------------------------------------------
diff --git a/include/couch_eunit.hrl b/include/couch_eunit.hrl
new file mode 100644
index 0000000..83e0d68
--- /dev/null
+++ b/include/couch_eunit.hrl
@@ -0,0 +1,44 @@
+% 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_lib("eunit/include/eunit.hrl").
+
+-define(BUILDDIR, "/Users/russell/src/couchdb").
+-define(SOURCEDIR, "/Users/russell/src/couchdb/src/couch").
+-define(CONFIG_CHAIN, [
+    filename:join([?BUILDDIR, "etc", "couchdb", "default_dev.ini"]),
+    filename:join([?BUILDDIR, "etc", "couchdb", "local_dev.ini"]),
+    filename:join([?BUILDDIR, "etc", "couchdb", "eunit.ini"])]).
+-define(FIXTURESDIR,
+    filename:join([?SOURCEDIR, "test", "fixtures"])).
+-define(TEMPDIR,
+    filename:join([?BUILDDIR, "test", "temp"])).
+
+-define(tempfile,
+    fun() ->
+        {A, B, C} = erlang:now(),
+        N = node(),
+        FileName = lists:flatten(io_lib:format("~p-~p.~p.~p", [N, A, B, C])),
+        filename:join([?TEMPDIR, FileName])
+    end).
+-define(tempdb,
+    fun() ->
+            Nums = tuple_to_list(erlang:now()),
+            Prefix = "eunit-test-db",
+            Suffix = lists:concat([integer_to_list(Num) || Num <- Nums]),
+            list_to_binary(Prefix ++ "-" ++ Suffix)
+    end).
+-define(docid,
+    fun() ->
+        {A, B, C} = erlang:now(),
+        lists:flatten(io_lib:format("~p~p~p", [A, B, C]))
+    end).


[25/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 210-os-proc-pool.t etap test suite to eunit


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/be1386af
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/be1386af
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/be1386af

Branch: refs/heads/1963-eunit-bigcouch
Commit: be1386af5ab3bfdcfe5d59421c1859076af4bb7b
Parents: ffc32ef
Author: Alexander Shorin <kx...@apache.org>
Authored: Sun Jun 8 13:08:50 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:44 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_os_proc_pool.erl | 179 +++++++++++++++++++++++++++++
 1 file changed, 179 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/be1386af/test/couchdb/couchdb_os_proc_pool.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_os_proc_pool.erl b/test/couchdb/couchdb_os_proc_pool.erl
new file mode 100644
index 0000000..1bb266e
--- /dev/null
+++ b/test/couchdb/couchdb_os_proc_pool.erl
@@ -0,0 +1,179 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_os_proc_pool).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(TIMEOUT, 3000).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    couch_config:set("query_server_config", "os_process_limit", "3", false),
+    Pid.
+
+stop(Pid) ->
+    couch_server_sup:stop(),
+    erlang:monitor(process, Pid),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+
+os_proc_pool_test_() ->
+    {
+        "OS processes pool tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            [
+                should_block_new_proc_on_full_pool(),
+                should_free_slot_on_proc_unexpected_exit()
+            ]
+        }
+    }.
+
+
+should_block_new_proc_on_full_pool() ->
+    ?_test(begin
+        Client1 = spawn_client(),
+        Client2 = spawn_client(),
+        Client3 = spawn_client(),
+
+        ?assertEqual(ok, ping_client(Client1)),
+        ?assertEqual(ok, ping_client(Client2)),
+        ?assertEqual(ok, ping_client(Client3)),
+
+        Proc1 = get_client_proc(Client1, "1"),
+        Proc2 = get_client_proc(Client2, "2"),
+        Proc3 = get_client_proc(Client3, "3"),
+
+        ?assertNotEqual(Proc1, Proc2),
+        ?assertNotEqual(Proc2, Proc3),
+        ?assertNotEqual(Proc3, Proc1),
+
+        Client4 = spawn_client(),
+        ?assertEqual(timeout, ping_client(Client4)),
+
+        ?assertEqual(ok, stop_client(Client1)),
+        ?assertEqual(ok, ping_client(Client4)),
+
+        Proc4 = get_client_proc(Client4, "4"),
+        ?assertEqual(Proc1, Proc4),
+
+        lists:map(fun(C) ->
+            ?assertEqual(ok, stop_client(C))
+        end, [Client2, Client3, Client4])
+    end).
+
+should_free_slot_on_proc_unexpected_exit() ->
+    ?_test(begin
+        Client1 = spawn_client(),
+        Client2 = spawn_client(),
+        Client3 = spawn_client(),
+
+        ?assertEqual(ok, ping_client(Client1)),
+        ?assertEqual(ok, ping_client(Client2)),
+        ?assertEqual(ok, ping_client(Client3)),
+
+        Proc1 = get_client_proc(Client1, "1"),
+        Proc2 = get_client_proc(Client2, "2"),
+        Proc3 = get_client_proc(Client3, "3"),
+
+        ?assertNotEqual(Proc1, Proc2),
+        ?assertNotEqual(Proc2, Proc3),
+        ?assertNotEqual(Proc3, Proc1),
+
+        ?assertEqual(ok, kill_client(Client1)),
+
+        Client4 = spawn_client(),
+        ?assertEqual(ok, ping_client(Client4)),
+
+        Proc4 = get_client_proc(Client4, "4"),
+        ?assertNotEqual(Proc4, Proc1),
+        ?assertNotEqual(Proc2, Proc4),
+        ?assertNotEqual(Proc3, Proc4),
+
+        lists:map(fun(C) ->
+            ?assertEqual(ok, stop_client(C))
+        end, [Client2, Client3, Client4])
+    end).
+
+
+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 ?TIMEOUT ->
+        timeout
+    end.
+
+get_client_proc({Pid, Ref}, ClientName) ->
+    Pid ! get_proc,
+    receive
+        {proc, Ref, Proc} -> Proc
+    after ?TIMEOUT ->
+        erlang:error({assertion_failed,
+                     [{module, ?MODULE},
+                      {line, ?LINE},
+                      {reason, "Timeout getting client "
+                               ++ ClientName ++ " proc"}]})
+    end.
+
+stop_client({Pid, Ref}) ->
+    Pid ! stop,
+    receive
+        {stop, Ref} ->
+            ok
+    after ?TIMEOUT ->
+        timeout
+    end.
+
+kill_client({Pid, Ref}) ->
+    Pid ! die,
+    receive
+        {die, Ref} ->
+            ok
+    after ?TIMEOUT ->
+        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.


[50/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
WIP: Add test_util

The addition of start_config here is suboptimal, but starting couch
requires config to be running, and a number of the tests also want
config running, so this is a (temporary?) workaround to make sure you
can always get a fresh config instance.

Currently the request function is unused, but I think we should
migrate tests making requests to use it.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/dc041fe1
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/dc041fe1
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/dc041fe1

Branch: refs/heads/1963-eunit-bigcouch
Commit: dc041fe142eea70202263300f396a2f1a597fc11
Parents: 7114666
Author: Russell Branca <ch...@apache.org>
Authored: Fri Aug 15 12:56:57 2014 -0700
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:24:06 2014 -0700

----------------------------------------------------------------------
 src/test_util.erl | 141 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 141 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dc041fe1/src/test_util.erl
----------------------------------------------------------------------
diff --git a/src/test_util.erl b/src/test_util.erl
new file mode 100644
index 0000000..dfc915f
--- /dev/null
+++ b/src/test_util.erl
@@ -0,0 +1,141 @@
+% 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]).
+%% -export([run/2]).
+-export([request/3, request/4]).
+-export([start_couch/0, start_couch/1, stop_couch/0, stop_couch/1]).
+-export([start_config/1, stop_config/1]).
+
+
+srcdir() ->
+    code:priv_dir(couch) ++ "/../../".
+
+builddir() ->
+    code:priv_dir(couch) ++ "/../../../".
+
+init_code_path() ->
+    Paths = [
+        "etap",
+        "couchdb",
+        "ejson",
+        "oauth",
+        "ibrowse",
+        "mochiweb",
+        "snappy"
+    ],
+    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("test/random_port.ini"),
+        build_file("etc/couchdb/local_dev.ini")
+    ].
+
+
+request(Url, Headers, Method) ->
+    request(Url, Headers, Method, []).
+
+request(Url, Headers, Method, Body) ->
+    request(Url, Headers, Method, Body, 3).
+
+request(_Url, _Headers, _Method, _Body, 0) ->
+    {error, request_failed};
+request(Url, Headers, Method, Body, N) ->
+    case code:is_loaded(ibrowse) of
+    false ->
+        {ok, _} = ibrowse:start();
+    _ ->
+        ok
+    end,
+    case ibrowse:send_req(Url, Headers, Method, Body) of
+    {ok, Code0, RespHeaders, RespBody0} ->
+        Code = list_to_integer(Code0),
+        RespBody = iolist_to_binary(RespBody0),
+        {ok, Code, RespHeaders, RespBody};
+    {error, {'EXIT', {normal, _}}} ->
+        % Connection closed right after a successful request that
+        % used the same connection.
+        request(Url, Headers, Method, Body, N - 1);
+    Error ->
+        Error
+    end.
+
+
+start_couch() ->
+    start_couch(config_files()).
+
+
+start_couch(IniFiles) ->
+    ok = application:set_env(config, ini_files, IniFiles),
+    ok = lager:start(),
+    ok = start_applications([config, couch]),
+    ok.
+
+
+stop_couch() ->
+    ok = application:stop(couch),
+    ok = application:stop(lager),
+    ok = application:stop(config),
+    ok.
+
+
+stop_couch(_) ->
+    stop_couch().
+
+
+start_applications([]) ->
+    ok;
+start_applications([App|Apps]) ->
+    case application:start(App) of
+        {error, {already_started, _}} ->
+            ok;
+        {error, {not_started, Dep}} ->
+            start_applications([Dep, App | Apps]);
+        ok ->
+            ok
+    end,
+    start_applications(Apps).
+
+
+start_config(Chain) ->
+    case config:start_link(Chain) of
+        {ok, Pid} ->
+            {ok, Pid};
+        {error, {already_started, OldPid}}  ->
+            ok = stop_config(OldPid),
+            start_config(Chain)
+    end.
+
+
+stop_config(Pid) ->
+    Timeout = 1000,
+    erlang:monitor(process, Pid),
+    config:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after Timeout ->
+        throw({timeout_error, config_stop})
+    end.


[15/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 170-os-daemons.t etap test suite to eunit


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/77a6a902
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/77a6a902
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/77a6a902

Branch: refs/heads/1963-eunit-bigcouch
Commit: 77a6a90255c94f0f2b741fd75d5c208154b75168
Parents: ab99d56
Author: Alexander Shorin <kx...@apache.org>
Authored: Tue Jun 3 12:32:02 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:44 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_os_daemons_tests.erl      | 145 ++++++++++++++++++++
 test/couchdb/fixtures/os_daemon_looper.escript |  26 ++++
 2 files changed, 171 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/77a6a902/test/couchdb/couchdb_os_daemons_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_os_daemons_tests.erl b/test/couchdb/couchdb_os_daemons_tests.erl
new file mode 100644
index 0000000..1f9f6be
--- /dev/null
+++ b/test/couchdb/couchdb_os_daemons_tests.erl
@@ -0,0 +1,145 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_os_daemons_tests).
+
+-include("couch_eunit.hrl").
+
+%% keep in sync with couchdb/couch_os_daemons.erl
+-record(daemon, {
+    port,
+    name,
+    cmd,
+    kill,
+    status=running,
+    cfg_patterns=[],
+    errors=[],
+    buf=[]
+}).
+
+-define(DAEMON_LOOPER, "os_daemon_looper.escript").
+-define(DELAY, 100).
+-define(TIMEOUT, 1000).
+
+
+setup(DName) ->
+    {ok, CfgPid} = couch_config:start_link(?CONFIG_CHAIN),
+    {ok, OsDPid} = couch_os_daemons:start_link(),
+    couch_config:set("os_daemons", DName,
+                     filename:join([?FIXTURESDIR, DName]), false),
+    timer:sleep(?DELAY),  % sleep a bit to let daemon set kill flag
+    {CfgPid, OsDPid}.
+
+teardown(_, {CfgPid, OsDPid}) ->
+    erlang:monitor(process, CfgPid),
+    couch_config:stop(),
+    receive
+        {'DOWN', _, _, CfgPid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, config_stop})
+    end,
+
+    erlang:monitor(process, OsDPid),
+    exit(OsDPid, normal),
+    receive
+        {'DOWN', _, _, OsDPid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, os_daemon_stop})
+    end.
+
+
+os_daemons_test_() ->
+    {
+        "OS Daemons tests",
+        {
+            foreachx,
+            fun setup/1, fun teardown/2,
+            [{?DAEMON_LOOPER, Fun} || Fun <- [
+                fun should_check_daemon/2,
+                fun should_check_daemon_table_form/2,
+                fun should_clean_tables_on_daemon_remove/2,
+                fun should_spawn_multiple_daemons/2,
+                fun should_keep_alive_one_daemon_on_killing_other/2
+            ]]
+        }
+    }.
+
+
+should_check_daemon(DName, _) ->
+    ?_test(begin
+        {ok, [D]} = couch_os_daemons:info([table]),
+        check_daemon(D, DName)
+    end).
+
+should_check_daemon_table_form(DName, _) ->
+    ?_test(begin
+        {ok, Tab} = couch_os_daemons:info(),
+        [D] = ets:tab2list(Tab),
+        check_daemon(D, DName)
+    end).
+
+should_clean_tables_on_daemon_remove(DName, _) ->
+    ?_test(begin
+        couch_config:delete("os_daemons", DName, false),
+        {ok, Tab2} = couch_os_daemons:info(),
+        ?_assertEqual([], ets:tab2list(Tab2))
+    end).
+
+should_spawn_multiple_daemons(DName, _) ->
+    ?_test(begin
+        couch_config:set("os_daemons", "bar",
+                         filename:join([?FIXTURESDIR, DName]), false),
+        couch_config:set("os_daemons", "baz",
+                         filename:join([?FIXTURESDIR, DName]), false),
+        timer:sleep(?DELAY),
+        {ok, Daemons} = couch_os_daemons:info([table]),
+        lists:foreach(fun(D) ->
+            check_daemon(D)
+        end, Daemons),
+        {ok, Tab} = couch_os_daemons:info(),
+        lists:foreach(fun(D) ->
+            check_daemon(D)
+        end, ets:tab2list(Tab))
+    end).
+
+should_keep_alive_one_daemon_on_killing_other(DName, _) ->
+    ?_test(begin
+        couch_config:set("os_daemons", "bar",
+                         filename:join([?FIXTURESDIR, DName]), false),
+        timer:sleep(?DELAY),
+        {ok, Daemons} = couch_os_daemons:info([table]),
+        lists:foreach(fun(D) ->
+            check_daemon(D)
+        end, Daemons),
+
+        couch_config:delete("os_daemons", "bar", false),
+        timer:sleep(?DELAY),
+        {ok, [D2]} = couch_os_daemons:info([table]),
+        check_daemon(D2, DName),
+
+        {ok, Tab} = couch_os_daemons:info(),
+        [T] = ets:tab2list(Tab),
+        check_daemon(T, DName)
+    end).
+
+
+check_daemon(D) ->
+    check_daemon(D, D#daemon.name).
+
+check_daemon(D, Name) ->
+    ?assert(is_port(D#daemon.port)),
+    ?assertEqual(Name, D#daemon.name),
+    ?assertNotEqual(undefined, D#daemon.kill),
+    ?assertEqual([], D#daemon.errors),
+    ?assertEqual([], D#daemon.buf).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/77a6a902/test/couchdb/fixtures/os_daemon_looper.escript
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/os_daemon_looper.escript b/test/couchdb/fixtures/os_daemon_looper.escript
new file mode 100755
index 0000000..73974e9
--- /dev/null
+++ b/test/couchdb/fixtures/os_daemon_looper.escript
@@ -0,0 +1,26 @@
+#! /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().


[48/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Delete tests for the no longer present couch_ref_counter.erl


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/bdc3ea70
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/bdc3ea70
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/bdc3ea70

Branch: refs/heads/1963-eunit-bigcouch
Commit: bdc3ea7047b3f651909c9dad22f58371579c50d6
Parents: 0456db3
Author: Russell Branca <ch...@apache.org>
Authored: Wed Aug 13 14:24:28 2014 -0700
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:24:06 2014 -0700

----------------------------------------------------------------------
 test/couch_ref_counter_tests.erl | 107 ----------------------------------
 1 file changed, 107 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/bdc3ea70/test/couch_ref_counter_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_ref_counter_tests.erl b/test/couch_ref_counter_tests.erl
deleted file mode 100644
index 0217623..0000000
--- a/test/couch_ref_counter_tests.erl
+++ /dev/null
@@ -1,107 +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(couch_ref_counter_tests).
-
--include_lib("couch/include/couch_eunit.hrl").
--include_lib("couch/include/couch_db.hrl").
-
--define(TIMEOUT, 1000).
-
-
-setup() ->
-    {ok, RefCtr} = couch_ref_counter:start([]),
-    ChildPid = spawn(fun() -> loop() end),
-    {RefCtr, ChildPid}.
-
-teardown({_, ChildPid}) ->
-    erlang:monitor(process, ChildPid),
-    ChildPid ! close,
-    wait().
-
-
-couch_ref_counter_test_() ->
-    {
-        "CouchDB reference counter tests",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                fun should_initialize_with_calling_process_as_referrer/1,
-                fun should_ignore_unknown_pid/1,
-                fun should_increment_counter_on_pid_add/1,
-                fun should_not_increase_counter_on_readding_same_pid/1,
-                fun should_drop_ref_for_double_added_pid/1,
-                fun should_decrement_counter_on_pid_drop/1,
-                fun should_add_after_drop/1,
-                fun should_decrement_counter_on_process_exit/1
-
-            ]
-        }
-    }.
-
-
-should_initialize_with_calling_process_as_referrer({RefCtr, _}) ->
-    ?_assertEqual(1, couch_ref_counter:count(RefCtr)).
-
-should_ignore_unknown_pid({RefCtr, ChildPid}) ->
-    ?_assertEqual(ok, couch_ref_counter:drop(RefCtr, ChildPid)).
-
-should_increment_counter_on_pid_add({RefCtr, ChildPid}) ->
-    couch_ref_counter:add(RefCtr, ChildPid),
-    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
-
-should_not_increase_counter_on_readding_same_pid({RefCtr, ChildPid}) ->
-    couch_ref_counter:add(RefCtr, ChildPid),
-    couch_ref_counter:add(RefCtr, ChildPid),
-    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
-
-should_drop_ref_for_double_added_pid({RefCtr, ChildPid}) ->
-    couch_ref_counter:add(RefCtr, ChildPid),
-    couch_ref_counter:add(RefCtr, ChildPid),
-    couch_ref_counter:drop(RefCtr, ChildPid),
-    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
-
-should_decrement_counter_on_pid_drop({RefCtr, ChildPid}) ->
-    couch_ref_counter:add(RefCtr, ChildPid),
-    couch_ref_counter:drop(RefCtr, ChildPid),
-    ?_assertEqual(1, couch_ref_counter:count(RefCtr)).
-
-should_add_after_drop({RefCtr, ChildPid}) ->
-    couch_ref_counter:add(RefCtr, ChildPid),
-    couch_ref_counter:drop(RefCtr, ChildPid),
-    couch_ref_counter:add(RefCtr, ChildPid),
-    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
-
-should_decrement_counter_on_process_exit({RefCtr, ChildPid}) ->
-    ?_assertEqual(1,
-        begin
-            couch_ref_counter:add(RefCtr, ChildPid),
-            erlang:monitor(process, ChildPid),
-            ChildPid ! close,
-            wait(),
-            couch_ref_counter:count(RefCtr)
-        end).
-
-
-loop() ->
-    receive
-        close -> ok
-    end.
-
-wait() ->
-    receive
-        {'DOWN', _, _, _, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw(timeout_error)
-    end.


[04/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 090-task-status.t etap test suite to eunit

Split huge test case into multiple ones. Fix issue with get_task_prop
when Acc may be reset if searched task isn't last in the list.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/49919881
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/49919881
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/49919881

Branch: refs/heads/1963-eunit-bigcouch
Commit: 49919881662c9fdd97caa60dd89daec956835fdf
Parents: 6f7a3e3
Author: Alexander Shorin <kx...@apache.org>
Authored: Mon May 26 20:23:41 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:43 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couch_task_status_tests.erl | 225 ++++++++++++++++++++++++++
 1 file changed, 225 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/49919881/test/couchdb/couch_task_status_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_task_status_tests.erl b/test/couchdb/couch_task_status_tests.erl
new file mode 100644
index 0000000..f71ad2b
--- /dev/null
+++ b/test/couchdb/couch_task_status_tests.erl
@@ -0,0 +1,225 @@
+% 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(couch_task_status_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(TIMEOUT, 1000).
+
+
+setup() ->
+    {ok, TaskStatusPid} = couch_task_status:start_link(),
+    TaskUpdaterPid = spawn(fun() -> loop() end),
+    {TaskStatusPid, TaskUpdaterPid}.
+
+teardown({TaskStatusPid, _}) ->
+    erlang:monitor(process, TaskStatusPid),
+    couch_task_status:stop(),
+    receive
+        {'DOWN', _, _, TaskStatusPid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw(timeout_error)
+    end.
+
+
+couch_task_status_test_() ->
+    {
+        "CouchDB task status updates",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_register_task/1,
+                fun should_set_task_startup_time/1,
+                fun should_have_update_time_as_startup_before_any_progress/1,
+                fun should_set_task_type/1,
+                fun should_not_register_multiple_tasks_for_same_pid/1,
+                fun should_set_task_progress/1,
+                fun should_update_task_progress/1,
+                fun should_update_time_changes_on_task_progress/1,
+                fun should_control_update_frequency/1,
+                fun should_reset_control_update_frequency/1,
+                fun should_track_multiple_tasks/1,
+                fun should_finish_task/1
+
+            ]
+        }
+    }.
+
+
+should_register_task({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    ?_assertEqual(1, length(couch_task_status:all())).
+
+should_set_task_startup_time({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    ?_assert(is_integer(get_task_prop(Pid, started_on))).
+
+should_have_update_time_as_startup_before_any_progress({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    StartTime = get_task_prop(Pid, started_on),
+    ?_assertEqual(StartTime, get_task_prop(Pid, updated_on)).
+
+should_set_task_type({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    ?_assertEqual(replication, get_task_prop(Pid, type)).
+
+should_not_register_multiple_tasks_for_same_pid({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    ?_assertEqual({add_task_error, already_registered},
+                  call(Pid, add, [{type, compaction}, {progress, 0}])).
+
+should_set_task_progress({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    ?_assertEqual(0, get_task_prop(Pid, progress)).
+
+should_update_task_progress({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    call(Pid, update, [{progress, 25}]),
+    ?_assertEqual(25, get_task_prop(Pid, progress)).
+
+should_update_time_changes_on_task_progress({_, Pid}) ->
+    ?_assert(
+        begin
+            ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+            ok = timer:sleep(1000),  % sleep awhile to customize update time
+            call(Pid, update, [{progress, 25}]),
+            get_task_prop(Pid, updated_on) > get_task_prop(Pid, started_on)
+        end).
+
+should_control_update_frequency({_, Pid}) ->
+    ?_assertEqual(66,
+        begin
+            ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+            call(Pid, update, [{progress, 50}]),
+            call(Pid, update_frequency, 500),
+            call(Pid, update, [{progress, 66}]),
+            call(Pid, update, [{progress, 77}]),
+            get_task_prop(Pid, progress)
+        end).
+
+should_reset_control_update_frequency({_, Pid}) ->
+    ?_assertEqual(87,
+        begin
+            ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+            call(Pid, update, [{progress, 50}]),
+            call(Pid, update_frequency, 500),
+            call(Pid, update, [{progress, 66}]),
+            call(Pid, update, [{progress, 77}]),
+            call(Pid, update_frequency, 0),
+            call(Pid, update, [{progress, 87}]),
+            get_task_prop(Pid, progress)
+        end).
+
+should_track_multiple_tasks(_) ->
+    ?_assert(run_multiple_tasks()).
+
+should_finish_task({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    ?assertEqual(1, length(couch_task_status:all())),
+    ok = call(Pid, done),
+    ?_assertEqual(0, length(couch_task_status:all())).
+
+
+run_multiple_tasks() ->
+    Pid1 = spawn(fun() -> loop() end),
+    Pid2 = spawn(fun() -> loop() end),
+    Pid3 = spawn(fun() -> loop() end),
+    call(Pid1, add, [{type, replication}, {progress, 0}]),
+    call(Pid2, add, [{type, compaction}, {progress, 0}]),
+    call(Pid3, add, [{type, indexer}, {progress, 0}]),
+
+    ?assertEqual(3, length(couch_task_status:all())),
+    ?assertEqual(replication, get_task_prop(Pid1, type)),
+    ?assertEqual(compaction, get_task_prop(Pid2, type)),
+    ?assertEqual(indexer, get_task_prop(Pid3, type)),
+
+    call(Pid2, update, [{progress, 33}]),
+    call(Pid3, update, [{progress, 42}]),
+    call(Pid1, update, [{progress, 11}]),
+    ?assertEqual(42, get_task_prop(Pid3, progress)),
+    call(Pid1, update, [{progress, 72}]),
+    ?assertEqual(72, get_task_prop(Pid1, progress)),
+    ?assertEqual(33, get_task_prop(Pid2, progress)),
+
+    call(Pid1, done),
+    ?assertEqual(2, length(couch_task_status:all())),
+    call(Pid3, done),
+    ?assertEqual(1, length(couch_task_status:all())),
+    call(Pid2, done),
+    ?assertEqual(0, length(couch_task_status:all())),
+
+    true.
+
+
+loop() ->
+    receive
+        {add, Props, From} ->
+            Resp = couch_task_status:add_task(Props),
+            From ! {ok, self(), Resp},
+            loop();
+        {update, Props, From} ->
+            Resp = couch_task_status:update(Props),
+            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 ?TIMEOUT ->
+        throw(timeout_error)
+    end.
+
+get_task_prop(Pid, Prop) ->
+    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];
+                _ ->
+                    Acc
+            end
+        end,
+        [], couch_task_status:all()
+    ),
+    case couch_util:get_value(Prop, hd(Element), nil) of
+        nil ->
+            erlang:error({assertion_failed,
+                         [{module, ?MODULE},
+                          {line, ?LINE},
+                          {reason, "Could not get property '"
+                                   ++ couch_util:to_list(Prop)
+                                   ++ "' for task "
+                                   ++ pid_to_list(Pid)}]});
+        Value ->
+            Value
+    end.


[06/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 073-changes.t etap test suite to eunit

For heartbeats test they don't being counted anymore since their
amount is heavy depends from the overall system performance and some
assertions may fail or not because of that. Instead of this, we just
ensure that their amount is going to increase over the time.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/4471f8c4
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/4471f8c4
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/4471f8c4

Branch: refs/heads/1963-eunit-bigcouch
Commit: 4471f8c4bc58bbade37224810f61a168065d35a6
Parents: 9c0f857
Author: Alexander Shorin <kx...@apache.org>
Authored: Tue May 20 07:19:22 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:43 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couch_changes_tests.erl | 612 ++++++++++++++++++++++++++++++
 1 file changed, 612 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/4471f8c4/test/couchdb/couch_changes_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_changes_tests.erl b/test/couchdb/couch_changes_tests.erl
new file mode 100644
index 0000000..a129ba2
--- /dev/null
+++ b/test/couchdb/couch_changes_tests.erl
@@ -0,0 +1,612 @@
+% 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(couch_changes_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(ADMIN_USER, {user_ctx, #user_ctx{roles = [<<"_admin">>]}}).
+-define(TIMEOUT, 3000).
+-define(TEST_TIMEOUT, 10000).
+
+-record(row, {
+    id,
+    seq,
+    deleted = false
+}).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    Pid.
+
+stop(Pid) ->
+    erlang:monitor(process, Pid),
+    couch_server_sup:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    DbName = ?tempdb(),
+    {ok, Db} = create_db(DbName),
+    Revs = [R || {ok, R} <- [
+        save_doc(Db, {[{<<"_id">>, <<"doc1">>}]}),
+        save_doc(Db, {[{<<"_id">>, <<"doc2">>}]}),
+        save_doc(Db, {[{<<"_id">>, <<"doc3">>}]}),
+        save_doc(Db, {[{<<"_id">>, <<"doc4">>}]}),
+        save_doc(Db, {[{<<"_id">>, <<"doc5">>}]})
+    ]],
+    Rev = lists:nth(3, Revs),
+    {ok, Rev1} = save_doc(Db, {[{<<"_id">>, <<"doc3">>}, {<<"_rev">>, Rev}]}),
+    Revs1 = Revs ++ [Rev1],
+    Revs2 = Revs1 ++ [R || {ok, R} <- [
+        save_doc(Db, {[{<<"_id">>, <<"doc6">>}]}),
+        save_doc(Db, {[{<<"_id">>, <<"_design/foo">>}]}),
+        save_doc(Db, {[{<<"_id">>, <<"doc7">>}]}),
+        save_doc(Db, {[{<<"_id">>, <<"doc8">>}]})
+    ]],
+    {DbName, list_to_tuple(Revs2)}.
+
+teardown({DbName, _}) ->
+    delete_db(DbName),
+    ok.
+
+
+changes_test_() ->
+    {
+        "Changes feeed",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            [
+                filter_by_doc_id(),
+                filter_by_design(),
+                continuous_feed(),
+                filter_by_custom_function()
+            ]
+        }
+    }.
+
+filter_by_doc_id() ->
+    {
+        "Filter _doc_id",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_filter_by_specific_doc_ids/1,
+                fun should_filter_by_specific_doc_ids_descending/1,
+                fun should_filter_by_specific_doc_ids_with_since/1,
+                fun should_filter_by_specific_doc_ids_no_result/1,
+                fun should_handle_deleted_docs/1
+            ]
+        }
+    }.
+
+filter_by_design() ->
+    {
+        "Filter _design",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_emit_only_design_documents/1
+            ]
+        }
+    }.
+
+filter_by_custom_function() ->
+    {
+        "Filter function",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_receive_heartbeats/1
+            ]
+        }
+    }.
+
+continuous_feed() ->
+    {
+        "Continuous Feed",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_filter_continuous_feed_by_specific_doc_ids/1
+            ]
+        }
+    }.
+
+
+should_filter_by_specific_doc_ids({DbName, _}) ->
+    ?_test(
+        begin
+            ChangesArgs = #changes_args{
+                filter = "_doc_ids"
+            },
+            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+
+            {Rows, LastSeq} = wait_finished(Consumer),
+            {ok, Db} = couch_db:open_int(DbName, []),
+            UpSeq = couch_db:get_update_seq(Db),
+            couch_db:close(Db),
+            stop_consumer(Consumer),
+
+            ?assertEqual(2, length(Rows)),
+            [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
+            ?assertEqual(<<"doc4">>, Id1),
+            ?assertEqual(4, Seq1),
+            ?assertEqual(<<"doc3">>, Id2),
+            ?assertEqual(6, Seq2),
+            ?assertEqual(UpSeq, LastSeq)
+        end).
+
+should_filter_by_specific_doc_ids_descending({DbName, _}) ->
+    ?_test(
+        begin
+            ChangesArgs = #changes_args{
+                filter = "_doc_ids",
+                dir = rev
+            },
+            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+
+            {Rows, LastSeq} = wait_finished(Consumer),
+            {ok, Db} = couch_db:open_int(DbName, []),
+            couch_db:close(Db),
+            stop_consumer(Consumer),
+
+            ?assertEqual(2, length(Rows)),
+            [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
+            ?assertEqual(<<"doc3">>, Id1),
+            ?assertEqual(6, Seq1),
+            ?assertEqual(<<"doc4">>, Id2),
+            ?assertEqual(4, Seq2),
+            ?assertEqual(4, LastSeq)
+        end).
+
+should_filter_by_specific_doc_ids_with_since({DbName, _}) ->
+    ?_test(
+        begin
+            ChangesArgs = #changes_args{
+                filter = "_doc_ids",
+                since = 5
+            },
+            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+
+            {Rows, LastSeq} = wait_finished(Consumer),
+            {ok, Db} = couch_db:open_int(DbName, []),
+            UpSeq = couch_db:get_update_seq(Db),
+            couch_db:close(Db),
+            stop_consumer(Consumer),
+
+            ?assertEqual(1, length(Rows)),
+            [#row{seq = Seq1, id = Id1}] = Rows,
+            ?assertEqual(<<"doc3">>, Id1),
+            ?assertEqual(6, Seq1),
+            ?assertEqual(UpSeq, LastSeq)
+        end).
+
+should_filter_by_specific_doc_ids_no_result({DbName, _}) ->
+    ?_test(
+        begin
+            ChangesArgs = #changes_args{
+                filter = "_doc_ids",
+                since = 6
+            },
+            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+
+            {Rows, LastSeq} = wait_finished(Consumer),
+            {ok, Db} = couch_db:open_int(DbName, []),
+            UpSeq = couch_db:get_update_seq(Db),
+            couch_db:close(Db),
+            stop_consumer(Consumer),
+
+            ?assertEqual(0, length(Rows)),
+            ?assertEqual(UpSeq, LastSeq)
+        end).
+
+should_handle_deleted_docs({DbName, Revs}) ->
+    ?_test(
+        begin
+            Rev3_2 = element(6, Revs),
+            {ok, Db} = couch_db:open_int(DbName, []),
+            {ok, _} = save_doc(
+                Db,
+                {[{<<"_id">>, <<"doc3">>},
+                  {<<"_deleted">>, true},
+                  {<<"_rev">>, Rev3_2}]}),
+
+            ChangesArgs = #changes_args{
+                filter = "_doc_ids",
+                since = 9
+            },
+            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+
+            {Rows, LastSeq} = wait_finished(Consumer),
+            couch_db:close(Db),
+            stop_consumer(Consumer),
+
+            ?assertEqual(1, length(Rows)),
+            ?assertMatch(
+                [#row{seq = LastSeq, id = <<"doc3">>, deleted = true}],
+                Rows
+            ),
+            ?assertEqual(11, LastSeq)
+        end).
+
+should_filter_continuous_feed_by_specific_doc_ids({DbName, Revs}) ->
+    ?_test(
+        begin
+            {ok, Db} = couch_db:open_int(DbName, []),
+            ChangesArgs = #changes_args{
+                filter = "_doc_ids",
+                feed = "continuous"
+            },
+            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+            pause(Consumer),
+
+            Rows = get_rows(Consumer),
+            ?assertEqual(2, length(Rows)),
+            [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
+            ?assertEqual(<<"doc4">>, Id1),
+            ?assertEqual(4, Seq1),
+            ?assertEqual(<<"doc3">>, Id2),
+            ?assertEqual(6, Seq2),
+
+            clear_rows(Consumer),
+            {ok, _Rev9} = save_doc(Db, {[{<<"_id">>, <<"doc9">>}]}),
+            {ok, _Rev10} = save_doc(Db, {[{<<"_id">>, <<"doc10">>}]}),
+            unpause(Consumer),
+            pause(Consumer),
+            ?assertEqual([], get_rows(Consumer)),
+
+            Rev4 = element(4, Revs),
+            Rev3_2 = element(6, Revs),
+            {ok, Rev4_2} = save_doc(Db, {[{<<"_id">>, <<"doc4">>},
+                                          {<<"_rev">>, Rev4}]}),
+            {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc11">>}]}),
+            {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc4">>},
+                                     {<<"_rev">>, Rev4_2}]}),
+            {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc12">>}]}),
+            {ok, Rev3_3} = save_doc(Db, {[{<<"_id">>, <<"doc3">>},
+                                          {<<"_rev">>, Rev3_2}]}),
+            unpause(Consumer),
+            pause(Consumer),
+
+            NewRows = get_rows(Consumer),
+            ?assertEqual(2, length(NewRows)),
+            [Row14, Row16] = NewRows,
+            ?assertEqual(<<"doc4">>, Row14#row.id),
+            ?assertEqual(15, Row14#row.seq),
+            ?assertEqual(<<"doc3">>, Row16#row.id),
+            ?assertEqual(17, Row16#row.seq),
+
+            clear_rows(Consumer),
+            {ok, _Rev3_4} = save_doc(Db, {[{<<"_id">>, <<"doc3">>},
+                                           {<<"_rev">>, Rev3_3}]}),
+            unpause(Consumer),
+            pause(Consumer),
+
+            FinalRows = get_rows(Consumer),
+
+            unpause(Consumer),
+            stop_consumer(Consumer),
+
+            ?assertMatch([#row{seq = 18, id = <<"doc3">>}], FinalRows)
+        end).
+
+should_emit_only_design_documents({DbName, Revs}) ->
+    ?_test(
+        begin
+            ChangesArgs = #changes_args{
+                filter = "_design"
+            },
+            Consumer = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
+
+            {Rows, LastSeq} = wait_finished(Consumer),
+            {ok, Db} = couch_db:open_int(DbName, []),
+            UpSeq = couch_db:get_update_seq(Db),
+            couch_db:close(Db),
+
+            ?assertEqual(1, length(Rows)),
+            ?assertEqual(UpSeq, LastSeq),
+            ?assertEqual([#row{seq = 8, id = <<"_design/foo">>}], Rows),
+
+            stop_consumer(Consumer),
+
+            {ok, Db2} = couch_db:open_int(DbName, [?ADMIN_USER]),
+            {ok, _} = save_doc(Db2, {[{<<"_id">>, <<"_design/foo">>},
+                                      {<<"_rev">>, element(8, Revs)},
+                                      {<<"_deleted">>, true}]}),
+
+            Consumer2 = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
+
+            {Rows2, LastSeq2} = wait_finished(Consumer2),
+            UpSeq2 = UpSeq + 1,
+            couch_db:close(Db2),
+
+            ?assertEqual(1, length(Rows2)),
+            ?assertEqual(UpSeq2, LastSeq2),
+            ?assertEqual([#row{seq = 11,
+                               id = <<"_design/foo">>,
+                               deleted = true}],
+                          Rows2)
+        end).
+
+should_receive_heartbeats(_) ->
+    {timeout, ?TEST_TIMEOUT div 1000,
+     ?_test(
+         begin
+             DbName = ?tempdb(),
+             Timeout = 100,
+             {ok, Db} = create_db(DbName),
+
+             {ok, _} = save_doc(Db, {[
+                 {<<"_id">>, <<"_design/filtered">>},
+                 {<<"language">>, <<"javascript">>},
+                     {<<"filters">>, {[
+                         {<<"foo">>, <<"function(doc) {
+                             return ['doc10', 'doc11', 'doc12'].indexOf(doc._id) != -1;}">>
+                     }]}}
+             ]}),
+
+             ChangesArgs = #changes_args{
+                 filter = "filtered/foo",
+                 feed = "continuous",
+                 timeout = 10000,
+                 heartbeat = 1000
+             },
+             Consumer = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
+
+             {ok, _Rev1} = save_doc(Db, {[{<<"_id">>, <<"doc1">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev2} = save_doc(Db, {[{<<"_id">>, <<"doc2">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev3} = save_doc(Db, {[{<<"_id">>, <<"doc3">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev4} = save_doc(Db, {[{<<"_id">>, <<"doc4">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev5} = save_doc(Db, {[{<<"_id">>, <<"doc5">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev6} = save_doc(Db, {[{<<"_id">>, <<"doc6">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev7} = save_doc(Db, {[{<<"_id">>, <<"doc7">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev8} = save_doc(Db, {[{<<"_id">>, <<"doc8">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev9} = save_doc(Db, {[{<<"_id">>, <<"doc9">>}]}),
+
+             Heartbeats = get_heartbeats(Consumer),
+             ?assert(Heartbeats > 0),
+
+             {ok, _Rev10} = save_doc(Db, {[{<<"_id">>, <<"doc10">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev11} = save_doc(Db, {[{<<"_id">>, <<"doc11">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev12} = save_doc(Db, {[{<<"_id">>, <<"doc12">>}]}),
+
+             Heartbeats2 = get_heartbeats(Consumer),
+             ?assert(Heartbeats2 > Heartbeats),
+
+             Rows = get_rows(Consumer),
+             ?assertEqual(3, length(Rows)),
+
+             {ok, _Rev13} = save_doc(Db, {[{<<"_id">>, <<"doc13">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev14} = save_doc(Db, {[{<<"_id">>, <<"doc14">>}]}),
+             timer:sleep(Timeout),
+
+             Heartbeats3 = get_heartbeats(Consumer),
+             ?assert(Heartbeats3 > Heartbeats2)
+        end)}.
+
+
+save_doc(Db, Json) ->
+    Doc = couch_doc:from_json_obj(Json),
+    {ok, Rev} = couch_db:update_doc(Db, Doc, []),
+    {ok, couch_doc:rev_to_str(Rev)}.
+
+get_rows(Consumer) ->
+    Ref = make_ref(),
+    Consumer ! {get_rows, Ref},
+    Resp = receive
+        {rows, Ref, Rows} ->
+            Rows
+    after ?TIMEOUT ->
+        timeout
+    end,
+    ?assertNotEqual(timeout, Resp),
+    Resp.
+
+get_heartbeats(Consumer) ->
+    Ref = make_ref(),
+    Consumer ! {get_heartbeats, Ref},
+    Resp = receive
+        {hearthbeats, Ref, HeartBeats} ->
+            HeartBeats
+    after ?TIMEOUT ->
+        timeout
+    end,
+    ?assertNotEqual(timeout, Resp),
+    Resp.
+
+clear_rows(Consumer) ->
+    Ref = make_ref(),
+    Consumer ! {reset, Ref},
+    Resp = receive
+        {ok, Ref} ->
+            ok
+    after ?TIMEOUT ->
+        timeout
+    end,
+    ?assertNotEqual(timeout, Resp),
+    Resp.
+
+stop_consumer(Consumer) ->
+    Ref = make_ref(),
+    Consumer ! {stop, Ref},
+    Resp = receive
+        {ok, Ref} ->
+            ok
+    after ?TIMEOUT ->
+        timeout
+    end,
+    ?assertNotEqual(timeout, Resp),
+    Resp.
+
+pause(Consumer) ->
+    Ref = make_ref(),
+    Consumer ! {pause, Ref},
+    Resp = receive
+        {paused, Ref} ->
+            ok
+    after ?TIMEOUT ->
+        timeout
+    end,
+    ?assertNotEqual(timeout, Resp),
+    Resp.
+
+unpause(Consumer) ->
+    Ref = make_ref(),
+    Consumer ! {continue, Ref},
+    Resp = receive
+        {ok, Ref} ->
+            ok
+    after ?TIMEOUT ->
+       timeout
+    end,
+    ?assertNotEqual(timeout, Resp),
+    Resp.
+
+wait_finished(_Consumer) ->
+    Resp = receive
+        {consumer_finished, Rows, LastSeq} ->
+            {Rows, LastSeq}
+    after ?TIMEOUT ->
+        timeout
+    end,
+    ?assertNotEqual(timeout, Resp),
+    Resp.
+
+spawn_consumer(DbName, ChangesArgs0, Req) ->
+    Parent = self(),
+    spawn(fun() ->
+        put(heartbeat_count, 0),
+        Callback = fun
+            ({change, {Change}, _}, _, Acc) ->
+                Id = couch_util:get_value(<<"id">>, Change),
+                Seq = couch_util:get_value(<<"seq">>, Change),
+                Del = couch_util:get_value(<<"deleted">>, Change, false),
+                [#row{id = Id, seq = Seq, deleted = Del} | Acc];
+            ({stop, LastSeq}, _, Acc) ->
+                Parent ! {consumer_finished, lists:reverse(Acc), LastSeq},
+                stop_loop(Parent, Acc);
+            (timeout, _, Acc) ->
+                put(heartbeat_count, get(heartbeat_count) + 1),
+                maybe_pause(Parent, Acc);
+            (_, _, Acc) ->
+                maybe_pause(Parent, Acc)
+        end,
+        {ok, Db} = couch_db:open_int(DbName, []),
+        ChangesArgs = case (ChangesArgs0#changes_args.timeout =:= undefined)
+            andalso (ChangesArgs0#changes_args.heartbeat =:= undefined) of
+            true ->
+                ChangesArgs0#changes_args{timeout = 10, heartbeat = 10};
+            false ->
+                ChangesArgs0
+        end,
+        FeedFun = couch_changes:handle_changes(ChangesArgs, Req, Db),
+        try
+            FeedFun({Callback, []})
+        catch throw:{stop, _} ->
+            ok
+        end,
+        catch couch_db:close(Db)
+    end).
+
+maybe_pause(Parent, Acc) ->
+    receive
+        {get_rows, Ref} ->
+            Parent ! {rows, Ref, lists:reverse(Acc)},
+            maybe_pause(Parent, Acc);
+        {get_heartbeats, Ref} ->
+            Parent ! {hearthbeats, Ref, get(heartbeat_count)},
+            maybe_pause(Parent, Acc);
+        {reset, Ref} ->
+            Parent ! {ok, Ref},
+            maybe_pause(Parent, []);
+        {pause, Ref} ->
+            Parent ! {paused, Ref},
+            pause_loop(Parent, Acc);
+        {stop, Ref} ->
+            Parent ! {ok, Ref},
+            throw({stop, Acc});
+        V ->
+            erlang:error({assertion_failed,
+                      [{module, ?MODULE},
+                       {line, ?LINE},
+                       {value, V},
+                       {reason, "Received unexpected message"}]})
+    after 0 ->
+        Acc
+    end.
+
+pause_loop(Parent, Acc) ->
+    receive
+        {stop, Ref} ->
+            Parent ! {ok, Ref},
+            throw({stop, Acc});
+        {reset, Ref} ->
+            Parent ! {ok, Ref},
+            pause_loop(Parent, []);
+        {continue, Ref} ->
+            Parent ! {ok, Ref},
+            Acc;
+        {get_rows, Ref} ->
+            Parent ! {rows, Ref, lists:reverse(Acc)},
+            pause_loop(Parent, Acc)
+    end.
+
+stop_loop(Parent, Acc) ->
+    receive
+        {get_rows, Ref} ->
+            Parent ! {rows, Ref, lists:reverse(Acc)},
+            stop_loop(Parent, Acc);
+        {stop, Ref} ->
+            Parent ! {ok, Ref},
+            Acc
+    end.
+
+create_db(DbName) ->
+    couch_db:create(DbName, [?ADMIN_USER, overwrite]).
+
+delete_db(DbName) ->
+    ok = couch_server:delete(DbName, [?ADMIN_USER]).


[14/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 220-compaction-daemon.t etap test suite to eunit


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/3ca50ad4
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/3ca50ad4
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/3ca50ad4

Branch: refs/heads/1963-eunit-bigcouch
Commit: 3ca50ad4318c820061e9fb276c655db72da7ca5b
Parents: be1386a
Author: Alexander Shorin <kx...@apache.org>
Authored: Mon Jun 9 20:15:37 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:44 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_compaction_daemon.erl | 231 ++++++++++++++++++++++++
 1 file changed, 231 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/3ca50ad4/test/couchdb/couchdb_compaction_daemon.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_compaction_daemon.erl b/test/couchdb/couchdb_compaction_daemon.erl
new file mode 100644
index 0000000..725a97b
--- /dev/null
+++ b/test/couchdb/couchdb_compaction_daemon.erl
@@ -0,0 +1,231 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_compaction_daemon).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
+-define(DELAY, 100).
+-define(TIMEOUT, 30000).
+-define(TIMEOUT_S, ?TIMEOUT div 1000).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    couch_config:set("compaction_daemon", "check_interval", "3", false),
+    couch_config:set("compaction_daemon", "min_file_size", "100000", false),
+    Pid.
+
+stop(Pid) ->
+    erlang:monitor(process, Pid),
+    couch_server_sup:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+    create_design_doc(Db),
+    ok = couch_db:close(Db),
+    DbName.
+
+teardown(DbName) ->
+    Configs = couch_config:get("compactions"),
+    lists:foreach(
+        fun({Key, _}) ->
+            ok = couch_config:delete("compactions", Key, false)
+        end,
+        Configs),
+    couch_server:delete(DbName, [?ADMIN_USER]),
+    ok.
+
+
+compaction_daemon_test_() ->
+    {
+        "Compaction daemon tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    fun should_compact_by_default_rule/1,
+                    fun should_compact_by_dbname_rule/1
+                ]
+            }
+        }
+    }.
+
+
+should_compact_by_default_rule(DbName) ->
+    {timeout, ?TIMEOUT_S, ?_test(begin
+        {ok, Db} = couch_db:open_int(DbName, []),
+        populate(DbName, 70, 70, 200 * 1024),
+
+        {_, DbFileSize} = get_db_frag(DbName),
+        {_, ViewFileSize} = get_view_frag(DbName),
+
+        ok = couch_config:set("compactions", "_default",
+            "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]",
+            false),
+
+        ok = timer:sleep(4000), % something >= check_interval
+        wait_compaction_finished(DbName),
+        ok = couch_config:delete("compactions", "_default", false),
+
+        {DbFrag2, DbFileSize2} = get_db_frag(DbName),
+        {ViewFrag2, ViewFileSize2} = get_view_frag(DbName),
+
+        ?assert(DbFrag2 < 70),
+        ?assert(ViewFrag2 < 70),
+
+        ?assert(DbFileSize > DbFileSize2),
+        ?assert(ViewFileSize > ViewFileSize2),
+
+        ?assert(couch_db:is_idle(Db)),
+        ok = couch_db:close(Db)
+    end)}.
+
+should_compact_by_dbname_rule(DbName) ->
+    {timeout, ?TIMEOUT_S, ?_test(begin
+        {ok, Db} = couch_db:open_int(DbName, []),
+        populate(DbName, 70, 70, 200 * 1024),
+
+        {_, DbFileSize} = get_db_frag(DbName),
+        {_, ViewFileSize} = get_view_frag(DbName),
+
+        ok = couch_config:set("compactions", ?b2l(DbName),
+            "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]",
+            false),
+
+        ok = timer:sleep(4000), % something >= check_interval
+        wait_compaction_finished(DbName),
+        ok = couch_config:delete("compactions", ?b2l(DbName), false),
+
+        {DbFrag2, DbFileSize2} = get_db_frag(DbName),
+        {ViewFrag2, ViewFileSize2} = get_view_frag(DbName),
+
+        ?assert(DbFrag2 < 70),
+        ?assert(ViewFrag2 < 70),
+
+        ?assert(DbFileSize > DbFileSize2),
+        ?assert(ViewFileSize > ViewFileSize2),
+
+        ?assert(couch_db:is_idle(Db)),
+        ok = couch_db:close(Db)
+    end)}.
+
+
+create_design_doc(Db) ->
+    DDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, <<"_design/foo">>},
+        {<<"language">>, <<"javascript">>},
+        {<<"views">>, {[
+            {<<"foo">>, {[
+                {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>}
+            ]}},
+            {<<"foo2">>, {[
+                {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>}
+            ]}},
+            {<<"foo3">>, {[
+                {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>}
+            ]}}
+        ]}}
+    ]}),
+    {ok, _} = couch_db:update_docs(Db, [DDoc]),
+    {ok, _} = couch_db:ensure_full_commit(Db),
+    ok.
+
+populate(DbName, DbFrag, ViewFrag, MinFileSize) ->
+    {CurDbFrag, DbFileSize} = get_db_frag(DbName),
+    {CurViewFrag, ViewFileSize} = get_view_frag(DbName),
+    populate(DbName, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag,
+             lists:min([DbFileSize, ViewFileSize])).
+
+populate(_Db, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag, FileSize)
+    when CurDbFrag >= DbFrag, CurViewFrag >= ViewFrag, FileSize >= MinFileSize ->
+    ok;
+populate(DbName, DbFrag, ViewFrag, MinFileSize, _, _, _) ->
+    update(DbName),
+    {CurDbFrag, DbFileSize} = get_db_frag(DbName),
+    {CurViewFrag, ViewFileSize} = get_view_frag(DbName),
+    populate(DbName, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag,
+             lists:min([DbFileSize, ViewFileSize])).
+
+update(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    lists:foreach(fun(_) ->
+        Doc = couch_doc:from_json_obj({[{<<"_id">>, couch_uuids:new()}]}),
+        {ok, _} = couch_db:update_docs(Db, [Doc]),
+        query_view(Db#db.name)
+    end, lists:seq(1, 200)),
+    couch_db:close(Db).
+
+db_url(DbName) ->
+    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+    "http://" ++ Addr ++ ":" ++ Port ++ "/" ++ ?b2l(DbName).
+
+query_view(DbName) ->
+    {ok, Code, _Headers, _Body} = test_request:get(
+        db_url(DbName) ++ "/_design/foo/_view/foo"),
+    ?assertEqual(200, Code).
+
+get_db_frag(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, Info} = couch_db:get_db_info(Db),
+    couch_db:close(Db),
+    FileSize = couch_util:get_value(disk_size, Info),
+    DataSize = couch_util:get_value(data_size, Info),
+    {round((FileSize - DataSize) / FileSize * 100), FileSize}.
+
+get_view_frag(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, Info} = couch_mrview:get_info(Db, <<"_design/foo">>),
+    couch_db:close(Db),
+    FileSize = couch_util:get_value(disk_size, Info),
+    DataSize = couch_util:get_value(data_size, Info),
+    {round((FileSize - DataSize) / FileSize * 100), FileSize}.
+
+wait_compaction_finished(DbName) ->
+    Parent = self(),
+    Loop = spawn_link(fun() -> wait_loop(DbName, Parent) end),
+    receive
+        {done, Loop} ->
+            ok
+    after ?TIMEOUT ->
+        erlang:error(
+            {assertion_failed,
+             [{module, ?MODULE}, {line, ?LINE},
+              {reason, "Compaction timeout"}]})
+    end.
+
+wait_loop(DbName, Parent) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, DbInfo} = couch_db:get_db_info(Db),
+    {ok, ViewInfo} = couch_mrview:get_info(Db, <<"_design/foo">>),
+    couch_db:close(Db),
+    case (couch_util:get_value(compact_running, ViewInfo) =:= true) orelse
+        (couch_util:get_value(compact_running, DbInfo) =:= true) of
+        false ->
+            Parent ! {done, self()};
+        true ->
+            ok = timer:sleep(?DELAY),
+            wait_loop(DbName, Parent)
+    end.


[11/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 077-couch-db-fast-db-delete-create.t etap test suite to eunit

Merged into couch_db_tests suite.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/f51ec464
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/f51ec464
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/f51ec464

Branch: refs/heads/1963-eunit-bigcouch
Commit: f51ec464f735f5a30d7772f93e200b7b2e02417e
Parents: 0511102
Author: Alexander Shorin <kx...@apache.org>
Authored: Thu May 22 20:31:09 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:43 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couch_db_tests.erl | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/f51ec464/test/couchdb/couch_db_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_db_tests.erl b/test/couchdb/couch_db_tests.erl
index 2b781ed..3089714 100644
--- a/test/couchdb/couch_db_tests.erl
+++ b/test/couchdb/couch_db_tests.erl
@@ -14,9 +14,12 @@
 
 -include("couch_eunit.hrl").
 
+-define(TIMEOUT, 120).
+
 
 setup() ->
     {ok, _} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    couch_config:set("log", "include_sasl", "false", false),
     ok.
 
 teardown(_) ->
@@ -33,7 +36,8 @@ create_delete_db_test_()->
                 [should_create_db(),
                  should_delete_db(),
                  should_create_multiple_dbs(),
-                 should_delete_multiple_dbs()]
+                 should_delete_multiple_dbs(),
+                 should_create_delete_database_continuously()]
             end
         }
     }.
@@ -88,3 +92,23 @@ should_delete_multiple_dbs() ->
     end, 0, DbNames),
 
     ?_assertEqual(NumDeleted, 6).
+
+should_create_delete_database_continuously() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, []),
+    couch_db:close(Db),
+    [{timeout, ?TIMEOUT, {integer_to_list(N) ++ " times",
+                           ?_assert(loop(DbName, N))}}
+     || N <- [10, 100, 1000]].
+
+loop(_, 0) ->
+    true;
+loop(DbName, N) ->
+    ok = cycle(DbName),
+    loop(DbName, N - 1).
+
+cycle(DbName) ->
+    ok = couch_server:delete(DbName, []),
+    {ok, Db} = couch_db:create(DbName, []),
+    couch_db:close(Db),
+    ok.


[28/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 250-upgrade-legacy-view-files.t etap test suite to eunit


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/6b114c6b
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/6b114c6b
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/6b114c6b

Branch: refs/heads/1963-eunit-bigcouch
Commit: 6b114c6bbcece20df55c37dc63dd9ae544509cb9
Parents: 013730c
Author: Alexander Shorin <kx...@apache.org>
Authored: Tue Jun 10 23:55:32 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:45 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_views_tests.erl            |  69 +++++++++++++++++++
 .../3b835456c235b1827e012e25666152f3.view       | Bin 0 -> 4192 bytes
 test/couchdb/fixtures/test.couch                | Bin 0 -> 16482 bytes
 3 files changed, 69 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/6b114c6b/test/couchdb/couchdb_views_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_views_tests.erl b/test/couchdb/couchdb_views_tests.erl
index 57d5a14..6d81f32 100644
--- a/test/couchdb/couchdb_views_tests.erl
+++ b/test/couchdb/couchdb_views_tests.erl
@@ -14,6 +14,7 @@
 
 -include("couch_eunit.hrl").
 -include_lib("couchdb/couch_db.hrl").
+-include_lib("couch_mrview/include/couch_mrview.hrl").
 
 -define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
 -define(DELAY, 100).
@@ -131,6 +132,68 @@ should_not_remember_docs_in_index_after_backup_restore_test() ->
     stop(whereis(couch_server_sup)).
 
 
+should_upgrade_legacy_view_files_test() ->
+    start(),
+
+    ok = couch_config:set("query_server_config", "commit_freq", "0", false),
+
+    DbName = <<"test">>,
+    DbFileName = "test.couch",
+    DbFilePath = filename:join([?FIXTURESDIR, DbFileName]),
+    OldViewName = "3b835456c235b1827e012e25666152f3.view",
+    FixtureViewFilePath = filename:join([?FIXTURESDIR, OldViewName]),
+    NewViewName = "a1c5929f912aca32f13446122cc6ce50.view",
+
+    DbDir = couch_config:get("couchdb", "database_dir"),
+    ViewDir = couch_config:get("couchdb", "view_index_dir"),
+    OldViewFilePath = filename:join([ViewDir, ".test_design", OldViewName]),
+    NewViewFilePath = filename:join([ViewDir, ".test_design", "mrview",
+                                     NewViewName]),
+
+    % cleanup
+    Files = [
+        filename:join([DbDir, DbFileName]),
+        OldViewFilePath,
+        NewViewFilePath
+    ],
+    lists:foreach(fun(File) -> file:delete(File) end, Files),
+
+    % copy old db file into db dir
+    {ok, _} = file:copy(DbFilePath, filename:join([DbDir, DbFileName])),
+
+    % copy old view file into view dir
+    ok = filelib:ensure_dir(filename:join([ViewDir, ".test_design"])),
+    {ok, _} = file:copy(FixtureViewFilePath, OldViewFilePath),
+
+    % ensure old header
+    OldHeader = read_header(OldViewFilePath),
+    ?assertMatch(#index_header{}, OldHeader),
+
+    % query view for expected results
+    Rows0 = query_view(DbName, "test", "test"),
+    ?assertEqual(2, length(Rows0)),
+
+    % ensure old file gone
+    ?assertNot(filelib:is_regular(OldViewFilePath)),
+
+    % add doc to trigger update
+    DocUrl = db_url(DbName) ++ "/boo",
+    {ok, _, _, _} = test_request:put(
+        DocUrl, [{"Content-Type", "application/json"}], <<"{\"a\":3}">>),
+
+    % query view for expected results
+    Rows1 = query_view(DbName, "test", "test"),
+    ?assertEqual(3, length(Rows1)),
+
+    % ensure new header
+    timer:sleep(2000),  % have to wait for awhile to upgrade the index
+    NewHeader = read_header(NewViewFilePath),
+    ?assertMatch(#mrheader{}, NewHeader),
+
+    teardown(DbName),
+    stop(whereis(couch_server_sup)).
+
+
 should_have_two_indexes_alive_before_deletion({DbName, _}) ->
     view_cleanup(DbName),
     ?_assertEqual(2, count_index_files(DbName)).
@@ -598,3 +661,9 @@ writer_loop_2(DbName, Parent, Error) ->
             Parent ! {ok, Ref},
             writer_loop(DbName, Parent)
     end.
+
+read_header(File) ->
+    {ok, Fd} = couch_file:open(File),
+    {ok, {_Sig, Header}} = couch_file:read_header(Fd),
+    couch_file:close(Fd),
+    Header.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/6b114c6b/test/couchdb/fixtures/3b835456c235b1827e012e25666152f3.view
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/3b835456c235b1827e012e25666152f3.view b/test/couchdb/fixtures/3b835456c235b1827e012e25666152f3.view
new file mode 100644
index 0000000..9c67648
Binary files /dev/null and b/test/couchdb/fixtures/3b835456c235b1827e012e25666152f3.view differ

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/6b114c6b/test/couchdb/fixtures/test.couch
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/test.couch b/test/couchdb/fixtures/test.couch
new file mode 100644
index 0000000..32c79af
Binary files /dev/null and b/test/couchdb/fixtures/test.couch differ


[32/50] [abbrv] Move files out of test/couchdb into top level test/ folder

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb_attachments_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_attachments_tests.erl b/test/couchdb_attachments_tests.erl
new file mode 100644
index 0000000..cf59785
--- /dev/null
+++ b/test/couchdb_attachments_tests.erl
@@ -0,0 +1,638 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_attachments_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(COMPRESSION_LEVEL, 8).
+-define(ATT_BIN_NAME, <<"logo.png">>).
+-define(ATT_TXT_NAME, <<"file.erl">>).
+-define(FIXTURE_PNG, filename:join([?FIXTURESDIR, "logo.png"])).
+-define(FIXTURE_TXT, ?FILE).
+-define(TIMEOUT, 1000).
+-define(TIMEOUT_EUNIT, 10).
+-define(TIMEWAIT, 100).
+-define(i2l(I), integer_to_list(I)).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    % ensure in default compression settings for attachments_compression_tests
+    couch_config:set("attachments", "compression_level",
+                     ?i2l(?COMPRESSION_LEVEL), false),
+    couch_config:set("attachments", "compressible_types", "text/*", false),
+    Pid.
+
+stop(Pid) ->
+    erlang:monitor(process, Pid),
+    couch_server_sup:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, []),
+    ok = couch_db:close(Db),
+    Addr = couch_config:get("httpd", "bind_address", any),
+    Port = mochiweb_socket_server:get(couch_httpd, port),
+    Host = Addr ++ ":" ++ ?i2l(Port),
+    {Host, ?b2l(DbName)}.
+
+setup({binary, standalone}) ->
+    {Host, DbName} = setup(),
+        setup_att(fun create_standalone_png_att/2, Host, DbName, ?FIXTURE_PNG);
+setup({text, standalone}) ->
+    {Host, DbName} = setup(),
+    setup_att(fun create_standalone_text_att/2, Host, DbName, ?FIXTURE_TXT);
+setup({binary, inline}) ->
+    {Host, DbName} = setup(),
+    setup_att(fun create_inline_png_att/2, Host, DbName, ?FIXTURE_PNG);
+setup({text, inline}) ->
+    {Host, DbName} = setup(),
+    setup_att(fun create_inline_text_att/2, Host, DbName, ?FIXTURE_TXT);
+setup(compressed) ->
+    {Host, DbName} = setup(),
+    setup_att(fun create_already_compressed_att/2, Host, DbName, ?FIXTURE_TXT).
+setup_att(Fun, Host, DbName, File) ->
+    HttpHost = "http://" ++ Host,
+    AttUrl = Fun(HttpHost, DbName),
+    {ok, Data} = file:read_file(File),
+    DocUrl = string:join([HttpHost, DbName, "doc"], "/"),
+    Helpers = {DbName, DocUrl, AttUrl},
+    {Data, Helpers}.
+
+teardown(_, {_, {DbName, _, _}}) ->
+    teardown(DbName).
+
+teardown({_, DbName}) ->
+    teardown(DbName);
+teardown(DbName) ->
+    ok = couch_server:delete(?l2b(DbName), []),
+    ok.
+
+
+attachments_test_() ->
+    {
+        "Attachments tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            [
+                attachments_md5_tests(),
+                attachments_compression_tests()
+            ]
+        }
+    }.
+
+attachments_md5_tests() ->
+    {
+        "Attachments MD5 tests",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_upload_attachment_without_md5/1,
+                fun should_upload_attachment_by_chunks_without_md5/1,
+                fun should_upload_attachment_with_valid_md5_header/1,
+                fun should_upload_attachment_by_chunks_with_valid_md5_header/1,
+                fun should_upload_attachment_by_chunks_with_valid_md5_trailer/1,
+                fun should_reject_attachment_with_invalid_md5/1,
+                fun should_reject_chunked_attachment_with_invalid_md5/1,
+                fun should_reject_chunked_attachment_with_invalid_md5_trailer/1
+            ]
+        }
+    }.
+
+attachments_compression_tests() ->
+    Funs = [
+         fun should_get_att_without_accept_gzip_encoding/2,
+         fun should_get_att_with_accept_gzip_encoding/2,
+         fun should_get_att_with_accept_deflate_encoding/2,
+         fun should_return_406_response_on_unsupported_encoding/2,
+         fun should_get_doc_with_att_data/2,
+         fun should_get_doc_with_att_data_stub/2
+    ],
+    {
+        "Attachments compression tests",
+        [
+            {
+                "Created via Attachments API",
+                created_attachments_compression_tests(standalone, Funs)
+            },
+            {
+                "Created inline via Document API",
+                created_attachments_compression_tests(inline, Funs)
+            },
+            {
+                "Created already been compressed via Attachments API",
+                {
+                    foreachx,
+                    fun setup/1, fun teardown/2,
+                    [{compressed, Fun} || Fun <- Funs]
+                }
+            },
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    fun should_not_create_compressed_att_with_deflate_encoding/1,
+                    fun should_not_create_compressed_att_with_compress_encoding/1,
+                    fun should_create_compressible_att_with_ctype_params/1
+                ]
+            }
+        ]
+    }.
+
+created_attachments_compression_tests(Mod, Funs) ->
+    [
+        {
+            "Compressiable attachments",
+            {
+                foreachx,
+                fun setup/1, fun teardown/2,
+                [{{text, Mod}, Fun} || Fun <- Funs]
+            }
+        },
+        {
+            "Uncompressiable attachments",
+            {
+                foreachx,
+                fun setup/1, fun teardown/2,
+                [{{binary, Mod}, Fun} || Fun <- Funs]
+            }
+        }
+    ].
+
+
+
+should_upload_attachment_without_md5({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        Body = "We all live in a yellow submarine!",
+        Headers = [
+            {"Content-Length", "34"},
+            {"Content-Type", "text/plain"},
+            {"Host", Host}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(201, Code),
+        ?assertEqual(true, get_json(Json, [<<"ok">>]))
+    end).
+
+should_upload_attachment_by_chunks_without_md5({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        AttData = <<"We all live in a yellow submarine!">>,
+        <<Part1:21/binary, Part2:13/binary>> = AttData,
+        Body = chunked_body([Part1, Part2]),
+        Headers = [
+            {"Content-Type", "text/plain"},
+            {"Transfer-Encoding", "chunked"},
+            {"Host", Host}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(201, Code),
+        ?assertEqual(true, get_json(Json, [<<"ok">>]))
+    end).
+
+should_upload_attachment_with_valid_md5_header({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        Body = "We all live in a yellow submarine!",
+        Headers = [
+            {"Content-Length", "34"},
+            {"Content-Type", "text/plain"},
+            {"Content-MD5", ?b2l(base64:encode(couch_util:md5(Body)))},
+            {"Host", Host}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(201, Code),
+        ?assertEqual(true, get_json(Json, [<<"ok">>]))
+    end).
+
+should_upload_attachment_by_chunks_with_valid_md5_header({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        AttData = <<"We all live in a yellow submarine!">>,
+        <<Part1:21/binary, Part2:13/binary>> = AttData,
+        Body = chunked_body([Part1, Part2]),
+        Headers = [
+            {"Content-Type", "text/plain"},
+            {"Content-MD5", ?b2l(base64:encode(couch_util:md5(AttData)))},
+            {"Host", Host},
+            {"Transfer-Encoding", "chunked"}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(201, Code),
+        ?assertEqual(true, get_json(Json, [<<"ok">>]))
+    end).
+
+should_upload_attachment_by_chunks_with_valid_md5_trailer({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        AttData = <<"We all live in a yellow submarine!">>,
+        <<Part1:21/binary, Part2:13/binary>> = AttData,
+        Body = [chunked_body([Part1, Part2]),
+                "Content-MD5: ", base64:encode(couch_util:md5(AttData)),
+                "\r\n"],
+        Headers = [
+            {"Content-Type", "text/plain"},
+            {"Host", Host},
+            {"Trailer", "Content-MD5"},
+            {"Transfer-Encoding", "chunked"}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(201, Code),
+        ?assertEqual(true, get_json(Json, [<<"ok">>]))
+    end).
+
+should_reject_attachment_with_invalid_md5({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        Body = "We all live in a yellow submarine!",
+        Headers = [
+            {"Content-Length", "34"},
+            {"Content-Type", "text/plain"},
+            {"Content-MD5", ?b2l(base64:encode(<<"foobar!">>))},
+            {"Host", Host}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(400, Code),
+        ?assertEqual(<<"content_md5_mismatch">>,
+                     get_json(Json, [<<"error">>]))
+    end).
+
+
+should_reject_chunked_attachment_with_invalid_md5({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        AttData = <<"We all live in a yellow submarine!">>,
+        <<Part1:21/binary, Part2:13/binary>> = AttData,
+        Body = chunked_body([Part1, Part2]),
+        Headers = [
+            {"Content-Type", "text/plain"},
+            {"Content-MD5", ?b2l(base64:encode(<<"foobar!">>))},
+            {"Host", Host},
+            {"Transfer-Encoding", "chunked"}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(400, Code),
+        ?assertEqual(<<"content_md5_mismatch">>,
+                     get_json(Json, [<<"error">>]))
+    end).
+
+should_reject_chunked_attachment_with_invalid_md5_trailer({Host, DbName}) ->
+    ?_test(begin
+        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+        AttData = <<"We all live in a yellow submarine!">>,
+        <<Part1:21/binary, Part2:13/binary>> = AttData,
+        Body = [chunked_body([Part1, Part2]),
+                "Content-MD5: ", base64:encode(<<"foobar!">>),
+                "\r\n"],
+        Headers = [
+            {"Content-Type", "text/plain"},
+            {"Host", Host},
+            {"Trailer", "Content-MD5"},
+            {"Transfer-Encoding", "chunked"}
+        ],
+        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+        ?assertEqual(400, Code),
+        ?assertEqual(<<"content_md5_mismatch">>, get_json(Json, [<<"error">>]))
+    end).
+
+should_get_att_without_accept_gzip_encoding(_, {Data, {_, _, AttUrl}}) ->
+    ?_test(begin
+        {ok, Code, Headers, Body} = test_request:get(AttUrl),
+        ?assertEqual(200, Code),
+        ?assertNot(lists:member({"Content-Encoding", "gzip"}, Headers)),
+        ?assertEqual(Data, iolist_to_binary(Body))
+    end).
+
+should_get_att_with_accept_gzip_encoding(compressed, {Data, {_, _, AttUrl}}) ->
+    ?_test(begin
+        {ok, Code, Headers, Body} = test_request:get(
+            AttUrl, [{"Accept-Encoding", "gzip"}]),
+        ?assertEqual(200, Code),
+        ?assert(lists:member({"Content-Encoding", "gzip"}, Headers)),
+        ?assertEqual(Data, zlib:gunzip(iolist_to_binary(Body)))
+    end);
+should_get_att_with_accept_gzip_encoding({text, _}, {Data, {_, _, AttUrl}}) ->
+    ?_test(begin
+        {ok, Code, Headers, Body} = test_request:get(
+            AttUrl, [{"Accept-Encoding", "gzip"}]),
+        ?assertEqual(200, Code),
+        ?assert(lists:member({"Content-Encoding", "gzip"}, Headers)),
+        ?assertEqual(Data, zlib:gunzip(iolist_to_binary(Body)))
+    end);
+should_get_att_with_accept_gzip_encoding({binary, _}, {Data, {_, _, AttUrl}}) ->
+    ?_test(begin
+        {ok, Code, Headers, Body} = test_request:get(
+            AttUrl, [{"Accept-Encoding", "gzip"}]),
+        ?assertEqual(200, Code),
+        ?assertEqual(undefined,
+                     couch_util:get_value("Content-Encoding", Headers)),
+        ?assertEqual(Data, iolist_to_binary(Body))
+    end).
+
+should_get_att_with_accept_deflate_encoding(_, {Data, {_, _, AttUrl}}) ->
+    ?_test(begin
+        {ok, Code, Headers, Body} = test_request:get(
+            AttUrl, [{"Accept-Encoding", "deflate"}]),
+        ?assertEqual(200, Code),
+        ?assertEqual(undefined,
+                     couch_util:get_value("Content-Encoding", Headers)),
+        ?assertEqual(Data, iolist_to_binary(Body))
+    end).
+
+should_return_406_response_on_unsupported_encoding(_, {_, {_, _, AttUrl}}) ->
+    ?_assertEqual(406,
+        begin
+            {ok, Code, _, _} = test_request:get(
+                AttUrl, [{"Accept-Encoding", "deflate, *;q=0"}]),
+            Code
+        end).
+
+should_get_doc_with_att_data(compressed, {Data, {_, DocUrl, _}}) ->
+    ?_test(begin
+        Url = DocUrl ++ "?attachments=true",
+        {ok, Code, _, Body} = test_request:get(
+            Url, [{"Accept", "application/json"}]),
+        ?assertEqual(200, Code),
+        Json = ejson:decode(Body),
+        AttJson = couch_util:get_nested_json_value(
+            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+        AttData = couch_util:get_nested_json_value(
+            AttJson, [<<"data">>]),
+        ?assertEqual(
+            <<"text/plain">>,
+            couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
+        ?assertEqual(Data, base64:decode(AttData))
+    end);
+should_get_doc_with_att_data({text, _}, {Data, {_, DocUrl, _}}) ->
+    ?_test(begin
+        Url = DocUrl ++ "?attachments=true",
+        {ok, Code, _, Body} = test_request:get(
+            Url, [{"Accept", "application/json"}]),
+        ?assertEqual(200, Code),
+        Json = ejson:decode(Body),
+        AttJson = couch_util:get_nested_json_value(
+            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+        AttData = couch_util:get_nested_json_value(
+            AttJson, [<<"data">>]),
+        ?assertEqual(
+            <<"text/plain">>,
+            couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
+        ?assertEqual(Data, base64:decode(AttData))
+    end);
+should_get_doc_with_att_data({binary, _}, {Data, {_, DocUrl, _}}) ->
+    ?_test(begin
+        Url = DocUrl ++ "?attachments=true",
+        {ok, Code, _, Body} = test_request:get(
+            Url, [{"Accept", "application/json"}]),
+        ?assertEqual(200, Code),
+        Json = ejson:decode(Body),
+        AttJson = couch_util:get_nested_json_value(
+            Json, [<<"_attachments">>, ?ATT_BIN_NAME]),
+        AttData = couch_util:get_nested_json_value(
+            AttJson, [<<"data">>]),
+        ?assertEqual(
+            <<"image/png">>,
+            couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
+        ?assertEqual(Data, base64:decode(AttData))
+    end).
+
+should_get_doc_with_att_data_stub(compressed, {Data, {_, DocUrl, _}}) ->
+    ?_test(begin
+        Url = DocUrl ++ "?att_encoding_info=true",
+        {ok, Code, _, Body} = test_request:get(
+            Url, [{"Accept", "application/json"}]),
+        ?assertEqual(200, Code),
+        Json = ejson:decode(Body),
+        {AttJson} = couch_util:get_nested_json_value(
+            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+        ?assertEqual(<<"gzip">>,
+                     couch_util:get_value(<<"encoding">>, AttJson)),
+        AttLength = couch_util:get_value(<<"length">>, AttJson),
+        EncLength = couch_util:get_value(<<"encoded_length">>, AttJson),
+        ?assertEqual(AttLength, EncLength),
+        ?assertEqual(iolist_size(zlib:gzip(Data)), AttLength)
+    end);
+should_get_doc_with_att_data_stub({text, _}, {Data, {_, DocUrl, _}}) ->
+    ?_test(begin
+        Url = DocUrl ++ "?att_encoding_info=true",
+        {ok, Code, _, Body} = test_request:get(
+            Url, [{"Accept", "application/json"}]),
+        ?assertEqual(200, Code),
+        Json = ejson:decode(Body),
+        {AttJson} = couch_util:get_nested_json_value(
+            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+        ?assertEqual(<<"gzip">>,
+                     couch_util:get_value(<<"encoding">>, AttJson)),
+        AttEncLength = iolist_size(gzip(Data)),
+        ?assertEqual(AttEncLength,
+                     couch_util:get_value(<<"encoded_length">>, AttJson)),
+        ?assertEqual(byte_size(Data),
+                     couch_util:get_value(<<"length">>, AttJson))
+    end);
+should_get_doc_with_att_data_stub({binary, _}, {Data, {_, DocUrl, _}}) ->
+    ?_test(begin
+        Url = DocUrl ++ "?att_encoding_info=true",
+        {ok, Code, _, Body} = test_request:get(
+            Url, [{"Accept", "application/json"}]),
+        ?assertEqual(200, Code),
+        Json = ejson:decode(Body),
+        {AttJson} = couch_util:get_nested_json_value(
+            Json, [<<"_attachments">>, ?ATT_BIN_NAME]),
+        ?assertEqual(undefined,
+                     couch_util:get_value(<<"encoding">>, AttJson)),
+        ?assertEqual(undefined,
+                     couch_util:get_value(<<"encoded_length">>, AttJson)),
+        ?assertEqual(byte_size(Data),
+                     couch_util:get_value(<<"length">>, AttJson))
+    end).
+
+should_not_create_compressed_att_with_deflate_encoding({Host, DbName}) ->
+    ?_assertEqual(415,
+        begin
+            HttpHost = "http://" ++ Host,
+            AttUrl = string:join([HttpHost, DbName, ?docid(), "file.txt"], "/"),
+            {ok, Data} = file:read_file(?FIXTURE_TXT),
+            Body = zlib:compress(Data),
+            Headers = [
+                {"Content-Encoding", "deflate"},
+                {"Content-Type", "text/plain"}
+            ],
+            {ok, Code, _, _} = test_request:put(AttUrl, Headers, Body),
+            Code
+        end).
+
+should_not_create_compressed_att_with_compress_encoding({Host, DbName}) ->
+    % 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
+    ?_assertEqual(415,
+        begin
+            HttpHost = "http://" ++ Host,
+            AttUrl = string:join([HttpHost, DbName, ?docid(), "file.txt"], "/"),
+            {ok, Data} = file:read_file(?FIXTURE_TXT),
+            Headers = [
+                {"Content-Encoding", "compress"},
+                {"Content-Type", "text/plain"}
+            ],
+            {ok, Code, _, _} = test_request:put(AttUrl, Headers, Data),
+            Code
+        end).
+
+should_create_compressible_att_with_ctype_params({Host, DbName}) ->
+    {timeout, ?TIMEOUT_EUNIT, ?_test(begin
+        HttpHost = "http://" ++ Host,
+        DocUrl = string:join([HttpHost, DbName, ?docid()], "/"),
+        AttUrl = string:join([DocUrl, ?b2l(?ATT_TXT_NAME)], "/"),
+        {ok, Data} = file:read_file(?FIXTURE_TXT),
+        Headers = [{"Content-Type", "text/plain; charset=UTF-8"}],
+        {ok, Code0, _, _} = test_request:put(AttUrl, Headers, Data),
+        ?assertEqual(201, Code0),
+
+        {ok, Code1, _, Body} = test_request:get(
+            DocUrl ++ "?att_encoding_info=true"),
+        ?assertEqual(200, Code1),
+        Json = ejson:decode(Body),
+        {AttJson} = couch_util:get_nested_json_value(
+            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+        ?assertEqual(<<"gzip">>,
+                     couch_util:get_value(<<"encoding">>, AttJson)),
+        AttEncLength = iolist_size(gzip(Data)),
+        ?assertEqual(AttEncLength,
+                     couch_util:get_value(<<"encoded_length">>, AttJson)),
+        ?assertEqual(byte_size(Data),
+                     couch_util:get_value(<<"length">>, AttJson))
+    end)}.
+
+
+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.
+
+chunked_body(Chunks) ->
+    chunked_body(Chunks, []).
+
+chunked_body([], Acc) ->
+    iolist_to_binary(lists:reverse(Acc, "0\r\n"));
+chunked_body([Chunk | Rest], Acc) ->
+    Size = to_hex(size(Chunk)),
+    chunked_body(Rest, ["\r\n", Chunk, "\r\n", Size | Acc]).
+
+get_socket() ->
+    Options = [binary, {packet, 0}, {active, false}],
+    Addr = couch_config:get("httpd", "bind_address", any),
+    Port = mochiweb_socket_server:get(couch_httpd, port),
+    {ok, Sock} = gen_tcp:connect(Addr, Port, Options),
+    Sock.
+
+request(Method, Url, Headers, Body) ->
+    RequestHead = [Method, " ", Url, " HTTP/1.1"],
+    RequestHeaders = [[string:join([Key, Value], ": "), "\r\n"]
+                      || {Key, Value} <- Headers],
+    Request = [RequestHead, "\r\n", RequestHeaders, "\r\n", Body, "\r\n"],
+    Sock = get_socket(),
+    gen_tcp:send(Sock, list_to_binary(lists:flatten(Request))),
+    timer:sleep(?TIMEWAIT),  % must wait to receive complete response
+    {ok, R} = gen_tcp:recv(Sock, 0),
+    gen_tcp:close(Sock),
+    [Header, Body1] = re:split(R, "\r\n\r\n", [{return, binary}]),
+    {ok, {http_response, _, Code, _}, _} =
+        erlang:decode_packet(http, Header, []),
+    Json = ejson:decode(Body1),
+    {ok, Code, Json}.
+
+create_standalone_text_att(Host, DbName) ->
+    {ok, Data} = file:read_file(?FIXTURE_TXT),
+    Url = string:join([Host, DbName, "doc", ?b2l(?ATT_TXT_NAME)], "/"),
+    {ok, Code, _Headers, _Body} = test_request:put(
+        Url, [{"Content-Type", "text/plain"}], Data),
+    ?assertEqual(201, Code),
+    Url.
+
+create_standalone_png_att(Host, DbName) ->
+    {ok, Data} = file:read_file(?FIXTURE_PNG),
+    Url = string:join([Host, DbName, "doc", ?b2l(?ATT_BIN_NAME)], "/"),
+    {ok, Code, _Headers, _Body} = test_request:put(
+        Url, [{"Content-Type", "image/png"}], Data),
+    ?assertEqual(201, Code),
+    Url.
+
+create_inline_text_att(Host, DbName) ->
+    {ok, Data} = file:read_file(?FIXTURE_TXT),
+    Url = string:join([Host, DbName, "doc"], "/"),
+    Doc = {[
+        {<<"_attachments">>, {[
+            {?ATT_TXT_NAME, {[
+                {<<"content_type">>, <<"text/plain">>},
+                {<<"data">>, base64:encode(Data)}
+            ]}
+        }]}}
+    ]},
+    {ok, Code, _Headers, _Body} = test_request:put(
+        Url, [{"Content-Type", "application/json"}], ejson:encode(Doc)),
+    ?assertEqual(201, Code),
+    string:join([Url, ?b2l(?ATT_TXT_NAME)], "/").
+
+create_inline_png_att(Host, DbName) ->
+    {ok, Data} = file:read_file(?FIXTURE_PNG),
+    Url = string:join([Host, DbName, "doc"], "/"),
+    Doc = {[
+        {<<"_attachments">>, {[
+            {?ATT_BIN_NAME, {[
+                {<<"content_type">>, <<"image/png">>},
+                {<<"data">>, base64:encode(Data)}
+            ]}
+        }]}}
+    ]},
+    {ok, Code, _Headers, _Body} = test_request:put(
+        Url, [{"Content-Type", "application/json"}], ejson:encode(Doc)),
+    ?assertEqual(201, Code),
+    string:join([Url, ?b2l(?ATT_BIN_NAME)], "/").
+
+create_already_compressed_att(Host, DbName) ->
+    {ok, Data} = file:read_file(?FIXTURE_TXT),
+    Url = string:join([Host, DbName, "doc", ?b2l(?ATT_TXT_NAME)], "/"),
+    {ok, Code, _Headers, _Body} = test_request:put(
+        Url, [{"Content-Type", "text/plain"}, {"Content-Encoding", "gzip"}],
+        zlib:gzip(Data)),
+    ?assertEqual(201, Code),
+    Url.
+
+gzip(Data) ->
+    Z = zlib:open(),
+    ok = zlib:deflateInit(Z, ?COMPRESSION_LEVEL, deflated, 16 + 15, 8, default),
+    zlib:deflate(Z, Data),
+    Last = zlib:deflate(Z, [], finish),
+    ok = zlib:deflateEnd(Z),
+    ok = zlib:close(Z),
+    Last.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb_compaction_daemon.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_compaction_daemon.erl b/test/couchdb_compaction_daemon.erl
new file mode 100644
index 0000000..725a97b
--- /dev/null
+++ b/test/couchdb_compaction_daemon.erl
@@ -0,0 +1,231 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_compaction_daemon).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
+-define(DELAY, 100).
+-define(TIMEOUT, 30000).
+-define(TIMEOUT_S, ?TIMEOUT div 1000).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    couch_config:set("compaction_daemon", "check_interval", "3", false),
+    couch_config:set("compaction_daemon", "min_file_size", "100000", false),
+    Pid.
+
+stop(Pid) ->
+    erlang:monitor(process, Pid),
+    couch_server_sup:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+    create_design_doc(Db),
+    ok = couch_db:close(Db),
+    DbName.
+
+teardown(DbName) ->
+    Configs = couch_config:get("compactions"),
+    lists:foreach(
+        fun({Key, _}) ->
+            ok = couch_config:delete("compactions", Key, false)
+        end,
+        Configs),
+    couch_server:delete(DbName, [?ADMIN_USER]),
+    ok.
+
+
+compaction_daemon_test_() ->
+    {
+        "Compaction daemon tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    fun should_compact_by_default_rule/1,
+                    fun should_compact_by_dbname_rule/1
+                ]
+            }
+        }
+    }.
+
+
+should_compact_by_default_rule(DbName) ->
+    {timeout, ?TIMEOUT_S, ?_test(begin
+        {ok, Db} = couch_db:open_int(DbName, []),
+        populate(DbName, 70, 70, 200 * 1024),
+
+        {_, DbFileSize} = get_db_frag(DbName),
+        {_, ViewFileSize} = get_view_frag(DbName),
+
+        ok = couch_config:set("compactions", "_default",
+            "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]",
+            false),
+
+        ok = timer:sleep(4000), % something >= check_interval
+        wait_compaction_finished(DbName),
+        ok = couch_config:delete("compactions", "_default", false),
+
+        {DbFrag2, DbFileSize2} = get_db_frag(DbName),
+        {ViewFrag2, ViewFileSize2} = get_view_frag(DbName),
+
+        ?assert(DbFrag2 < 70),
+        ?assert(ViewFrag2 < 70),
+
+        ?assert(DbFileSize > DbFileSize2),
+        ?assert(ViewFileSize > ViewFileSize2),
+
+        ?assert(couch_db:is_idle(Db)),
+        ok = couch_db:close(Db)
+    end)}.
+
+should_compact_by_dbname_rule(DbName) ->
+    {timeout, ?TIMEOUT_S, ?_test(begin
+        {ok, Db} = couch_db:open_int(DbName, []),
+        populate(DbName, 70, 70, 200 * 1024),
+
+        {_, DbFileSize} = get_db_frag(DbName),
+        {_, ViewFileSize} = get_view_frag(DbName),
+
+        ok = couch_config:set("compactions", ?b2l(DbName),
+            "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]",
+            false),
+
+        ok = timer:sleep(4000), % something >= check_interval
+        wait_compaction_finished(DbName),
+        ok = couch_config:delete("compactions", ?b2l(DbName), false),
+
+        {DbFrag2, DbFileSize2} = get_db_frag(DbName),
+        {ViewFrag2, ViewFileSize2} = get_view_frag(DbName),
+
+        ?assert(DbFrag2 < 70),
+        ?assert(ViewFrag2 < 70),
+
+        ?assert(DbFileSize > DbFileSize2),
+        ?assert(ViewFileSize > ViewFileSize2),
+
+        ?assert(couch_db:is_idle(Db)),
+        ok = couch_db:close(Db)
+    end)}.
+
+
+create_design_doc(Db) ->
+    DDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, <<"_design/foo">>},
+        {<<"language">>, <<"javascript">>},
+        {<<"views">>, {[
+            {<<"foo">>, {[
+                {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>}
+            ]}},
+            {<<"foo2">>, {[
+                {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>}
+            ]}},
+            {<<"foo3">>, {[
+                {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>}
+            ]}}
+        ]}}
+    ]}),
+    {ok, _} = couch_db:update_docs(Db, [DDoc]),
+    {ok, _} = couch_db:ensure_full_commit(Db),
+    ok.
+
+populate(DbName, DbFrag, ViewFrag, MinFileSize) ->
+    {CurDbFrag, DbFileSize} = get_db_frag(DbName),
+    {CurViewFrag, ViewFileSize} = get_view_frag(DbName),
+    populate(DbName, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag,
+             lists:min([DbFileSize, ViewFileSize])).
+
+populate(_Db, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag, FileSize)
+    when CurDbFrag >= DbFrag, CurViewFrag >= ViewFrag, FileSize >= MinFileSize ->
+    ok;
+populate(DbName, DbFrag, ViewFrag, MinFileSize, _, _, _) ->
+    update(DbName),
+    {CurDbFrag, DbFileSize} = get_db_frag(DbName),
+    {CurViewFrag, ViewFileSize} = get_view_frag(DbName),
+    populate(DbName, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag,
+             lists:min([DbFileSize, ViewFileSize])).
+
+update(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    lists:foreach(fun(_) ->
+        Doc = couch_doc:from_json_obj({[{<<"_id">>, couch_uuids:new()}]}),
+        {ok, _} = couch_db:update_docs(Db, [Doc]),
+        query_view(Db#db.name)
+    end, lists:seq(1, 200)),
+    couch_db:close(Db).
+
+db_url(DbName) ->
+    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+    "http://" ++ Addr ++ ":" ++ Port ++ "/" ++ ?b2l(DbName).
+
+query_view(DbName) ->
+    {ok, Code, _Headers, _Body} = test_request:get(
+        db_url(DbName) ++ "/_design/foo/_view/foo"),
+    ?assertEqual(200, Code).
+
+get_db_frag(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, Info} = couch_db:get_db_info(Db),
+    couch_db:close(Db),
+    FileSize = couch_util:get_value(disk_size, Info),
+    DataSize = couch_util:get_value(data_size, Info),
+    {round((FileSize - DataSize) / FileSize * 100), FileSize}.
+
+get_view_frag(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, Info} = couch_mrview:get_info(Db, <<"_design/foo">>),
+    couch_db:close(Db),
+    FileSize = couch_util:get_value(disk_size, Info),
+    DataSize = couch_util:get_value(data_size, Info),
+    {round((FileSize - DataSize) / FileSize * 100), FileSize}.
+
+wait_compaction_finished(DbName) ->
+    Parent = self(),
+    Loop = spawn_link(fun() -> wait_loop(DbName, Parent) end),
+    receive
+        {done, Loop} ->
+            ok
+    after ?TIMEOUT ->
+        erlang:error(
+            {assertion_failed,
+             [{module, ?MODULE}, {line, ?LINE},
+              {reason, "Compaction timeout"}]})
+    end.
+
+wait_loop(DbName, Parent) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, DbInfo} = couch_db:get_db_info(Db),
+    {ok, ViewInfo} = couch_mrview:get_info(Db, <<"_design/foo">>),
+    couch_db:close(Db),
+    case (couch_util:get_value(compact_running, ViewInfo) =:= true) orelse
+        (couch_util:get_value(compact_running, DbInfo) =:= true) of
+        false ->
+            Parent ! {done, self()};
+        true ->
+            ok = timer:sleep(?DELAY),
+            wait_loop(DbName, Parent)
+    end.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb_cors_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_cors_tests.erl b/test/couchdb_cors_tests.erl
new file mode 100644
index 0000000..4e88ae7
--- /dev/null
+++ b/test/couchdb_cors_tests.erl
@@ -0,0 +1,344 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_cors_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+
+-define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
+-define(SUPPORTED_METHODS,
+        "GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, COPY, OPTIONS").
+-define(TIMEOUT, 1000).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    ok = couch_config:set("httpd", "enable_cors", "true", false),
+    ok = couch_config:set("vhosts", "example.com", "/", false),
+    Pid.
+
+stop(Pid) ->
+    couch_server_sup:stop(),
+    erlang:monitor(process, Pid),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+    couch_db:close(Db),
+
+    couch_config:set("cors", "credentials", "false", false),
+    couch_config:set("cors", "origins", "http://example.com", false),
+
+    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+    Host = "http://" ++ Addr ++ ":" ++ Port,
+    {Host, ?b2l(DbName)}.
+
+setup({Mod, VHost}) ->
+    {Host, DbName} = setup(),
+    Url = case Mod of
+        server ->
+            Host;
+        db ->
+            Host ++ "/" ++ DbName
+    end,
+    DefaultHeaders = [{"Origin", "http://example.com"}]
+                     ++ maybe_append_vhost(VHost),
+    {Host, DbName, Url, DefaultHeaders}.
+
+teardown(DbName) when is_list(DbName) ->
+    ok = couch_server:delete(?l2b(DbName), [?ADMIN_USER]),
+    ok;
+teardown({_, DbName}) ->
+    teardown(DbName).
+
+teardown(_, {_, DbName, _, _}) ->
+    teardown(DbName).
+
+
+cors_test_() ->
+    Funs = [
+        fun should_not_allow_origin/2,
+        fun should_not_allow_origin_with_port_mismatch/2,
+        fun should_not_allow_origin_with_scheme_mismatch/2,
+        fun should_not_all_origin_due_case_mismatch/2,
+        fun should_make_simple_request/2,
+        fun should_make_preflight_request/2,
+        fun should_make_prefligh_request_with_port/2,
+        fun should_make_prefligh_request_with_scheme/2,
+        fun should_make_prefligh_request_with_wildcard_origin/2,
+        fun should_make_request_with_credentials/2,
+        fun should_make_origin_request_with_auth/2,
+        fun should_make_preflight_request_with_auth/2
+    ],
+    {
+        "CORS (COUCHDB-431)",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            [
+                cors_tests(Funs),
+                vhost_cors_tests(Funs),
+                headers_tests()
+            ]
+        }
+    }.
+
+headers_tests() ->
+    {
+        "Various headers tests",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_not_return_cors_headers_for_invalid_origin/1,
+                fun should_not_return_cors_headers_for_invalid_origin_preflight/1,
+                fun should_make_request_against_attachment/1,
+                fun should_make_range_request_against_attachment/1,
+                fun should_make_request_with_if_none_match_header/1
+            ]
+        }
+    }.
+
+cors_tests(Funs) ->
+    {
+        "CORS tests",
+        [
+            make_test_case(server, false, Funs),
+            make_test_case(db, false, Funs)
+        ]
+    }.
+
+vhost_cors_tests(Funs) ->
+    {
+        "Virtual Host CORS",
+        [
+            make_test_case(server, true, Funs),
+            make_test_case(db, true, Funs)
+        ]
+    }.
+
+make_test_case(Mod, UseVhost, Funs) ->
+    {
+        case Mod of server -> "Server"; db -> "Database" end,
+        {foreachx, fun setup/1, fun teardown/2, [{{Mod, UseVhost}, Fun}
+                                                 || Fun <- Funs]}
+    }.
+
+
+should_not_allow_origin(_, {_, _, Url, Headers0}) ->
+    ?_assertEqual(undefined,
+        begin
+            couch_config:delete("cors", "origins", false),
+            Headers1 = proplists:delete("Origin", Headers0),
+            Headers = [{"Origin", "http://127.0.0.1"}]
+                      ++ Headers1,
+            {ok, _, Resp, _} = test_request:get(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_not_allow_origin_with_port_mismatch({_, VHost}, {_, _, Url, _}) ->
+    ?_assertEqual(undefined,
+        begin
+            Headers = [{"Origin", "http://example.com:5984"},
+                       {"Access-Control-Request-Method", "GET"}]
+                      ++ maybe_append_vhost(VHost),
+            {ok, _, Resp, _} = test_request:options(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_not_allow_origin_with_scheme_mismatch({_, VHost}, {_, _, Url, _}) ->
+    ?_assertEqual(undefined,
+        begin
+            Headers = [{"Origin", "http://example.com:5984"},
+                       {"Access-Control-Request-Method", "GET"}]
+                      ++ maybe_append_vhost(VHost),
+            {ok, _, Resp, _} = test_request:options(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_not_all_origin_due_case_mismatch({_, VHost}, {_, _, Url, _}) ->
+    ?_assertEqual(undefined,
+        begin
+            Headers = [{"Origin", "http://ExAmPlE.CoM"},
+                       {"Access-Control-Request-Method", "GET"}]
+                      ++ maybe_append_vhost(VHost),
+            {ok, _, Resp, _} = test_request:options(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_make_simple_request(_, {_, _, Url, DefaultHeaders}) ->
+    ?_test(begin
+        {ok, _, Resp, _} = test_request:get(Url, DefaultHeaders),
+        ?assertEqual(
+            undefined,
+            proplists:get_value("Access-Control-Allow-Credentials", Resp)),
+        ?assertEqual(
+            "http://example.com",
+            proplists:get_value("Access-Control-Allow-Origin", Resp)),
+        ?assertEqual(
+            "Cache-Control, Content-Type, Server",
+            proplists:get_value("Access-Control-Expose-Headers", Resp))
+    end).
+
+should_make_preflight_request(_, {_, _, Url, DefaultHeaders}) ->
+    ?_assertEqual(?SUPPORTED_METHODS,
+        begin
+            Headers = DefaultHeaders
+                      ++ [{"Access-Control-Request-Method", "GET"}],
+            {ok, _, Resp, _} = test_request:options(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Methods", Resp)
+        end).
+
+should_make_prefligh_request_with_port({_, VHost}, {_, _, Url, _}) ->
+    ?_assertEqual("http://example.com:5984",
+        begin
+            couch_config:set("cors", "origins", "http://example.com:5984",
+                             false),
+            Headers = [{"Origin", "http://example.com:5984"},
+                       {"Access-Control-Request-Method", "GET"}]
+                      ++ maybe_append_vhost(VHost),
+            {ok, _, Resp, _} = test_request:options(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_make_prefligh_request_with_scheme({_, VHost}, {_, _, Url, _}) ->
+    ?_assertEqual("https://example.com:5984",
+        begin
+            couch_config:set("cors", "origins", "https://example.com:5984",
+                             false),
+            Headers = [{"Origin", "https://example.com:5984"},
+                       {"Access-Control-Request-Method", "GET"}]
+                      ++ maybe_append_vhost(VHost),
+            {ok, _, Resp, _} = test_request:options(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_make_prefligh_request_with_wildcard_origin({_, VHost}, {_, _, Url, _}) ->
+    ?_assertEqual("https://example.com:5984",
+        begin
+            couch_config:set("cors", "origins", "*", false),
+            Headers = [{"Origin", "https://example.com:5984"},
+                       {"Access-Control-Request-Method", "GET"}]
+                      ++ maybe_append_vhost(VHost),
+            {ok, _, Resp, _} = test_request:options(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_make_request_with_credentials(_, {_, _, Url, DefaultHeaders}) ->
+    ?_assertEqual("true",
+        begin
+            ok = couch_config:set("cors", "credentials", "true", false),
+            {ok, _, Resp, _} = test_request:options(Url, DefaultHeaders),
+            proplists:get_value("Access-Control-Allow-Credentials", Resp)
+        end).
+
+should_make_origin_request_with_auth(_, {_, _, Url, DefaultHeaders}) ->
+    ?_assertEqual("http://example.com",
+        begin
+            Hashed = couch_passwords:hash_admin_password(<<"test">>),
+            couch_config:set("admins", "test", Hashed, false),
+            {ok, _, Resp, _} = test_request:get(
+                Url, DefaultHeaders, [{basic_auth, {"test", "test"}}]),
+            couch_config:delete("admins", "test", false),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_make_preflight_request_with_auth(_, {_, _, Url, DefaultHeaders}) ->
+    ?_assertEqual(?SUPPORTED_METHODS,
+        begin
+            Hashed = couch_passwords:hash_admin_password(<<"test">>),
+            couch_config:set("admins", "test", Hashed, false),
+            Headers = DefaultHeaders
+                      ++ [{"Access-Control-Request-Method", "GET"}],
+            {ok, _, Resp, _} = test_request:options(
+                Url, Headers, [{basic_auth, {"test", "test"}}]),
+            couch_config:delete("admins", "test", false),
+            proplists:get_value("Access-Control-Allow-Methods", Resp)
+        end).
+
+should_not_return_cors_headers_for_invalid_origin({Host, _}) ->
+    ?_assertEqual(undefined,
+        begin
+            Headers = [{"Origin", "http://127.0.0.1"}],
+            {ok, _, Resp, _} = test_request:get(Host, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_not_return_cors_headers_for_invalid_origin_preflight({Host, _}) ->
+    ?_assertEqual(undefined,
+        begin
+            Headers = [{"Origin", "http://127.0.0.1"},
+                       {"Access-Control-Request-Method", "GET"}],
+            {ok, _, Resp, _} = test_request:options(Host, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_make_request_against_attachment({Host, DbName}) ->
+    {"COUCHDB-1689",
+     ?_assertEqual(200,
+         begin
+             Url = Host ++ "/" ++ DbName,
+             {ok, Code0, _, _} = test_request:put(
+                 Url ++ "/doc/file.txt", [{"Content-Type", "text/plain"}],
+                 "hello, couch!"),
+             ?assert(Code0 =:= 201),
+             {ok, Code, _, _} = test_request:get(
+                 Url ++ "/doc?attachments=true",
+                 [{"Origin", "http://example.com"}]),
+             Code
+         end)}.
+
+should_make_range_request_against_attachment({Host, DbName}) ->
+    {"COUCHDB-1689",
+     ?_assertEqual(206,
+         begin
+             Url = Host ++ "/" ++ DbName,
+             {ok, Code0, _, _} = test_request:put(
+                 Url ++ "/doc/file.txt",
+                 [{"Content-Type", "application/octet-stream"}],
+                 "hello, couch!"),
+             ?assert(Code0 =:= 201),
+             {ok, Code, _, _} = test_request:get(
+                 Url ++ "/doc/file.txt", [{"Origin", "http://example.com"},
+                                          {"Range", "bytes=0-6"}]),
+             Code
+         end)}.
+
+should_make_request_with_if_none_match_header({Host, DbName}) ->
+    {"COUCHDB-1697",
+     ?_assertEqual(304,
+         begin
+             Url = Host ++ "/" ++ DbName,
+             {ok, Code0, Headers0, _} = test_request:put(
+                 Url ++ "/doc", [{"Content-Type", "application/json"}], "{}"),
+             ?assert(Code0 =:= 201),
+             ETag = proplists:get_value("ETag", Headers0),
+             {ok, Code, _, _} = test_request:get(
+                 Url ++ "/doc", [{"Origin", "http://example.com"},
+                                 {"If-None-Match", ETag}]),
+             Code
+        end)}.
+
+
+maybe_append_vhost(true) ->
+    [{"Host", "http://example.com"}];
+maybe_append_vhost(false) ->
+    [].

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb_csp_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_csp_tests.erl b/test/couchdb_csp_tests.erl
new file mode 100644
index 0000000..adb0e6d
--- /dev/null
+++ b/test/couchdb_csp_tests.erl
@@ -0,0 +1,96 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_csp_tests).
+
+-include("couch_eunit.hrl").
+
+-define(TIMEOUT, 1000).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    Pid.
+
+stop(Pid) ->
+    couch_server_sup:stop(),
+    erlang:monitor(process, Pid),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    ok = couch_config:set("csp", "enable", "true", false),
+    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+    lists:concat(["http://", Addr, ":", Port, "/_utils/"]).
+
+teardown(_) ->
+    ok.
+
+
+csp_test_() ->
+    {
+        "Content Security Policy tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    fun should_not_return_any_csp_headers_when_disabled/1,
+                    fun should_apply_default_policy/1,
+                    fun should_return_custom_policy/1,
+                    fun should_only_enable_csp_when_true/1
+                ]
+            }
+        }
+    }.
+
+
+should_not_return_any_csp_headers_when_disabled(Url) ->
+    ?_assertEqual(undefined,
+        begin
+            ok = couch_config:set("csp", "enable", "false", false),
+            {ok, _, Headers, _} = test_request:get(Url),
+            proplists:get_value("Content-Security-Policy", Headers)
+        end).
+
+should_apply_default_policy(Url) ->
+    ?_assertEqual(
+        "default-src 'self'; img-src 'self'; font-src 'self'; "
+        "script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline';",
+        begin
+            {ok, _, Headers, _} = test_request:get(Url),
+            proplists:get_value("Content-Security-Policy", Headers)
+        end).
+
+should_return_custom_policy(Url) ->
+    ?_assertEqual("default-src 'http://example.com';",
+        begin
+            ok = couch_config:set("csp", "header_value",
+                                  "default-src 'http://example.com';", false),
+            {ok, _, Headers, _} = test_request:get(Url),
+            proplists:get_value("Content-Security-Policy", Headers)
+        end).
+
+should_only_enable_csp_when_true(Url) ->
+    ?_assertEqual(undefined,
+        begin
+            ok = couch_config:set("csp", "enable", "tru", false),
+            {ok, _, Headers, _} = test_request:get(Url),
+            proplists:get_value("Content-Security-Policy", Headers)
+        end).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb_file_compression_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_file_compression_tests.erl b/test/couchdb_file_compression_tests.erl
new file mode 100644
index 0000000..fd3f513
--- /dev/null
+++ b/test/couchdb_file_compression_tests.erl
@@ -0,0 +1,239 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_file_compression_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
+-define(DDOC_ID, <<"_design/test">>).
+-define(DOCS_COUNT, 5000).
+-define(TIMEOUT, 30000).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    Pid.
+
+stop(Pid) ->
+    erlang:monitor(process, Pid),
+    couch_server_sup:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    couch_config:set("couchdb", "file_compression", "none", false),
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+    ok = populate_db(Db, ?DOCS_COUNT),
+    DDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, ?DDOC_ID},
+        {<<"language">>, <<"javascript">>},
+        {<<"views">>, {[
+                {<<"by_id">>, {[
+                    {<<"map">>, <<"function(doc){emit(doc._id, doc.string);}">>}
+                ]}}
+            ]}
+        }
+    ]}),
+    {ok, _} = couch_db:update_doc(Db, DDoc, []),
+    refresh_index(DbName),
+    ok = couch_db:close(Db),
+    DbName.
+
+teardown(DbName) ->
+    ok = couch_server:delete(DbName, [?ADMIN_USER]),
+    ok.
+
+
+couch_auth_cache_test_() ->
+    {
+        "CouchDB file compression tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    fun should_use_none/1,
+                    fun should_use_deflate_1/1,
+                    fun should_use_deflate_9/1,
+                    fun should_use_snappy/1,
+                    fun should_compare_compression_methods/1
+                ]
+            }
+        }
+    }.
+
+
+should_use_none(DbName) ->
+    couch_config:set("couchdb", "file_compression", "none", false),
+    {
+        "Use no compression",
+        [
+            {"compact database", ?_test(compact_db(DbName))},
+            {"compact view", ?_test(compact_view(DbName))}
+        ]
+    }.
+
+should_use_deflate_1(DbName) ->
+    couch_config:set("couchdb", "file_compression", "deflate_1", false),
+    {
+        "Use deflate compression at level 1",
+        [
+            {"compact database", ?_test(compact_db(DbName))},
+            {"compact view", ?_test(compact_view(DbName))}
+        ]
+    }.
+
+should_use_deflate_9(DbName) ->
+    couch_config:set("couchdb", "file_compression", "deflate_9", false),
+    {
+        "Use deflate compression at level 9",
+        [
+            {"compact database", ?_test(compact_db(DbName))},
+            {"compact view", ?_test(compact_view(DbName))}
+        ]
+    }.
+
+should_use_snappy(DbName) ->
+    couch_config:set("couchdb", "file_compression", "snappy", false),
+    {
+        "Use snappy compression",
+        [
+            {"compact database", ?_test(compact_db(DbName))},
+            {"compact view", ?_test(compact_view(DbName))}
+        ]
+    }.
+
+should_compare_compression_methods(DbName) ->
+    {"none > snappy > deflate_1 > deflate_9",
+     {timeout, ?TIMEOUT div 1000, ?_test(compare_compression_methods(DbName))}}.
+
+compare_compression_methods(DbName) ->
+    couch_config:set("couchdb", "file_compression", "none", false),
+    compact_db(DbName),
+    compact_view(DbName),
+    DbSizeNone = db_disk_size(DbName),
+    ViewSizeNone = view_disk_size(DbName),
+
+    couch_config:set("couchdb", "file_compression", "snappy", false),
+    compact_db(DbName),
+    compact_view(DbName),
+    DbSizeSnappy = db_disk_size(DbName),
+    ViewSizeSnappy = view_disk_size(DbName),
+
+    ?assert(DbSizeNone > DbSizeSnappy),
+    ?assert(ViewSizeNone > ViewSizeSnappy),
+
+    couch_config:set("couchdb", "file_compression", "deflate_1", false),
+    compact_db(DbName),
+    compact_view(DbName),
+    DbSizeDeflate1 = db_disk_size(DbName),
+    ViewSizeDeflate1 = view_disk_size(DbName),
+
+    ?assert(DbSizeSnappy > DbSizeDeflate1),
+    ?assert(ViewSizeSnappy > ViewSizeDeflate1),
+
+    couch_config:set("couchdb", "file_compression", "deflate_9", false),
+    compact_db(DbName),
+    compact_view(DbName),
+    DbSizeDeflate9 = db_disk_size(DbName),
+    ViewSizeDeflate9 = view_disk_size(DbName),
+
+    ?assert(DbSizeDeflate1 > DbSizeDeflate9),
+    ?assert(ViewSizeDeflate1 > ViewSizeDeflate9).
+
+
+populate_db(_Db, NumDocs) when NumDocs =< 0 ->
+    ok;
+populate_db(Db, NumDocs) ->
+    Docs = lists:map(
+        fun(_) ->
+            couch_doc:from_json_obj({[
+                {<<"_id">>, couch_uuids:random()},
+                {<<"string">>, ?l2b(lists:duplicate(1000, $X))}
+            ]})
+        end,
+        lists:seq(1, 500)),
+    {ok, _} = couch_db:update_docs(Db, Docs, []),
+    populate_db(Db, NumDocs - 500).
+
+refresh_index(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, DDoc} = couch_db:open_doc(Db, ?DDOC_ID, [ejson_body]),
+    couch_mrview:query_view(Db, DDoc, <<"by_id">>, [{stale, false}]),
+    ok = couch_db:close(Db).
+
+compact_db(DbName) ->
+    DiskSizeBefore = db_disk_size(DbName),
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, CompactPid} = couch_db:start_compact(Db),
+    MonRef = erlang:monitor(process, CompactPid),
+    receive
+        {'DOWN', MonRef, process, CompactPid, normal} ->
+            ok;
+        {'DOWN', MonRef, process, CompactPid, Reason} ->
+            erlang:error({assertion_failed,
+                          [{module, ?MODULE},
+                           {line, ?LINE},
+                           {reason, "Error compacting database: "
+                                    ++ couch_util:to_list(Reason)}]})
+    after ?TIMEOUT ->
+        erlang:error({assertion_failed,
+                      [{module, ?MODULE},
+                       {line, ?LINE},
+                       {reason, "Timeout waiting for database compaction"}]})
+    end,
+    ok = couch_db:close(Db),
+    DiskSizeAfter = db_disk_size(DbName),
+    ?assert(DiskSizeBefore > DiskSizeAfter).
+
+compact_view(DbName) ->
+    DiskSizeBefore = view_disk_size(DbName),
+    {ok, MonRef} = couch_mrview:compact(DbName, ?DDOC_ID, [monitor]),
+    receive
+        {'DOWN', MonRef, process, _CompactPid, normal} ->
+            ok;
+        {'DOWN', MonRef, process, _CompactPid, Reason} ->
+            erlang:error({assertion_failed,
+                          [{module, ?MODULE},
+                           {line, ?LINE},
+                           {reason, "Error compacting view group: "
+                                    ++ couch_util:to_list(Reason)}]})
+    after ?TIMEOUT ->
+        erlang:error({assertion_failed,
+                      [{module, ?MODULE},
+                       {line, ?LINE},
+                       {reason, "Timeout waiting for view group compaction"}]})
+    end,
+    DiskSizeAfter = view_disk_size(DbName),
+    ?assert(DiskSizeBefore > DiskSizeAfter).
+
+db_disk_size(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, Info} = couch_db:get_db_info(Db),
+    ok = couch_db:close(Db),
+    couch_util:get_value(disk_size, Info).
+
+view_disk_size(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, DDoc} = couch_db:open_doc(Db, ?DDOC_ID, [ejson_body]),
+    {ok, Info} = couch_mrview:get_info(Db, DDoc),
+    ok = couch_db:close(Db),
+    couch_util:get_value(disk_size, Info).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb_http_proxy_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_http_proxy_tests.erl b/test/couchdb_http_proxy_tests.erl
new file mode 100644
index 0000000..acb1974
--- /dev/null
+++ b/test/couchdb_http_proxy_tests.erl
@@ -0,0 +1,462 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_http_proxy_tests).
+
+-include("couch_eunit.hrl").
+
+-record(req, {method=get, path="", headers=[], body="", opts=[]}).
+
+-define(CONFIG_FIXTURE_TEMP,
+    begin
+        FileName = filename:join([?TEMPDIR, ?tempfile() ++ ".ini"]),
+        {ok, Fd} = file:open(FileName, write),
+        ok = file:truncate(Fd),
+        ok = file:close(Fd),
+        FileName
+    end).
+-define(TIMEOUT, 5000).
+
+
+start() ->
+    % we have to write any config changes to temp ini file to not loose them
+    % when supervisor will kill all children due to reaching restart threshold
+    % (each httpd_global_handlers changes causes couch_httpd restart)
+    couch_server_sup:start_link(?CONFIG_CHAIN ++ [?CONFIG_FIXTURE_TEMP]),
+    % 49151 is IANA Reserved, let's assume no one is listening there
+    couch_config:set("httpd_global_handlers", "_error",
+        "{couch_httpd_proxy, handle_proxy_req, <<\"http://127.0.0.1:49151/\">>}"
+    ),
+    ok.
+
+stop(_) ->
+    couch_server_sup:stop(),
+    ok.
+
+setup() ->
+    {ok, Pid} = test_web:start_link(),
+    Value = lists:flatten(io_lib:format(
+        "{couch_httpd_proxy, handle_proxy_req, ~p}",
+        [list_to_binary(proxy_url())])),
+    couch_config:set("httpd_global_handlers", "_test", Value),
+    % let couch_httpd restart
+    timer:sleep(100),
+    Pid.
+
+teardown(Pid) ->
+    erlang:monitor(process, Pid),
+    test_web:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, test_web_stop})
+    end.
+
+
+http_proxy_test_() ->
+    {
+        "HTTP Proxy handler tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    fun should_proxy_basic_request/1,
+                    fun should_return_alternative_status/1,
+                    fun should_respect_trailing_slash/1,
+                    fun should_proxy_headers/1,
+                    fun should_proxy_host_header/1,
+                    fun should_pass_headers_back/1,
+                    fun should_use_same_protocol_version/1,
+                    fun should_proxy_body/1,
+                    fun should_proxy_body_back/1,
+                    fun should_proxy_chunked_body/1,
+                    fun should_proxy_chunked_body_back/1,
+                    fun should_rewrite_location_header/1,
+                    fun should_not_rewrite_external_locations/1,
+                    fun should_rewrite_relative_location/1,
+                    fun should_refuse_connection_to_backend/1
+                ]
+            }
+
+        }
+    }.
+
+
+should_proxy_basic_request(_) ->
+    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,
+    ?_test(check_request(#req{}, Remote, Local)).
+
+should_return_alternative_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"},
+    ?_test(check_request(Req, Remote, Local)).
+
+should_respect_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/"},
+    ?_test(check_request(Req, Remote, Local)).
+
+should_proxy_headers(_) ->
+    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"}]
+    },
+    ?_test(check_request(Req, Remote, Local)).
+
+should_proxy_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"}]
+    },
+    ?_test(check_request(Req, Remote, Local)).
+
+should_pass_headers_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"},
+    ?_test(check_request(Req, Remote, Local)).
+
+should_use_same_protocol_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}}]
+    },
+    ?_test(check_request(Req, Remote, Local)).
+
+should_proxy_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!"
+    },
+    ?_test(check_request(Req, Remote, Local)).
+
+should_proxy_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"},
+    ?_test(check_request(Req, Remote, Local)).
+
+should_proxy_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=chunked_body(BodyChunks)
+    },
+    ?_test(check_request(Req, Remote, Local)).
+
+should_proxy_chunked_body_back(_) ->
+    ?_test(begin
+        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(Req, Remote, no_local),
+        ?assertMatch({ibrowse_req_id, _}, Resp),
+        {_, ReqId} = Resp,
+
+        % Grab headers from response
+        receive
+            {ibrowse_async_headers, ReqId, "200", Headers} ->
+                ?assertEqual("chunked",
+                             proplists:get_value("Transfer-Encoding", Headers)),
+            ibrowse:stream_next(ReqId)
+        after 1000 ->
+            throw({error, timeout})
+        end,
+
+        ?assertEqual(<<"foobarbazinga">>, recv_body(ReqId, [])),
+        ?assertEqual(was_ok, test_web:check_last())
+    end).
+
+should_refuse_connection_to_backend(_) ->
+    Local = fun
+        ({ok, "500", _, _}) ->
+            true;
+        (_) ->
+            false
+    end,
+    Req = #req{opts=[{url, server_url("/_error")}]},
+    ?_test(check_request(Req, no_remote, Local)).
+
+should_rewrite_location_header(_) ->
+    {
+        "Testing location header rewrites",
+        do_rewrite_tests([
+            {"Location", proxy_url() ++ "/foo/bar",
+                         server_url() ++ "/foo/bar"},
+            {"Content-Location", proxy_url() ++ "/bing?q=2",
+                                 server_url() ++ "/bing?q=2"},
+            {"Uri", proxy_url() ++ "/zip#frag",
+                    server_url() ++ "/zip#frag"},
+            {"Destination", proxy_url(),
+                            server_url() ++ "/"}
+        ])
+    }.
+
+should_not_rewrite_external_locations(_) ->
+    {
+        "Testing no rewrite of external locations",
+        do_rewrite_tests([
+            {"Location", external_url() ++ "/search",
+                         external_url() ++ "/search"},
+            {"Content-Location", external_url() ++ "/s?q=2",
+                                 external_url() ++ "/s?q=2"},
+            {"Uri", external_url() ++ "/f#f",
+                    external_url() ++ "/f#f"},
+            {"Destination", external_url() ++ "/f?q=2#f",
+                            external_url() ++ "/f?q=2#f"}
+        ])
+    }.
+
+should_rewrite_relative_location(_) ->
+    {
+        "Testing relative rewrites",
+        do_rewrite_tests([
+            {"Location", "/foo",
+                         server_url() ++ "/foo"},
+            {"Content-Location", "bar",
+                                 server_url() ++ "/bar"},
+            {"Uri", "/zing?q=3",
+                    server_url() ++ "/zing?q=3"},
+            {"Destination", "bing?q=stuff#yay",
+                            server_url() ++ "/bing?q=stuff#yay"}
+        ])
+    }.
+
+
+do_rewrite_tests(Tests) ->
+    lists:map(fun({Header, Location, Url}) ->
+        should_rewrite_header(Header, Location, Url)
+    end, Tests).
+
+should_rewrite_header(Header, Location, Url) ->
+    Remote = fun(Req) ->
+        "/rewrite_test" = Req:get(path),
+        {ok, {302, [{Header, Location}], "ok"}}
+    end,
+    Local = fun
+        ({ok, "302", Headers, "ok"}) ->
+            ?assertEqual(Url, couch_util:get_value(Header, Headers)),
+            true;
+        (E) ->
+            ?debugFmt("~p", [E]),
+            false
+    end,
+    Req = #req{path="/rewrite_test"},
+    {Header, ?_test(check_request(Req, Remote, Local))}.
+
+
+server_url() ->
+    server_url("/_test").
+
+server_url(Resource) ->
+    Addr = couch_config:get("httpd", "bind_address"),
+    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+    lists:concat(["http://", Addr, ":", Port, Resource]).
+
+proxy_url() ->
+    "http://127.0.0.1:" ++ integer_to_list(test_web:get_port()).
+
+external_url() ->
+    "https://google.com".
+
+check_request(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_url() ++ 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
+    ),
+    %?debugFmt("ibrowse response: ~p", [Resp]),
+    case Local of
+        no_local ->
+            ok;
+        _ ->
+            ?assert(Local(Resp))
+    end,
+    case {Remote, Local} of
+        {no_remote, _} ->
+            ok;
+        {_, no_local} ->
+            ok;
+        _ ->
+            ?assertEqual(was_ok, test_web:check_last())
+    end,
+    Resp.
+
+chunked_body(Chunks) ->
+    chunked_body(Chunks, []).
+
+chunked_body([], Acc) ->
+    iolist_to_binary(lists:reverse(Acc, "0\r\n\r\n"));
+chunked_body([Chunk | Rest], Acc) ->
+    Size = to_hex(size(Chunk)),
+    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 ?TIMEOUT ->
+        throw({error, timeout})
+    end.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb_modules_load_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_modules_load_tests.erl b/test/couchdb_modules_load_tests.erl
new file mode 100644
index 0000000..4eaa42b
--- /dev/null
+++ b/test/couchdb_modules_load_tests.erl
@@ -0,0 +1,68 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_modules_load_tests).
+
+-include("couch_eunit.hrl").
+
+
+modules_load_test_() ->
+    {
+        "Verify that all modules loads",
+        should_load_modules()
+    }.
+
+
+should_load_modules() ->
+    Modules = [
+        couch_auth_cache,
+        couch_btree,
+        couch_changes,
+        couch_compress,
+        couch_config,
+        couch_config_writer,
+        couch_db,
+        couch_db_update_notifier,
+        couch_db_update_notifier_sup,
+        couch_db_updater,
+        couch_doc,
+        % Fails unless couch_config gen_server is started.
+        % couch_ejson_compare,
+        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_rewrite,
+        couch_httpd_stats_handlers,
+        couch_key_tree,
+        couch_log,
+        couch_os_process,
+        couch_query_servers,
+        couch_ref_counter,
+        couch_server,
+        couch_server_sup,
+        couch_stats_aggregator,
+        couch_stats_collector,
+        couch_stream,
+        couch_task_status,
+        couch_util,
+        couch_work_queue,
+        json_stream_parse
+    ],
+    [should_load_module(Mod) || Mod <- Modules].
+
+should_load_module(Mod) ->
+    {atom_to_list(Mod), ?_assertMatch({module, _}, code:load_file(Mod))}.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb_os_daemons_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_os_daemons_tests.erl b/test/couchdb_os_daemons_tests.erl
new file mode 100644
index 0000000..aa949c9
--- /dev/null
+++ b/test/couchdb_os_daemons_tests.erl
@@ -0,0 +1,228 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_os_daemons_tests).
+
+-include("couch_eunit.hrl").
+
+%% keep in sync with couchdb/couch_os_daemons.erl
+-record(daemon, {
+    port,
+    name,
+    cmd,
+    kill,
+    status=running,
+    cfg_patterns=[],
+    errors=[],
+    buf=[]
+}).
+
+-define(DAEMON_CONFIGER, "os_daemon_configer.escript").
+-define(DAEMON_LOOPER, "os_daemon_looper.escript").
+-define(DAEMON_BAD_PERM, "os_daemon_bad_perm.sh").
+-define(DAEMON_CAN_REBOOT, "os_daemon_can_reboot.sh").
+-define(DAEMON_DIE_ON_BOOT, "os_daemon_die_on_boot.sh").
+-define(DAEMON_DIE_QUICKLY, "os_daemon_die_quickly.sh").
+-define(DELAY, 100).
+-define(TIMEOUT, 1000).
+
+
+setup(DName) ->
+    {ok, CfgPid} = couch_config:start_link(?CONFIG_CHAIN),
+    {ok, OsDPid} = couch_os_daemons:start_link(),
+    couch_config:set("os_daemons", DName,
+                     filename:join([?FIXTURESDIR, DName]), false),
+    timer:sleep(?DELAY),  % sleep a bit to let daemon set kill flag
+    {CfgPid, OsDPid}.
+
+teardown(_, {CfgPid, OsDPid}) ->
+    erlang:monitor(process, CfgPid),
+    couch_config:stop(),
+    receive
+        {'DOWN', _, _, CfgPid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, config_stop})
+    end,
+
+    erlang:monitor(process, OsDPid),
+    exit(OsDPid, normal),
+    receive
+        {'DOWN', _, _, OsDPid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, os_daemon_stop})
+    end.
+
+
+os_daemons_test_() ->
+    {
+        "OS Daemons tests",
+        {
+            foreachx,
+            fun setup/1, fun teardown/2,
+            [{?DAEMON_LOOPER, Fun} || Fun <- [
+                fun should_check_daemon/2,
+                fun should_check_daemon_table_form/2,
+                fun should_clean_tables_on_daemon_remove/2,
+                fun should_spawn_multiple_daemons/2,
+                fun should_keep_alive_one_daemon_on_killing_other/2
+            ]]
+        }
+    }.
+
+configuration_reader_test_() ->
+    {
+        "OS Daemon requests CouchDB configuration",
+        {
+            foreachx,
+            fun setup/1, fun teardown/2,
+            [{?DAEMON_CONFIGER,
+              fun should_read_write_config_settings_by_daemon/2}]
+
+        }
+    }.
+
+error_test_() ->
+    {
+        "OS Daemon process error tests",
+        {
+            foreachx,
+            fun setup/1, fun teardown/2,
+            [{?DAEMON_BAD_PERM, fun should_fail_due_to_lack_of_permissions/2},
+             {?DAEMON_DIE_ON_BOOT, fun should_die_on_boot/2},
+             {?DAEMON_DIE_QUICKLY, fun should_die_quickly/2},
+             {?DAEMON_CAN_REBOOT, fun should_not_being_halted/2}]
+        }
+    }.
+
+
+should_check_daemon(DName, _) ->
+    ?_test(begin
+        {ok, [D]} = couch_os_daemons:info([table]),
+        check_daemon(D, DName)
+    end).
+
+should_check_daemon_table_form(DName, _) ->
+    ?_test(begin
+        {ok, Tab} = couch_os_daemons:info(),
+        [D] = ets:tab2list(Tab),
+        check_daemon(D, DName)
+    end).
+
+should_clean_tables_on_daemon_remove(DName, _) ->
+    ?_test(begin
+        couch_config:delete("os_daemons", DName, false),
+        {ok, Tab2} = couch_os_daemons:info(),
+        ?_assertEqual([], ets:tab2list(Tab2))
+    end).
+
+should_spawn_multiple_daemons(DName, _) ->
+    ?_test(begin
+        couch_config:set("os_daemons", "bar",
+                         filename:join([?FIXTURESDIR, DName]), false),
+        couch_config:set("os_daemons", "baz",
+                         filename:join([?FIXTURESDIR, DName]), false),
+        timer:sleep(?DELAY),
+        {ok, Daemons} = couch_os_daemons:info([table]),
+        lists:foreach(fun(D) ->
+            check_daemon(D)
+        end, Daemons),
+        {ok, Tab} = couch_os_daemons:info(),
+        lists:foreach(fun(D) ->
+            check_daemon(D)
+        end, ets:tab2list(Tab))
+    end).
+
+should_keep_alive_one_daemon_on_killing_other(DName, _) ->
+    ?_test(begin
+        couch_config:set("os_daemons", "bar",
+                         filename:join([?FIXTURESDIR, DName]), false),
+        timer:sleep(?DELAY),
+        {ok, Daemons} = couch_os_daemons:info([table]),
+        lists:foreach(fun(D) ->
+            check_daemon(D)
+        end, Daemons),
+
+        couch_config:delete("os_daemons", "bar", false),
+        timer:sleep(?DELAY),
+        {ok, [D2]} = couch_os_daemons:info([table]),
+        check_daemon(D2, DName),
+
+        {ok, Tab} = couch_os_daemons:info(),
+        [T] = ets:tab2list(Tab),
+        check_daemon(T, DName)
+    end).
+
+should_read_write_config_settings_by_daemon(DName, _) ->
+    ?_test(begin
+        % have to wait till daemon run all his tests
+        % see daemon's script for more info
+        timer:sleep(?TIMEOUT),
+        {ok, [D]} = couch_os_daemons:info([table]),
+        check_daemon(D, DName)
+    end).
+
+should_fail_due_to_lack_of_permissions(DName, _) ->
+    ?_test(should_halts(DName, 1000)).
+
+should_die_on_boot(DName, _) ->
+    ?_test(should_halts(DName, 1000)).
+
+should_die_quickly(DName, _) ->
+    ?_test(should_halts(DName, 4000)).
+
+should_not_being_halted(DName, _) ->
+    ?_test(begin
+        timer:sleep(1000),
+        {ok, [D1]} = couch_os_daemons:info([table]),
+        check_daemon(D1, DName, 0),
+
+        % Should reboot every two seconds. We're at 1s, so wait
+        % until 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, DName, 1),
+
+        % If the kill command changed, that means we rebooted the process.
+        ?assertNotEqual(D1#daemon.kill, D2#daemon.kill)
+    end).
+
+should_halts(DName, Time) ->
+    timer:sleep(Time),
+    {ok, [D]} = couch_os_daemons:info([table]),
+    check_dead(D, DName),
+    couch_config:delete("os_daemons", DName, false).
+
+check_daemon(D) ->
+    check_daemon(D, D#daemon.name).
+
+check_daemon(D, Name) ->
+    check_daemon(D, Name, 0).
+
+check_daemon(D, Name, Errs) ->
+    ?assert(is_port(D#daemon.port)),
+    ?assertEqual(Name, D#daemon.name),
+    ?assertNotEqual(undefined, D#daemon.kill),
+    ?assertEqual(running, D#daemon.status),
+    ?assertEqual(Errs, length(D#daemon.errors)),
+    ?assertEqual([], D#daemon.buf).
+
+check_dead(D, Name) ->
+    ?assert(is_port(D#daemon.port)),
+    ?assertEqual(Name, D#daemon.name),
+    ?assertNotEqual(undefined, D#daemon.kill),
+    ?assertEqual(halted, D#daemon.status),
+    ?assertEqual(nil, D#daemon.errors),
+    ?assertEqual(nil, D#daemon.buf).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb_os_proc_pool.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_os_proc_pool.erl b/test/couchdb_os_proc_pool.erl
new file mode 100644
index 0000000..1bb266e
--- /dev/null
+++ b/test/couchdb_os_proc_pool.erl
@@ -0,0 +1,179 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_os_proc_pool).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(TIMEOUT, 3000).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    couch_config:set("query_server_config", "os_process_limit", "3", false),
+    Pid.
+
+stop(Pid) ->
+    couch_server_sup:stop(),
+    erlang:monitor(process, Pid),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+
+os_proc_pool_test_() ->
+    {
+        "OS processes pool tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            [
+                should_block_new_proc_on_full_pool(),
+                should_free_slot_on_proc_unexpected_exit()
+            ]
+        }
+    }.
+
+
+should_block_new_proc_on_full_pool() ->
+    ?_test(begin
+        Client1 = spawn_client(),
+        Client2 = spawn_client(),
+        Client3 = spawn_client(),
+
+        ?assertEqual(ok, ping_client(Client1)),
+        ?assertEqual(ok, ping_client(Client2)),
+        ?assertEqual(ok, ping_client(Client3)),
+
+        Proc1 = get_client_proc(Client1, "1"),
+        Proc2 = get_client_proc(Client2, "2"),
+        Proc3 = get_client_proc(Client3, "3"),
+
+        ?assertNotEqual(Proc1, Proc2),
+        ?assertNotEqual(Proc2, Proc3),
+        ?assertNotEqual(Proc3, Proc1),
+
+        Client4 = spawn_client(),
+        ?assertEqual(timeout, ping_client(Client4)),
+
+        ?assertEqual(ok, stop_client(Client1)),
+        ?assertEqual(ok, ping_client(Client4)),
+
+        Proc4 = get_client_proc(Client4, "4"),
+        ?assertEqual(Proc1, Proc4),
+
+        lists:map(fun(C) ->
+            ?assertEqual(ok, stop_client(C))
+        end, [Client2, Client3, Client4])
+    end).
+
+should_free_slot_on_proc_unexpected_exit() ->
+    ?_test(begin
+        Client1 = spawn_client(),
+        Client2 = spawn_client(),
+        Client3 = spawn_client(),
+
+        ?assertEqual(ok, ping_client(Client1)),
+        ?assertEqual(ok, ping_client(Client2)),
+        ?assertEqual(ok, ping_client(Client3)),
+
+        Proc1 = get_client_proc(Client1, "1"),
+        Proc2 = get_client_proc(Client2, "2"),
+        Proc3 = get_client_proc(Client3, "3"),
+
+        ?assertNotEqual(Proc1, Proc2),
+        ?assertNotEqual(Proc2, Proc3),
+        ?assertNotEqual(Proc3, Proc1),
+
+        ?assertEqual(ok, kill_client(Client1)),
+
+        Client4 = spawn_client(),
+        ?assertEqual(ok, ping_client(Client4)),
+
+        Proc4 = get_client_proc(Client4, "4"),
+        ?assertNotEqual(Proc4, Proc1),
+        ?assertNotEqual(Proc2, Proc4),
+        ?assertNotEqual(Proc3, Proc4),
+
+        lists:map(fun(C) ->
+            ?assertEqual(ok, stop_client(C))
+        end, [Client2, Client3, Client4])
+    end).
+
+
+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 ?TIMEOUT ->
+        timeout
+    end.
+
+get_client_proc({Pid, Ref}, ClientName) ->
+    Pid ! get_proc,
+    receive
+        {proc, Ref, Proc} -> Proc
+    after ?TIMEOUT ->
+        erlang:error({assertion_failed,
+                     [{module, ?MODULE},
+                      {line, ?LINE},
+                      {reason, "Timeout getting client "
+                               ++ ClientName ++ " proc"}]})
+    end.
+
+stop_client({Pid, Ref}) ->
+    Pid ! stop,
+    receive
+        {stop, Ref} ->
+            ok
+    after ?TIMEOUT ->
+        timeout
+    end.
+
+kill_client({Pid, Ref}) ->
+    Pid ! die,
+    receive
+        {die, Ref} ->
+            ok
+    after ?TIMEOUT ->
+        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.


[46/50] [abbrv] WIP: Disable problematic tests

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/6179af60/test/couch_uuids_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_uuids_tests.erl b/test/couch_uuids_tests.erl
index 27c5cb8..8eb378f 100644
--- a/test/couch_uuids_tests.erl
+++ b/test/couch_uuids_tests.erl
@@ -17,145 +17,146 @@
 -define(TIMEOUT_S, 20).
 
 
-setup() ->
-    {ok, Pid} = config:start_link(?CONFIG_CHAIN),
-    erlang:monitor(process, Pid),
-    couch_uuids:start(),
-    Pid.
-
-setup(Opts) ->
-    Pid = setup(),
-    lists:foreach(
-        fun({Option, Value}) ->
-            config:set("uuids", Option, Value, false)
-        end, Opts),
-    Pid.
-
-teardown(Pid) ->
-    couch_uuids:stop(),
-    config:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} -> ok
-    after
-        1000 -> throw({timeout_error, config_stop})
-    end.
-
-teardown(_, Pid) ->
-    teardown(Pid).
-
-
-default_test_() ->
-    {
-        "Default UUID algorithm",
-        {
-            setup,
-            fun setup/0, fun teardown/1,
-            fun should_be_unique/1
-        }
-    }.
-
-sequential_test_() ->
-    Opts = [{"algorithm", "sequential"}],
-    Cases = [
-        fun should_be_unique/2,
-        fun should_increment_monotonically/2,
-        fun should_rollover/2
-    ],
-    {
-        "UUID algorithm: sequential",
-        {
-            foreachx,
-            fun setup/1, fun teardown/2,
-            [{Opts, Fun} || Fun <- Cases]
-        }
-    }.
-
-utc_test_() ->
-    Opts = [{"algorithm", "utc_random"}],
-    Cases = [
-        fun should_be_unique/2,
-        fun should_increment_monotonically/2
-    ],
-    {
-        "UUID algorithm: utc_random",
-        {
-            foreachx,
-            fun setup/1, fun teardown/2,
-            [{Opts, Fun} || Fun <- Cases]
-        }
-    }.
-
-utc_id_suffix_test_() ->
-    Opts = [{"algorithm", "utc_id"}, {"utc_id_suffix", "bozo"}],
-    Cases = [
-        fun should_be_unique/2,
-        fun should_increment_monotonically/2,
-        fun should_preserve_suffix/2
-    ],
-    {
-        "UUID algorithm: utc_id",
-        {
-            foreachx,
-            fun setup/1, fun teardown/2,
-            [{Opts, Fun} || Fun <- Cases]
-        }
-    }.
-
-
-should_be_unique() ->
-    %% this one may really runs for too long on slow hosts
-    {timeout, ?TIMEOUT_S, ?_assert(test_unique(10000, [couch_uuids:new()]))}.
-should_be_unique(_) ->
-    should_be_unique().
-should_be_unique(_, _) ->
-    should_be_unique().
-
-should_increment_monotonically(_, _) ->
-    ?_assert(couch_uuids:new() < couch_uuids:new()).
-
-should_rollover(_, _) ->
-    ?_test(begin
-        UUID = binary_to_list(couch_uuids:new()),
-        Prefix = element(1, lists:split(26, UUID)),
-        N = gen_until_pref_change(Prefix, 0),
-        ?assert(N >= 5000 andalso N =< 11000)
-    end).
-
-should_preserve_suffix(_, _) ->
-    ?_test(begin
-        UUID = binary_to_list(couch_uuids:new()),
-        Suffix = get_suffix(UUID),
-        ?assert(test_same_suffix(10000, Suffix))
-    end).
-
-
-test_unique(0, _) ->
-    true;
-test_unique(N, UUIDs) ->
-    UUID = couch_uuids:new(),
-    ?assertNot(lists:member(UUID, UUIDs)),
-    test_unique(N - 1, [UUID| UUIDs]).
-
-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.
-
-get_suffix(UUID) when is_binary(UUID) ->
-    get_suffix(binary_to_list(UUID));
-get_suffix(UUID) ->
-    element(2, lists:split(14, UUID)).
-
-test_same_suffix(0, _) ->
-    true;
-test_same_suffix(N, Suffix) ->
-    case get_suffix(couch_uuids:new()) of
-        Suffix -> test_same_suffix(N - 1, Suffix);
-        _ -> false
-    end.
+%% setup() ->
+%%     %% {ok, Pid} = config:start_link(?CONFIG_CHAIN),
+%%     {ok, Pid} = test_util:start_config(?CONFIG_CHAIN),
+%%     erlang:monitor(process, Pid),
+%%     couch_uuids:start(),
+%%     Pid.
+
+%% setup(Opts) ->
+%%     Pid = setup(),
+%%     lists:foreach(
+%%         fun({Option, Value}) ->
+%%             config:set("uuids", Option, Value, false)
+%%         end, Opts),
+%%     Pid.
+
+%% teardown(Pid) ->
+%%     couch_uuids:stop(),
+%%     config:stop(),
+%%     receive
+%%         {'DOWN', _, _, Pid, _} -> ok
+%%     after
+%%         1000 -> throw({timeout_error, config_stop})
+%%     end.
+
+%% teardown(_, Pid) ->
+%%     teardown(Pid).
+
+
+%% default_test_() ->
+%%     {
+%%         "Default UUID algorithm",
+%%         {
+%%             setup,
+%%             fun setup/0, fun teardown/1,
+%%             fun should_be_unique/1
+%%         }
+%%     }.
+
+%% sequential_test_() ->
+%%     Opts = [{"algorithm", "sequential"}],
+%%     Cases = [
+%%         fun should_be_unique/2,
+%%         fun should_increment_monotonically/2,
+%%         fun should_rollover/2
+%%     ],
+%%     {
+%%         "UUID algorithm: sequential",
+%%         {
+%%             foreachx,
+%%             fun setup/1, fun teardown/2,
+%%             [{Opts, Fun} || Fun <- Cases]
+%%         }
+%%     }.
+
+%% utc_test_() ->
+%%     Opts = [{"algorithm", "utc_random"}],
+%%     Cases = [
+%%         fun should_be_unique/2,
+%%         fun should_increment_monotonically/2
+%%     ],
+%%     {
+%%         "UUID algorithm: utc_random",
+%%         {
+%%             foreachx,
+%%             fun setup/1, fun teardown/2,
+%%             [{Opts, Fun} || Fun <- Cases]
+%%         }
+%%     }.
+
+%% utc_id_suffix_test_() ->
+%%     Opts = [{"algorithm", "utc_id"}, {"utc_id_suffix", "bozo"}],
+%%     Cases = [
+%%         fun should_be_unique/2,
+%%         fun should_increment_monotonically/2,
+%%         fun should_preserve_suffix/2
+%%     ],
+%%     {
+%%         "UUID algorithm: utc_id",
+%%         {
+%%             foreachx,
+%%             fun setup/1, fun teardown/2,
+%%             [{Opts, Fun} || Fun <- Cases]
+%%         }
+%%     }.
+
+
+%% should_be_unique() ->
+%%     %% this one may really runs for too long on slow hosts
+%%     {timeout, ?TIMEOUT_S, ?_assert(test_unique(10000, [couch_uuids:new()]))}.
+%% should_be_unique(_) ->
+%%     should_be_unique().
+%% should_be_unique(_, _) ->
+%%     should_be_unique().
+
+%% should_increment_monotonically(_, _) ->
+%%     ?_assert(couch_uuids:new() < couch_uuids:new()).
+
+%% should_rollover(_, _) ->
+%%     ?_test(begin
+%%         UUID = binary_to_list(couch_uuids:new()),
+%%         Prefix = element(1, lists:split(26, UUID)),
+%%         N = gen_until_pref_change(Prefix, 0),
+%%         ?assert(N >= 5000 andalso N =< 11000)
+%%     end).
+
+%% should_preserve_suffix(_, _) ->
+%%     ?_test(begin
+%%         UUID = binary_to_list(couch_uuids:new()),
+%%         Suffix = get_suffix(UUID),
+%%         ?assert(test_same_suffix(10000, Suffix))
+%%     end).
+
+
+%% test_unique(0, _) ->
+%%     true;
+%% test_unique(N, UUIDs) ->
+%%     UUID = couch_uuids:new(),
+%%     ?assertNot(lists:member(UUID, UUIDs)),
+%%     test_unique(N - 1, [UUID| UUIDs]).
+
+%% 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.
+
+%% get_suffix(UUID) when is_binary(UUID) ->
+%%     get_suffix(binary_to_list(UUID));
+%% get_suffix(UUID) ->
+%%     element(2, lists:split(14, UUID)).
+
+%% test_same_suffix(0, _) ->
+%%     true;
+%% test_same_suffix(N, Suffix) ->
+%%     case get_suffix(couch_uuids:new()) of
+%%         Suffix -> test_same_suffix(N - 1, Suffix);
+%%         _ -> false
+%%     end.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/6179af60/test/couchdb_attachments_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_attachments_tests.erl b/test/couchdb_attachments_tests.erl
index b203a82..f1d7776 100644
--- a/test/couchdb_attachments_tests.erl
+++ b/test/couchdb_attachments_tests.erl
@@ -26,603 +26,603 @@
 -define(i2l(I), integer_to_list(I)).
 
 
-start() ->
-    ok = test_util:start_couch(),
-    % ensure in default compression settings for attachments_compression_tests
-    config:set("attachments", "compression_level",
-                     ?i2l(?COMPRESSION_LEVEL), false),
-    config:set("attachments", "compressible_types", "text/*", false),
-    ok.
-
-setup() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, []),
-    ok = couch_db:close(Db),
-    Addr = config:get("httpd", "bind_address", any),
-    Port = mochiweb_socket_server:get(couch_httpd, port),
-    Host = Addr ++ ":" ++ ?i2l(Port),
-    {Host, ?b2l(DbName)}.
-
-setup({binary, standalone}) ->
-    {Host, DbName} = setup(),
-        setup_att(fun create_standalone_png_att/2, Host, DbName, ?FIXTURE_PNG);
-setup({text, standalone}) ->
-    {Host, DbName} = setup(),
-    setup_att(fun create_standalone_text_att/2, Host, DbName, ?FIXTURE_TXT);
-setup({binary, inline}) ->
-    {Host, DbName} = setup(),
-    setup_att(fun create_inline_png_att/2, Host, DbName, ?FIXTURE_PNG);
-setup({text, inline}) ->
-    {Host, DbName} = setup(),
-    setup_att(fun create_inline_text_att/2, Host, DbName, ?FIXTURE_TXT);
-setup(compressed) ->
-    {Host, DbName} = setup(),
-    setup_att(fun create_already_compressed_att/2, Host, DbName, ?FIXTURE_TXT).
-setup_att(Fun, Host, DbName, File) ->
-    HttpHost = "http://" ++ Host,
-    AttUrl = Fun(HttpHost, DbName),
-    {ok, Data} = file:read_file(File),
-    DocUrl = string:join([HttpHost, DbName, "doc"], "/"),
-    Helpers = {DbName, DocUrl, AttUrl},
-    {Data, Helpers}.
-
-teardown(_, {_, {DbName, _, _}}) ->
-    teardown(DbName).
-
-teardown({_, DbName}) ->
-    teardown(DbName);
-teardown(DbName) ->
-    ok = couch_server:delete(?l2b(DbName), []),
-    ok.
-
-
-attachments_test_() ->
-    {
-        "Attachments tests",
-        {
-            setup,
-            fun start/0, fun test_util:stop_couch/1,
-            [
-                attachments_md5_tests(),
-                attachments_compression_tests()
-            ]
-        }
-    }.
-
-attachments_md5_tests() ->
-    {
-        "Attachments MD5 tests",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                fun should_upload_attachment_without_md5/1,
-                fun should_upload_attachment_by_chunks_without_md5/1,
-                fun should_upload_attachment_with_valid_md5_header/1,
-                fun should_upload_attachment_by_chunks_with_valid_md5_header/1,
-                fun should_upload_attachment_by_chunks_with_valid_md5_trailer/1,
-                fun should_reject_attachment_with_invalid_md5/1,
-                fun should_reject_chunked_attachment_with_invalid_md5/1,
-                fun should_reject_chunked_attachment_with_invalid_md5_trailer/1
-            ]
-        }
-    }.
-
-attachments_compression_tests() ->
-    Funs = [
-         fun should_get_att_without_accept_gzip_encoding/2,
-         fun should_get_att_with_accept_gzip_encoding/2,
-         fun should_get_att_with_accept_deflate_encoding/2,
-         fun should_return_406_response_on_unsupported_encoding/2,
-         fun should_get_doc_with_att_data/2,
-         fun should_get_doc_with_att_data_stub/2
-    ],
-    {
-        "Attachments compression tests",
-        [
-            {
-                "Created via Attachments API",
-                created_attachments_compression_tests(standalone, Funs)
-            },
-            {
-                "Created inline via Document API",
-                created_attachments_compression_tests(inline, Funs)
-            },
-            {
-                "Created already been compressed via Attachments API",
-                {
-                    foreachx,
-                    fun setup/1, fun teardown/2,
-                    [{compressed, Fun} || Fun <- Funs]
-                }
-            },
-            {
-                foreach,
-                fun setup/0, fun teardown/1,
-                [
-                    fun should_not_create_compressed_att_with_deflate_encoding/1,
-                    fun should_not_create_compressed_att_with_compress_encoding/1,
-                    fun should_create_compressible_att_with_ctype_params/1
-                ]
-            }
-        ]
-    }.
-
-created_attachments_compression_tests(Mod, Funs) ->
-    [
-        {
-            "Compressiable attachments",
-            {
-                foreachx,
-                fun setup/1, fun teardown/2,
-                [{{text, Mod}, Fun} || Fun <- Funs]
-            }
-        },
-        {
-            "Uncompressiable attachments",
-            {
-                foreachx,
-                fun setup/1, fun teardown/2,
-                [{{binary, Mod}, Fun} || Fun <- Funs]
-            }
-        }
-    ].
-
-
-
-should_upload_attachment_without_md5({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        Body = "We all live in a yellow submarine!",
-        Headers = [
-            {"Content-Length", "34"},
-            {"Content-Type", "text/plain"},
-            {"Host", Host}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(201, Code),
-        ?assertEqual(true, get_json(Json, [<<"ok">>]))
-    end).
-
-should_upload_attachment_by_chunks_without_md5({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        AttData = <<"We all live in a yellow submarine!">>,
-        <<Part1:21/binary, Part2:13/binary>> = AttData,
-        Body = chunked_body([Part1, Part2]),
-        Headers = [
-            {"Content-Type", "text/plain"},
-            {"Transfer-Encoding", "chunked"},
-            {"Host", Host}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(201, Code),
-        ?assertEqual(true, get_json(Json, [<<"ok">>]))
-    end).
-
-should_upload_attachment_with_valid_md5_header({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        Body = "We all live in a yellow submarine!",
-        Headers = [
-            {"Content-Length", "34"},
-            {"Content-Type", "text/plain"},
-            {"Content-MD5", ?b2l(base64:encode(couch_util:md5(Body)))},
-            {"Host", Host}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(201, Code),
-        ?assertEqual(true, get_json(Json, [<<"ok">>]))
-    end).
-
-should_upload_attachment_by_chunks_with_valid_md5_header({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        AttData = <<"We all live in a yellow submarine!">>,
-        <<Part1:21/binary, Part2:13/binary>> = AttData,
-        Body = chunked_body([Part1, Part2]),
-        Headers = [
-            {"Content-Type", "text/plain"},
-            {"Content-MD5", ?b2l(base64:encode(couch_util:md5(AttData)))},
-            {"Host", Host},
-            {"Transfer-Encoding", "chunked"}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(201, Code),
-        ?assertEqual(true, get_json(Json, [<<"ok">>]))
-    end).
-
-should_upload_attachment_by_chunks_with_valid_md5_trailer({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        AttData = <<"We all live in a yellow submarine!">>,
-        <<Part1:21/binary, Part2:13/binary>> = AttData,
-        Body = [chunked_body([Part1, Part2]),
-                "Content-MD5: ", base64:encode(couch_util:md5(AttData)),
-                "\r\n"],
-        Headers = [
-            {"Content-Type", "text/plain"},
-            {"Host", Host},
-            {"Trailer", "Content-MD5"},
-            {"Transfer-Encoding", "chunked"}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(201, Code),
-        ?assertEqual(true, get_json(Json, [<<"ok">>]))
-    end).
-
-should_reject_attachment_with_invalid_md5({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        Body = "We all live in a yellow submarine!",
-        Headers = [
-            {"Content-Length", "34"},
-            {"Content-Type", "text/plain"},
-            {"Content-MD5", ?b2l(base64:encode(<<"foobar!">>))},
-            {"Host", Host}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(400, Code),
-        ?assertEqual(<<"content_md5_mismatch">>,
-                     get_json(Json, [<<"error">>]))
-    end).
-
-
-should_reject_chunked_attachment_with_invalid_md5({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        AttData = <<"We all live in a yellow submarine!">>,
-        <<Part1:21/binary, Part2:13/binary>> = AttData,
-        Body = chunked_body([Part1, Part2]),
-        Headers = [
-            {"Content-Type", "text/plain"},
-            {"Content-MD5", ?b2l(base64:encode(<<"foobar!">>))},
-            {"Host", Host},
-            {"Transfer-Encoding", "chunked"}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(400, Code),
-        ?assertEqual(<<"content_md5_mismatch">>,
-                     get_json(Json, [<<"error">>]))
-    end).
-
-should_reject_chunked_attachment_with_invalid_md5_trailer({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        AttData = <<"We all live in a yellow submarine!">>,
-        <<Part1:21/binary, Part2:13/binary>> = AttData,
-        Body = [chunked_body([Part1, Part2]),
-                "Content-MD5: ", base64:encode(<<"foobar!">>),
-                "\r\n"],
-        Headers = [
-            {"Content-Type", "text/plain"},
-            {"Host", Host},
-            {"Trailer", "Content-MD5"},
-            {"Transfer-Encoding", "chunked"}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(400, Code),
-        ?assertEqual(<<"content_md5_mismatch">>, get_json(Json, [<<"error">>]))
-    end).
-
-should_get_att_without_accept_gzip_encoding(_, {Data, {_, _, AttUrl}}) ->
-    ?_test(begin
-        {ok, Code, Headers, Body} = test_request:get(AttUrl),
-        ?assertEqual(200, Code),
-        ?assertNot(lists:member({"Content-Encoding", "gzip"}, Headers)),
-        ?assertEqual(Data, iolist_to_binary(Body))
-    end).
-
-should_get_att_with_accept_gzip_encoding(compressed, {Data, {_, _, AttUrl}}) ->
-    ?_test(begin
-        {ok, Code, Headers, Body} = test_request:get(
-            AttUrl, [{"Accept-Encoding", "gzip"}]),
-        ?assertEqual(200, Code),
-        ?assert(lists:member({"Content-Encoding", "gzip"}, Headers)),
-        ?assertEqual(Data, zlib:gunzip(iolist_to_binary(Body)))
-    end);
-should_get_att_with_accept_gzip_encoding({text, _}, {Data, {_, _, AttUrl}}) ->
-    ?_test(begin
-        {ok, Code, Headers, Body} = test_request:get(
-            AttUrl, [{"Accept-Encoding", "gzip"}]),
-        ?assertEqual(200, Code),
-        ?assert(lists:member({"Content-Encoding", "gzip"}, Headers)),
-        ?assertEqual(Data, zlib:gunzip(iolist_to_binary(Body)))
-    end);
-should_get_att_with_accept_gzip_encoding({binary, _}, {Data, {_, _, AttUrl}}) ->
-    ?_test(begin
-        {ok, Code, Headers, Body} = test_request:get(
-            AttUrl, [{"Accept-Encoding", "gzip"}]),
-        ?assertEqual(200, Code),
-        ?assertEqual(undefined,
-                     couch_util:get_value("Content-Encoding", Headers)),
-        ?assertEqual(Data, iolist_to_binary(Body))
-    end).
-
-should_get_att_with_accept_deflate_encoding(_, {Data, {_, _, AttUrl}}) ->
-    ?_test(begin
-        {ok, Code, Headers, Body} = test_request:get(
-            AttUrl, [{"Accept-Encoding", "deflate"}]),
-        ?assertEqual(200, Code),
-        ?assertEqual(undefined,
-                     couch_util:get_value("Content-Encoding", Headers)),
-        ?assertEqual(Data, iolist_to_binary(Body))
-    end).
-
-should_return_406_response_on_unsupported_encoding(_, {_, {_, _, AttUrl}}) ->
-    ?_assertEqual(406,
-        begin
-            {ok, Code, _, _} = test_request:get(
-                AttUrl, [{"Accept-Encoding", "deflate, *;q=0"}]),
-            Code
-        end).
-
-should_get_doc_with_att_data(compressed, {Data, {_, DocUrl, _}}) ->
-    ?_test(begin
-        Url = DocUrl ++ "?attachments=true",
-        {ok, Code, _, Body} = test_request:get(
-            Url, [{"Accept", "application/json"}]),
-        ?assertEqual(200, Code),
-        Json = ejson:decode(Body),
-        AttJson = couch_util:get_nested_json_value(
-            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
-        AttData = couch_util:get_nested_json_value(
-            AttJson, [<<"data">>]),
-        ?assertEqual(
-            <<"text/plain">>,
-            couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
-        ?assertEqual(Data, base64:decode(AttData))
-    end);
-should_get_doc_with_att_data({text, _}, {Data, {_, DocUrl, _}}) ->
-    ?_test(begin
-        Url = DocUrl ++ "?attachments=true",
-        {ok, Code, _, Body} = test_request:get(
-            Url, [{"Accept", "application/json"}]),
-        ?assertEqual(200, Code),
-        Json = ejson:decode(Body),
-        AttJson = couch_util:get_nested_json_value(
-            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
-        AttData = couch_util:get_nested_json_value(
-            AttJson, [<<"data">>]),
-        ?assertEqual(
-            <<"text/plain">>,
-            couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
-        ?assertEqual(Data, base64:decode(AttData))
-    end);
-should_get_doc_with_att_data({binary, _}, {Data, {_, DocUrl, _}}) ->
-    ?_test(begin
-        Url = DocUrl ++ "?attachments=true",
-        {ok, Code, _, Body} = test_request:get(
-            Url, [{"Accept", "application/json"}]),
-        ?assertEqual(200, Code),
-        Json = ejson:decode(Body),
-        AttJson = couch_util:get_nested_json_value(
-            Json, [<<"_attachments">>, ?ATT_BIN_NAME]),
-        AttData = couch_util:get_nested_json_value(
-            AttJson, [<<"data">>]),
-        ?assertEqual(
-            <<"image/png">>,
-            couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
-        ?assertEqual(Data, base64:decode(AttData))
-    end).
-
-should_get_doc_with_att_data_stub(compressed, {Data, {_, DocUrl, _}}) ->
-    ?_test(begin
-        Url = DocUrl ++ "?att_encoding_info=true",
-        {ok, Code, _, Body} = test_request:get(
-            Url, [{"Accept", "application/json"}]),
-        ?assertEqual(200, Code),
-        Json = ejson:decode(Body),
-        {AttJson} = couch_util:get_nested_json_value(
-            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
-        ?assertEqual(<<"gzip">>,
-                     couch_util:get_value(<<"encoding">>, AttJson)),
-        AttLength = couch_util:get_value(<<"length">>, AttJson),
-        EncLength = couch_util:get_value(<<"encoded_length">>, AttJson),
-        ?assertEqual(AttLength, EncLength),
-        ?assertEqual(iolist_size(zlib:gzip(Data)), AttLength)
-    end);
-should_get_doc_with_att_data_stub({text, _}, {Data, {_, DocUrl, _}}) ->
-    ?_test(begin
-        Url = DocUrl ++ "?att_encoding_info=true",
-        {ok, Code, _, Body} = test_request:get(
-            Url, [{"Accept", "application/json"}]),
-        ?assertEqual(200, Code),
-        Json = ejson:decode(Body),
-        {AttJson} = couch_util:get_nested_json_value(
-            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
-        ?assertEqual(<<"gzip">>,
-                     couch_util:get_value(<<"encoding">>, AttJson)),
-        AttEncLength = iolist_size(gzip(Data)),
-        ?assertEqual(AttEncLength,
-                     couch_util:get_value(<<"encoded_length">>, AttJson)),
-        ?assertEqual(byte_size(Data),
-                     couch_util:get_value(<<"length">>, AttJson))
-    end);
-should_get_doc_with_att_data_stub({binary, _}, {Data, {_, DocUrl, _}}) ->
-    ?_test(begin
-        Url = DocUrl ++ "?att_encoding_info=true",
-        {ok, Code, _, Body} = test_request:get(
-            Url, [{"Accept", "application/json"}]),
-        ?assertEqual(200, Code),
-        Json = ejson:decode(Body),
-        {AttJson} = couch_util:get_nested_json_value(
-            Json, [<<"_attachments">>, ?ATT_BIN_NAME]),
-        ?assertEqual(undefined,
-                     couch_util:get_value(<<"encoding">>, AttJson)),
-        ?assertEqual(undefined,
-                     couch_util:get_value(<<"encoded_length">>, AttJson)),
-        ?assertEqual(byte_size(Data),
-                     couch_util:get_value(<<"length">>, AttJson))
-    end).
-
-should_not_create_compressed_att_with_deflate_encoding({Host, DbName}) ->
-    ?_assertEqual(415,
-        begin
-            HttpHost = "http://" ++ Host,
-            AttUrl = string:join([HttpHost, DbName, ?docid(), "file.txt"], "/"),
-            {ok, Data} = file:read_file(?FIXTURE_TXT),
-            Body = zlib:compress(Data),
-            Headers = [
-                {"Content-Encoding", "deflate"},
-                {"Content-Type", "text/plain"}
-            ],
-            {ok, Code, _, _} = test_request:put(AttUrl, Headers, Body),
-            Code
-        end).
-
-should_not_create_compressed_att_with_compress_encoding({Host, DbName}) ->
-    % 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
-    ?_assertEqual(415,
-        begin
-            HttpHost = "http://" ++ Host,
-            AttUrl = string:join([HttpHost, DbName, ?docid(), "file.txt"], "/"),
-            {ok, Data} = file:read_file(?FIXTURE_TXT),
-            Headers = [
-                {"Content-Encoding", "compress"},
-                {"Content-Type", "text/plain"}
-            ],
-            {ok, Code, _, _} = test_request:put(AttUrl, Headers, Data),
-            Code
-        end).
-
-should_create_compressible_att_with_ctype_params({Host, DbName}) ->
-    {timeout, ?TIMEOUT_EUNIT, ?_test(begin
-        HttpHost = "http://" ++ Host,
-        DocUrl = string:join([HttpHost, DbName, ?docid()], "/"),
-        AttUrl = string:join([DocUrl, ?b2l(?ATT_TXT_NAME)], "/"),
-        {ok, Data} = file:read_file(?FIXTURE_TXT),
-        Headers = [{"Content-Type", "text/plain; charset=UTF-8"}],
-        {ok, Code0, _, _} = test_request:put(AttUrl, Headers, Data),
-        ?assertEqual(201, Code0),
-
-        {ok, Code1, _, Body} = test_request:get(
-            DocUrl ++ "?att_encoding_info=true"),
-        ?assertEqual(200, Code1),
-        Json = ejson:decode(Body),
-        {AttJson} = couch_util:get_nested_json_value(
-            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
-        ?assertEqual(<<"gzip">>,
-                     couch_util:get_value(<<"encoding">>, AttJson)),
-        AttEncLength = iolist_size(gzip(Data)),
-        ?assertEqual(AttEncLength,
-                     couch_util:get_value(<<"encoded_length">>, AttJson)),
-        ?assertEqual(byte_size(Data),
-                     couch_util:get_value(<<"length">>, AttJson))
-    end)}.
-
-
-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.
-
-chunked_body(Chunks) ->
-    chunked_body(Chunks, []).
-
-chunked_body([], Acc) ->
-    iolist_to_binary(lists:reverse(Acc, "0\r\n"));
-chunked_body([Chunk | Rest], Acc) ->
-    Size = to_hex(size(Chunk)),
-    chunked_body(Rest, ["\r\n", Chunk, "\r\n", Size | Acc]).
-
-get_socket() ->
-    Options = [binary, {packet, 0}, {active, false}],
-    Addr = config:get("httpd", "bind_address", any),
-    Port = mochiweb_socket_server:get(couch_httpd, port),
-    {ok, Sock} = gen_tcp:connect(Addr, Port, Options),
-    Sock.
-
-request(Method, Url, Headers, Body) ->
-    RequestHead = [Method, " ", Url, " HTTP/1.1"],
-    RequestHeaders = [[string:join([Key, Value], ": "), "\r\n"]
-                      || {Key, Value} <- Headers],
-    Request = [RequestHead, "\r\n", RequestHeaders, "\r\n", Body, "\r\n"],
-    Sock = get_socket(),
-    gen_tcp:send(Sock, list_to_binary(lists:flatten(Request))),
-    timer:sleep(?TIMEWAIT),  % must wait to receive complete response
-    {ok, R} = gen_tcp:recv(Sock, 0),
-    gen_tcp:close(Sock),
-    [Header, Body1] = re:split(R, "\r\n\r\n", [{return, binary}]),
-    {ok, {http_response, _, Code, _}, _} =
-        erlang:decode_packet(http, Header, []),
-    Json = ejson:decode(Body1),
-    {ok, Code, Json}.
-
-create_standalone_text_att(Host, DbName) ->
-    {ok, Data} = file:read_file(?FIXTURE_TXT),
-    Url = string:join([Host, DbName, "doc", ?b2l(?ATT_TXT_NAME)], "/"),
-    {ok, Code, _Headers, _Body} = test_request:put(
-        Url, [{"Content-Type", "text/plain"}], Data),
-    ?assertEqual(201, Code),
-    Url.
-
-create_standalone_png_att(Host, DbName) ->
-    {ok, Data} = file:read_file(?FIXTURE_PNG),
-    Url = string:join([Host, DbName, "doc", ?b2l(?ATT_BIN_NAME)], "/"),
-    {ok, Code, _Headers, _Body} = test_request:put(
-        Url, [{"Content-Type", "image/png"}], Data),
-    ?assertEqual(201, Code),
-    Url.
-
-create_inline_text_att(Host, DbName) ->
-    {ok, Data} = file:read_file(?FIXTURE_TXT),
-    Url = string:join([Host, DbName, "doc"], "/"),
-    Doc = {[
-        {<<"_attachments">>, {[
-            {?ATT_TXT_NAME, {[
-                {<<"content_type">>, <<"text/plain">>},
-                {<<"data">>, base64:encode(Data)}
-            ]}
-        }]}}
-    ]},
-    {ok, Code, _Headers, _Body} = test_request:put(
-        Url, [{"Content-Type", "application/json"}], ejson:encode(Doc)),
-    ?assertEqual(201, Code),
-    string:join([Url, ?b2l(?ATT_TXT_NAME)], "/").
-
-create_inline_png_att(Host, DbName) ->
-    {ok, Data} = file:read_file(?FIXTURE_PNG),
-    Url = string:join([Host, DbName, "doc"], "/"),
-    Doc = {[
-        {<<"_attachments">>, {[
-            {?ATT_BIN_NAME, {[
-                {<<"content_type">>, <<"image/png">>},
-                {<<"data">>, base64:encode(Data)}
-            ]}
-        }]}}
-    ]},
-    {ok, Code, _Headers, _Body} = test_request:put(
-        Url, [{"Content-Type", "application/json"}], ejson:encode(Doc)),
-    ?assertEqual(201, Code),
-    string:join([Url, ?b2l(?ATT_BIN_NAME)], "/").
-
-create_already_compressed_att(Host, DbName) ->
-    {ok, Data} = file:read_file(?FIXTURE_TXT),
-    Url = string:join([Host, DbName, "doc", ?b2l(?ATT_TXT_NAME)], "/"),
-    {ok, Code, _Headers, _Body} = test_request:put(
-        Url, [{"Content-Type", "text/plain"}, {"Content-Encoding", "gzip"}],
-        zlib:gzip(Data)),
-    ?assertEqual(201, Code),
-    Url.
-
-gzip(Data) ->
-    Z = zlib:open(),
-    ok = zlib:deflateInit(Z, ?COMPRESSION_LEVEL, deflated, 16 + 15, 8, default),
-    zlib:deflate(Z, Data),
-    Last = zlib:deflate(Z, [], finish),
-    ok = zlib:deflateEnd(Z),
-    ok = zlib:close(Z),
-    Last.
+%% start() ->
+%%     ok = test_util:start_couch(),
+%%     % ensure in default compression settings for attachments_compression_tests
+%%     config:set("attachments", "compression_level",
+%%                      ?i2l(?COMPRESSION_LEVEL), false),
+%%     config:set("attachments", "compressible_types", "text/*", false),
+%%     ok.
+
+%% setup() ->
+%%     DbName = ?tempdb(),
+%%     {ok, Db} = couch_db:create(DbName, []),
+%%     ok = couch_db:close(Db),
+%%     Addr = config:get("httpd", "bind_address", any),
+%%     Port = mochiweb_socket_server:get(couch_httpd, port),
+%%     Host = Addr ++ ":" ++ ?i2l(Port),
+%%     {Host, ?b2l(DbName)}.
+
+%% setup({binary, standalone}) ->
+%%     {Host, DbName} = setup(),
+%%         setup_att(fun create_standalone_png_att/2, Host, DbName, ?FIXTURE_PNG);
+%% setup({text, standalone}) ->
+%%     {Host, DbName} = setup(),
+%%     setup_att(fun create_standalone_text_att/2, Host, DbName, ?FIXTURE_TXT);
+%% setup({binary, inline}) ->
+%%     {Host, DbName} = setup(),
+%%     setup_att(fun create_inline_png_att/2, Host, DbName, ?FIXTURE_PNG);
+%% setup({text, inline}) ->
+%%     {Host, DbName} = setup(),
+%%     setup_att(fun create_inline_text_att/2, Host, DbName, ?FIXTURE_TXT);
+%% setup(compressed) ->
+%%     {Host, DbName} = setup(),
+%%     setup_att(fun create_already_compressed_att/2, Host, DbName, ?FIXTURE_TXT).
+%% setup_att(Fun, Host, DbName, File) ->
+%%     HttpHost = "http://" ++ Host,
+%%     AttUrl = Fun(HttpHost, DbName),
+%%     {ok, Data} = file:read_file(File),
+%%     DocUrl = string:join([HttpHost, DbName, "doc"], "/"),
+%%     Helpers = {DbName, DocUrl, AttUrl},
+%%     {Data, Helpers}.
+
+%% teardown(_, {_, {DbName, _, _}}) ->
+%%     teardown(DbName).
+
+%% teardown({_, DbName}) ->
+%%     teardown(DbName);
+%% teardown(DbName) ->
+%%     ok = couch_server:delete(?l2b(DbName), []),
+%%     ok.
+
+
+%% attachments_test_() ->
+%%     {
+%%         "Attachments tests",
+%%         {
+%%             setup,
+%%             fun start/0, fun test_util:stop_couch/1,
+%%             [
+%%                 attachments_md5_tests(),
+%%                 attachments_compression_tests()
+%%             ]
+%%         }
+%%     }.
+
+%% attachments_md5_tests() ->
+%%     {
+%%         "Attachments MD5 tests",
+%%         {
+%%             foreach,
+%%             fun setup/0, fun teardown/1,
+%%             [
+%%                 fun should_upload_attachment_without_md5/1,
+%%                 fun should_upload_attachment_by_chunks_without_md5/1,
+%%                 fun should_upload_attachment_with_valid_md5_header/1,
+%%                 fun should_upload_attachment_by_chunks_with_valid_md5_header/1,
+%%                 fun should_upload_attachment_by_chunks_with_valid_md5_trailer/1,
+%%                 fun should_reject_attachment_with_invalid_md5/1,
+%%                 fun should_reject_chunked_attachment_with_invalid_md5/1,
+%%                 fun should_reject_chunked_attachment_with_invalid_md5_trailer/1
+%%             ]
+%%         }
+%%     }.
+
+%% attachments_compression_tests() ->
+%%     Funs = [
+%%          fun should_get_att_without_accept_gzip_encoding/2,
+%%          fun should_get_att_with_accept_gzip_encoding/2,
+%%          fun should_get_att_with_accept_deflate_encoding/2,
+%%          fun should_return_406_response_on_unsupported_encoding/2,
+%%          fun should_get_doc_with_att_data/2,
+%%          fun should_get_doc_with_att_data_stub/2
+%%     ],
+%%     {
+%%         "Attachments compression tests",
+%%         [
+%%             {
+%%                 "Created via Attachments API",
+%%                 created_attachments_compression_tests(standalone, Funs)
+%%             },
+%%             {
+%%                 "Created inline via Document API",
+%%                 created_attachments_compression_tests(inline, Funs)
+%%             },
+%%             {
+%%                 "Created already been compressed via Attachments API",
+%%                 {
+%%                     foreachx,
+%%                     fun setup/1, fun teardown/2,
+%%                     [{compressed, Fun} || Fun <- Funs]
+%%                 }
+%%             },
+%%             {
+%%                 foreach,
+%%                 fun setup/0, fun teardown/1,
+%%                 [
+%%                     fun should_not_create_compressed_att_with_deflate_encoding/1,
+%%                     fun should_not_create_compressed_att_with_compress_encoding/1,
+%%                     fun should_create_compressible_att_with_ctype_params/1
+%%                 ]
+%%             }
+%%         ]
+%%     }.
+
+%% created_attachments_compression_tests(Mod, Funs) ->
+%%     [
+%%         {
+%%             "Compressiable attachments",
+%%             {
+%%                 foreachx,
+%%                 fun setup/1, fun teardown/2,
+%%                 [{{text, Mod}, Fun} || Fun <- Funs]
+%%             }
+%%         },
+%%         {
+%%             "Uncompressiable attachments",
+%%             {
+%%                 foreachx,
+%%                 fun setup/1, fun teardown/2,
+%%                 [{{binary, Mod}, Fun} || Fun <- Funs]
+%%             }
+%%         }
+%%     ].
+
+
+
+%% should_upload_attachment_without_md5({Host, DbName}) ->
+%%     ?_test(begin
+%%         AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+%%         Body = "We all live in a yellow submarine!",
+%%         Headers = [
+%%             {"Content-Length", "34"},
+%%             {"Content-Type", "text/plain"},
+%%             {"Host", Host}
+%%         ],
+%%         {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+%%         ?assertEqual(201, Code),
+%%         ?assertEqual(true, get_json(Json, [<<"ok">>]))
+%%     end).
+
+%% should_upload_attachment_by_chunks_without_md5({Host, DbName}) ->
+%%     ?_test(begin
+%%         AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+%%         AttData = <<"We all live in a yellow submarine!">>,
+%%         <<Part1:21/binary, Part2:13/binary>> = AttData,
+%%         Body = chunked_body([Part1, Part2]),
+%%         Headers = [
+%%             {"Content-Type", "text/plain"},
+%%             {"Transfer-Encoding", "chunked"},
+%%             {"Host", Host}
+%%         ],
+%%         {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+%%         ?assertEqual(201, Code),
+%%         ?assertEqual(true, get_json(Json, [<<"ok">>]))
+%%     end).
+
+%% should_upload_attachment_with_valid_md5_header({Host, DbName}) ->
+%%     ?_test(begin
+%%         AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+%%         Body = "We all live in a yellow submarine!",
+%%         Headers = [
+%%             {"Content-Length", "34"},
+%%             {"Content-Type", "text/plain"},
+%%             {"Content-MD5", ?b2l(base64:encode(couch_util:md5(Body)))},
+%%             {"Host", Host}
+%%         ],
+%%         {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+%%         ?assertEqual(201, Code),
+%%         ?assertEqual(true, get_json(Json, [<<"ok">>]))
+%%     end).
+
+%% should_upload_attachment_by_chunks_with_valid_md5_header({Host, DbName}) ->
+%%     ?_test(begin
+%%         AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+%%         AttData = <<"We all live in a yellow submarine!">>,
+%%         <<Part1:21/binary, Part2:13/binary>> = AttData,
+%%         Body = chunked_body([Part1, Part2]),
+%%         Headers = [
+%%             {"Content-Type", "text/plain"},
+%%             {"Content-MD5", ?b2l(base64:encode(couch_util:md5(AttData)))},
+%%             {"Host", Host},
+%%             {"Transfer-Encoding", "chunked"}
+%%         ],
+%%         {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+%%         ?assertEqual(201, Code),
+%%         ?assertEqual(true, get_json(Json, [<<"ok">>]))
+%%     end).
+
+%% should_upload_attachment_by_chunks_with_valid_md5_trailer({Host, DbName}) ->
+%%     ?_test(begin
+%%         AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+%%         AttData = <<"We all live in a yellow submarine!">>,
+%%         <<Part1:21/binary, Part2:13/binary>> = AttData,
+%%         Body = [chunked_body([Part1, Part2]),
+%%                 "Content-MD5: ", base64:encode(couch_util:md5(AttData)),
+%%                 "\r\n"],
+%%         Headers = [
+%%             {"Content-Type", "text/plain"},
+%%             {"Host", Host},
+%%             {"Trailer", "Content-MD5"},
+%%             {"Transfer-Encoding", "chunked"}
+%%         ],
+%%         {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+%%         ?assertEqual(201, Code),
+%%         ?assertEqual(true, get_json(Json, [<<"ok">>]))
+%%     end).
+
+%% should_reject_attachment_with_invalid_md5({Host, DbName}) ->
+%%     ?_test(begin
+%%         AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+%%         Body = "We all live in a yellow submarine!",
+%%         Headers = [
+%%             {"Content-Length", "34"},
+%%             {"Content-Type", "text/plain"},
+%%             {"Content-MD5", ?b2l(base64:encode(<<"foobar!">>))},
+%%             {"Host", Host}
+%%         ],
+%%         {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+%%         ?assertEqual(400, Code),
+%%         ?assertEqual(<<"content_md5_mismatch">>,
+%%                      get_json(Json, [<<"error">>]))
+%%     end).
+
+
+%% should_reject_chunked_attachment_with_invalid_md5({Host, DbName}) ->
+%%     ?_test(begin
+%%         AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+%%         AttData = <<"We all live in a yellow submarine!">>,
+%%         <<Part1:21/binary, Part2:13/binary>> = AttData,
+%%         Body = chunked_body([Part1, Part2]),
+%%         Headers = [
+%%             {"Content-Type", "text/plain"},
+%%             {"Content-MD5", ?b2l(base64:encode(<<"foobar!">>))},
+%%             {"Host", Host},
+%%             {"Transfer-Encoding", "chunked"}
+%%         ],
+%%         {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+%%         ?assertEqual(400, Code),
+%%         ?assertEqual(<<"content_md5_mismatch">>,
+%%                      get_json(Json, [<<"error">>]))
+%%     end).
+
+%% should_reject_chunked_attachment_with_invalid_md5_trailer({Host, DbName}) ->
+%%     ?_test(begin
+%%         AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
+%%         AttData = <<"We all live in a yellow submarine!">>,
+%%         <<Part1:21/binary, Part2:13/binary>> = AttData,
+%%         Body = [chunked_body([Part1, Part2]),
+%%                 "Content-MD5: ", base64:encode(<<"foobar!">>),
+%%                 "\r\n"],
+%%         Headers = [
+%%             {"Content-Type", "text/plain"},
+%%             {"Host", Host},
+%%             {"Trailer", "Content-MD5"},
+%%             {"Transfer-Encoding", "chunked"}
+%%         ],
+%%         {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
+%%         ?assertEqual(400, Code),
+%%         ?assertEqual(<<"content_md5_mismatch">>, get_json(Json, [<<"error">>]))
+%%     end).
+
+%% should_get_att_without_accept_gzip_encoding(_, {Data, {_, _, AttUrl}}) ->
+%%     ?_test(begin
+%%         {ok, Code, Headers, Body} = test_request:get(AttUrl),
+%%         ?assertEqual(200, Code),
+%%         ?assertNot(lists:member({"Content-Encoding", "gzip"}, Headers)),
+%%         ?assertEqual(Data, iolist_to_binary(Body))
+%%     end).
+
+%% should_get_att_with_accept_gzip_encoding(compressed, {Data, {_, _, AttUrl}}) ->
+%%     ?_test(begin
+%%         {ok, Code, Headers, Body} = test_request:get(
+%%             AttUrl, [{"Accept-Encoding", "gzip"}]),
+%%         ?assertEqual(200, Code),
+%%         ?assert(lists:member({"Content-Encoding", "gzip"}, Headers)),
+%%         ?assertEqual(Data, zlib:gunzip(iolist_to_binary(Body)))
+%%     end);
+%% should_get_att_with_accept_gzip_encoding({text, _}, {Data, {_, _, AttUrl}}) ->
+%%     ?_test(begin
+%%         {ok, Code, Headers, Body} = test_request:get(
+%%             AttUrl, [{"Accept-Encoding", "gzip"}]),
+%%         ?assertEqual(200, Code),
+%%         ?assert(lists:member({"Content-Encoding", "gzip"}, Headers)),
+%%         ?assertEqual(Data, zlib:gunzip(iolist_to_binary(Body)))
+%%     end);
+%% should_get_att_with_accept_gzip_encoding({binary, _}, {Data, {_, _, AttUrl}}) ->
+%%     ?_test(begin
+%%         {ok, Code, Headers, Body} = test_request:get(
+%%             AttUrl, [{"Accept-Encoding", "gzip"}]),
+%%         ?assertEqual(200, Code),
+%%         ?assertEqual(undefined,
+%%                      couch_util:get_value("Content-Encoding", Headers)),
+%%         ?assertEqual(Data, iolist_to_binary(Body))
+%%     end).
+
+%% should_get_att_with_accept_deflate_encoding(_, {Data, {_, _, AttUrl}}) ->
+%%     ?_test(begin
+%%         {ok, Code, Headers, Body} = test_request:get(
+%%             AttUrl, [{"Accept-Encoding", "deflate"}]),
+%%         ?assertEqual(200, Code),
+%%         ?assertEqual(undefined,
+%%                      couch_util:get_value("Content-Encoding", Headers)),
+%%         ?assertEqual(Data, iolist_to_binary(Body))
+%%     end).
+
+%% should_return_406_response_on_unsupported_encoding(_, {_, {_, _, AttUrl}}) ->
+%%     ?_assertEqual(406,
+%%         begin
+%%             {ok, Code, _, _} = test_request:get(
+%%                 AttUrl, [{"Accept-Encoding", "deflate, *;q=0"}]),
+%%             Code
+%%         end).
+
+%% should_get_doc_with_att_data(compressed, {Data, {_, DocUrl, _}}) ->
+%%     ?_test(begin
+%%         Url = DocUrl ++ "?attachments=true",
+%%         {ok, Code, _, Body} = test_request:get(
+%%             Url, [{"Accept", "application/json"}]),
+%%         ?assertEqual(200, Code),
+%%         Json = ejson:decode(Body),
+%%         AttJson = couch_util:get_nested_json_value(
+%%             Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+%%         AttData = couch_util:get_nested_json_value(
+%%             AttJson, [<<"data">>]),
+%%         ?assertEqual(
+%%             <<"text/plain">>,
+%%             couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
+%%         ?assertEqual(Data, base64:decode(AttData))
+%%     end);
+%% should_get_doc_with_att_data({text, _}, {Data, {_, DocUrl, _}}) ->
+%%     ?_test(begin
+%%         Url = DocUrl ++ "?attachments=true",
+%%         {ok, Code, _, Body} = test_request:get(
+%%             Url, [{"Accept", "application/json"}]),
+%%         ?assertEqual(200, Code),
+%%         Json = ejson:decode(Body),
+%%         AttJson = couch_util:get_nested_json_value(
+%%             Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+%%         AttData = couch_util:get_nested_json_value(
+%%             AttJson, [<<"data">>]),
+%%         ?assertEqual(
+%%             <<"text/plain">>,
+%%             couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
+%%         ?assertEqual(Data, base64:decode(AttData))
+%%     end);
+%% should_get_doc_with_att_data({binary, _}, {Data, {_, DocUrl, _}}) ->
+%%     ?_test(begin
+%%         Url = DocUrl ++ "?attachments=true",
+%%         {ok, Code, _, Body} = test_request:get(
+%%             Url, [{"Accept", "application/json"}]),
+%%         ?assertEqual(200, Code),
+%%         Json = ejson:decode(Body),
+%%         AttJson = couch_util:get_nested_json_value(
+%%             Json, [<<"_attachments">>, ?ATT_BIN_NAME]),
+%%         AttData = couch_util:get_nested_json_value(
+%%             AttJson, [<<"data">>]),
+%%         ?assertEqual(
+%%             <<"image/png">>,
+%%             couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
+%%         ?assertEqual(Data, base64:decode(AttData))
+%%     end).
+
+%% should_get_doc_with_att_data_stub(compressed, {Data, {_, DocUrl, _}}) ->
+%%     ?_test(begin
+%%         Url = DocUrl ++ "?att_encoding_info=true",
+%%         {ok, Code, _, Body} = test_request:get(
+%%             Url, [{"Accept", "application/json"}]),
+%%         ?assertEqual(200, Code),
+%%         Json = ejson:decode(Body),
+%%         {AttJson} = couch_util:get_nested_json_value(
+%%             Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+%%         ?assertEqual(<<"gzip">>,
+%%                      couch_util:get_value(<<"encoding">>, AttJson)),
+%%         AttLength = couch_util:get_value(<<"length">>, AttJson),
+%%         EncLength = couch_util:get_value(<<"encoded_length">>, AttJson),
+%%         ?assertEqual(AttLength, EncLength),
+%%         ?assertEqual(iolist_size(zlib:gzip(Data)), AttLength)
+%%     end);
+%% should_get_doc_with_att_data_stub({text, _}, {Data, {_, DocUrl, _}}) ->
+%%     ?_test(begin
+%%         Url = DocUrl ++ "?att_encoding_info=true",
+%%         {ok, Code, _, Body} = test_request:get(
+%%             Url, [{"Accept", "application/json"}]),
+%%         ?assertEqual(200, Code),
+%%         Json = ejson:decode(Body),
+%%         {AttJson} = couch_util:get_nested_json_value(
+%%             Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+%%         ?assertEqual(<<"gzip">>,
+%%                      couch_util:get_value(<<"encoding">>, AttJson)),
+%%         AttEncLength = iolist_size(gzip(Data)),
+%%         ?assertEqual(AttEncLength,
+%%                      couch_util:get_value(<<"encoded_length">>, AttJson)),
+%%         ?assertEqual(byte_size(Data),
+%%                      couch_util:get_value(<<"length">>, AttJson))
+%%     end);
+%% should_get_doc_with_att_data_stub({binary, _}, {Data, {_, DocUrl, _}}) ->
+%%     ?_test(begin
+%%         Url = DocUrl ++ "?att_encoding_info=true",
+%%         {ok, Code, _, Body} = test_request:get(
+%%             Url, [{"Accept", "application/json"}]),
+%%         ?assertEqual(200, Code),
+%%         Json = ejson:decode(Body),
+%%         {AttJson} = couch_util:get_nested_json_value(
+%%             Json, [<<"_attachments">>, ?ATT_BIN_NAME]),
+%%         ?assertEqual(undefined,
+%%                      couch_util:get_value(<<"encoding">>, AttJson)),
+%%         ?assertEqual(undefined,
+%%                      couch_util:get_value(<<"encoded_length">>, AttJson)),
+%%         ?assertEqual(byte_size(Data),
+%%                      couch_util:get_value(<<"length">>, AttJson))
+%%     end).
+
+%% should_not_create_compressed_att_with_deflate_encoding({Host, DbName}) ->
+%%     ?_assertEqual(415,
+%%         begin
+%%             HttpHost = "http://" ++ Host,
+%%             AttUrl = string:join([HttpHost, DbName, ?docid(), "file.txt"], "/"),
+%%             {ok, Data} = file:read_file(?FIXTURE_TXT),
+%%             Body = zlib:compress(Data),
+%%             Headers = [
+%%                 {"Content-Encoding", "deflate"},
+%%                 {"Content-Type", "text/plain"}
+%%             ],
+%%             {ok, Code, _, _} = test_request:put(AttUrl, Headers, Body),
+%%             Code
+%%         end).
+
+%% should_not_create_compressed_att_with_compress_encoding({Host, DbName}) ->
+%%     % 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
+%%     ?_assertEqual(415,
+%%         begin
+%%             HttpHost = "http://" ++ Host,
+%%             AttUrl = string:join([HttpHost, DbName, ?docid(), "file.txt"], "/"),
+%%             {ok, Data} = file:read_file(?FIXTURE_TXT),
+%%             Headers = [
+%%                 {"Content-Encoding", "compress"},
+%%                 {"Content-Type", "text/plain"}
+%%             ],
+%%             {ok, Code, _, _} = test_request:put(AttUrl, Headers, Data),
+%%             Code
+%%         end).
+
+%% should_create_compressible_att_with_ctype_params({Host, DbName}) ->
+%%     {timeout, ?TIMEOUT_EUNIT, ?_test(begin
+%%         HttpHost = "http://" ++ Host,
+%%         DocUrl = string:join([HttpHost, DbName, ?docid()], "/"),
+%%         AttUrl = string:join([DocUrl, ?b2l(?ATT_TXT_NAME)], "/"),
+%%         {ok, Data} = file:read_file(?FIXTURE_TXT),
+%%         Headers = [{"Content-Type", "text/plain; charset=UTF-8"}],
+%%         {ok, Code0, _, _} = test_request:put(AttUrl, Headers, Data),
+%%         ?assertEqual(201, Code0),
+
+%%         {ok, Code1, _, Body} = test_request:get(
+%%             DocUrl ++ "?att_encoding_info=true"),
+%%         ?assertEqual(200, Code1),
+%%         Json = ejson:decode(Body),
+%%         {AttJson} = couch_util:get_nested_json_value(
+%%             Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
+%%         ?assertEqual(<<"gzip">>,
+%%                      couch_util:get_value(<<"encoding">>, AttJson)),
+%%         AttEncLength = iolist_size(gzip(Data)),
+%%         ?assertEqual(AttEncLength,
+%%                      couch_util:get_value(<<"encoded_length">>, AttJson)),
+%%         ?assertEqual(byte_size(Data),
+%%                      couch_util:get_value(<<"length">>, AttJson))
+%%     end)}.
+
+
+%% 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.
+
+%% chunked_body(Chunks) ->
+%%     chunked_body(Chunks, []).
+
+%% chunked_body([], Acc) ->
+%%     iolist_to_binary(lists:reverse(Acc, "0\r\n"));
+%% chunked_body([Chunk | Rest], Acc) ->
+%%     Size = to_hex(size(Chunk)),
+%%     chunked_body(Rest, ["\r\n", Chunk, "\r\n", Size | Acc]).
+
+%% get_socket() ->
+%%     Options = [binary, {packet, 0}, {active, false}],
+%%     Addr = config:get("httpd", "bind_address", any),
+%%     Port = mochiweb_socket_server:get(couch_httpd, port),
+%%     {ok, Sock} = gen_tcp:connect(Addr, Port, Options),
+%%     Sock.
+
+%% request(Method, Url, Headers, Body) ->
+%%     RequestHead = [Method, " ", Url, " HTTP/1.1"],
+%%     RequestHeaders = [[string:join([Key, Value], ": "), "\r\n"]
+%%                       || {Key, Value} <- Headers],
+%%     Request = [RequestHead, "\r\n", RequestHeaders, "\r\n", Body, "\r\n"],
+%%     Sock = get_socket(),
+%%     gen_tcp:send(Sock, list_to_binary(lists:flatten(Request))),
+%%     timer:sleep(?TIMEWAIT),  % must wait to receive complete response
+%%     {ok, R} = gen_tcp:recv(Sock, 0),
+%%     gen_tcp:close(Sock),
+%%     [Header, Body1] = re:split(R, "\r\n\r\n", [{return, binary}]),
+%%     {ok, {http_response, _, Code, _}, _} =
+%%         erlang:decode_packet(http, Header, []),
+%%     Json = ejson:decode(Body1),
+%%     {ok, Code, Json}.
+
+%% create_standalone_text_att(Host, DbName) ->
+%%     {ok, Data} = file:read_file(?FIXTURE_TXT),
+%%     Url = string:join([Host, DbName, "doc", ?b2l(?ATT_TXT_NAME)], "/"),
+%%     {ok, Code, _Headers, _Body} = test_request:put(
+%%         Url, [{"Content-Type", "text/plain"}], Data),
+%%     ?assertEqual(201, Code),
+%%     Url.
+
+%% create_standalone_png_att(Host, DbName) ->
+%%     {ok, Data} = file:read_file(?FIXTURE_PNG),
+%%     Url = string:join([Host, DbName, "doc", ?b2l(?ATT_BIN_NAME)], "/"),
+%%     {ok, Code, _Headers, _Body} = test_request:put(
+%%         Url, [{"Content-Type", "image/png"}], Data),
+%%     ?assertEqual(201, Code),
+%%     Url.
+
+%% create_inline_text_att(Host, DbName) ->
+%%     {ok, Data} = file:read_file(?FIXTURE_TXT),
+%%     Url = string:join([Host, DbName, "doc"], "/"),
+%%     Doc = {[
+%%         {<<"_attachments">>, {[
+%%             {?ATT_TXT_NAME, {[
+%%                 {<<"content_type">>, <<"text/plain">>},
+%%                 {<<"data">>, base64:encode(Data)}
+%%             ]}
+%%         }]}}
+%%     ]},
+%%     {ok, Code, _Headers, _Body} = test_request:put(
+%%         Url, [{"Content-Type", "application/json"}], ejson:encode(Doc)),
+%%     ?assertEqual(201, Code),
+%%     string:join([Url, ?b2l(?ATT_TXT_NAME)], "/").
+
+%% create_inline_png_att(Host, DbName) ->
+%%     {ok, Data} = file:read_file(?FIXTURE_PNG),
+%%     Url = string:join([Host, DbName, "doc"], "/"),
+%%     Doc = {[
+%%         {<<"_attachments">>, {[
+%%             {?ATT_BIN_NAME, {[
+%%                 {<<"content_type">>, <<"image/png">>},
+%%                 {<<"data">>, base64:encode(Data)}
+%%             ]}
+%%         }]}}
+%%     ]},
+%%     {ok, Code, _Headers, _Body} = test_request:put(
+%%         Url, [{"Content-Type", "application/json"}], ejson:encode(Doc)),
+%%     ?assertEqual(201, Code),
+%%     string:join([Url, ?b2l(?ATT_BIN_NAME)], "/").
+
+%% create_already_compressed_att(Host, DbName) ->
+%%     {ok, Data} = file:read_file(?FIXTURE_TXT),
+%%     Url = string:join([Host, DbName, "doc", ?b2l(?ATT_TXT_NAME)], "/"),
+%%     {ok, Code, _Headers, _Body} = test_request:put(
+%%         Url, [{"Content-Type", "text/plain"}, {"Content-Encoding", "gzip"}],
+%%         zlib:gzip(Data)),
+%%     ?assertEqual(201, Code),
+%%     Url.
+
+%% gzip(Data) ->
+%%     Z = zlib:open(),
+%%     ok = zlib:deflateInit(Z, ?COMPRESSION_LEVEL, deflated, 16 + 15, 8, default),
+%%     zlib:deflate(Z, Data),
+%%     Last = zlib:deflate(Z, [], finish),
+%%     ok = zlib:deflateEnd(Z),
+%%     ok = zlib:close(Z),
+%%     Last.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/6179af60/test/couchdb_compaction_daemon.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_compaction_daemon.erl b/test/couchdb_compaction_daemon.erl
index 24c5d7b..7db24fe 100644
--- a/test/couchdb_compaction_daemon.erl
+++ b/test/couchdb_compaction_daemon.erl
@@ -21,201 +21,201 @@
 -define(TIMEOUT_S, ?TIMEOUT div 1000).
 
 
-start() ->
-    ok = test_util:start_couch(),
-    config:set("compaction_daemon", "check_interval", "3", false),
-    config:set("compaction_daemon", "min_file_size", "100000", false),
-    ok.
-
-setup() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
-    create_design_doc(Db),
-    ok = couch_db:close(Db),
-    DbName.
-
-teardown(DbName) ->
-    Configs = config:get("compactions"),
-    lists:foreach(
-        fun({Key, _}) ->
-            ok = config:delete("compactions", Key, false)
-        end,
-        Configs),
-    couch_server:delete(DbName, [?ADMIN_USER]),
-    ok.
-
-
-compaction_daemon_test_() ->
-    {
-        "Compaction daemon tests",
-        {
-            setup,
-            fun start/0, fun test_util:stop_couch/1,
-            {
-                foreach,
-                fun setup/0, fun teardown/1,
-                [
-                    fun should_compact_by_default_rule/1,
-                    fun should_compact_by_dbname_rule/1
-                ]
-            }
-        }
-    }.
-
-
-should_compact_by_default_rule(DbName) ->
-    {timeout, ?TIMEOUT_S, ?_test(begin
-        {ok, Db} = couch_db:open_int(DbName, []),
-        populate(DbName, 70, 70, 200 * 1024),
-
-        {_, DbFileSize} = get_db_frag(DbName),
-        {_, ViewFileSize} = get_view_frag(DbName),
-
-        ok = config:set("compactions", "_default",
-            "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]",
-            false),
-
-        ok = timer:sleep(4000), % something >= check_interval
-        wait_compaction_finished(DbName),
-        ok = config:delete("compactions", "_default", false),
-
-        {DbFrag2, DbFileSize2} = get_db_frag(DbName),
-        {ViewFrag2, ViewFileSize2} = get_view_frag(DbName),
-
-        ?assert(DbFrag2 < 70),
-        ?assert(ViewFrag2 < 70),
-
-        ?assert(DbFileSize > DbFileSize2),
-        ?assert(ViewFileSize > ViewFileSize2),
-
-        ?assert(couch_db:is_idle(Db)),
-        ok = couch_db:close(Db)
-    end)}.
-
-should_compact_by_dbname_rule(DbName) ->
-    {timeout, ?TIMEOUT_S, ?_test(begin
-        {ok, Db} = couch_db:open_int(DbName, []),
-        populate(DbName, 70, 70, 200 * 1024),
-
-        {_, DbFileSize} = get_db_frag(DbName),
-        {_, ViewFileSize} = get_view_frag(DbName),
-
-        ok = config:set("compactions", ?b2l(DbName),
-            "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]",
-            false),
-
-        ok = timer:sleep(4000), % something >= check_interval
-        wait_compaction_finished(DbName),
-        ok = config:delete("compactions", ?b2l(DbName), false),
-
-        {DbFrag2, DbFileSize2} = get_db_frag(DbName),
-        {ViewFrag2, ViewFileSize2} = get_view_frag(DbName),
-
-        ?assert(DbFrag2 < 70),
-        ?assert(ViewFrag2 < 70),
-
-        ?assert(DbFileSize > DbFileSize2),
-        ?assert(ViewFileSize > ViewFileSize2),
-
-        ?assert(couch_db:is_idle(Db)),
-        ok = couch_db:close(Db)
-    end)}.
-
-
-create_design_doc(Db) ->
-    DDoc = couch_doc:from_json_obj({[
-        {<<"_id">>, <<"_design/foo">>},
-        {<<"language">>, <<"javascript">>},
-        {<<"views">>, {[
-            {<<"foo">>, {[
-                {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>}
-            ]}},
-            {<<"foo2">>, {[
-                {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>}
-            ]}},
-            {<<"foo3">>, {[
-                {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>}
-            ]}}
-        ]}}
-    ]}),
-    {ok, _} = couch_db:update_docs(Db, [DDoc]),
-    {ok, _} = couch_db:ensure_full_commit(Db),
-    ok.
-
-populate(DbName, DbFrag, ViewFrag, MinFileSize) ->
-    {CurDbFrag, DbFileSize} = get_db_frag(DbName),
-    {CurViewFrag, ViewFileSize} = get_view_frag(DbName),
-    populate(DbName, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag,
-             lists:min([DbFileSize, ViewFileSize])).
-
-populate(_Db, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag, FileSize)
-    when CurDbFrag >= DbFrag, CurViewFrag >= ViewFrag, FileSize >= MinFileSize ->
-    ok;
-populate(DbName, DbFrag, ViewFrag, MinFileSize, _, _, _) ->
-    update(DbName),
-    {CurDbFrag, DbFileSize} = get_db_frag(DbName),
-    {CurViewFrag, ViewFileSize} = get_view_frag(DbName),
-    populate(DbName, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag,
-             lists:min([DbFileSize, ViewFileSize])).
-
-update(DbName) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    lists:foreach(fun(_) ->
-        Doc = couch_doc:from_json_obj({[{<<"_id">>, couch_uuids:new()}]}),
-        {ok, _} = couch_db:update_docs(Db, [Doc]),
-        query_view(Db#db.name)
-    end, lists:seq(1, 200)),
-    couch_db:close(Db).
-
-db_url(DbName) ->
-    Addr = config:get("httpd", "bind_address", "127.0.0.1"),
-    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
-    "http://" ++ Addr ++ ":" ++ Port ++ "/" ++ ?b2l(DbName).
-
-query_view(DbName) ->
-    {ok, Code, _Headers, _Body} = test_request:get(
-        db_url(DbName) ++ "/_design/foo/_view/foo"),
-    ?assertEqual(200, Code).
-
-get_db_frag(DbName) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    {ok, Info} = couch_db:get_db_info(Db),
-    couch_db:close(Db),
-    FileSize = couch_util:get_value(disk_size, Info),
-    DataSize = couch_util:get_value(data_size, Info),
-    {round((FileSize - DataSize) / FileSize * 100), FileSize}.
-
-get_view_frag(DbName) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    {ok, Info} = couch_mrview:get_info(Db, <<"_design/foo">>),
-    couch_db:close(Db),
-    FileSize = couch_util:get_value(disk_size, Info),
-    DataSize = couch_util:get_value(data_size, Info),
-    {round((FileSize - DataSize) / FileSize * 100), FileSize}.
-
-wait_compaction_finished(DbName) ->
-    Parent = self(),
-    Loop = spawn_link(fun() -> wait_loop(DbName, Parent) end),
-    receive
-        {done, Loop} ->
-            ok
-    after ?TIMEOUT ->
-        erlang:error(
-            {assertion_failed,
-             [{module, ?MODULE}, {line, ?LINE},
-              {reason, "Compaction timeout"}]})
-    end.
-
-wait_loop(DbName, Parent) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    {ok, DbInfo} = couch_db:get_db_info(Db),
-    {ok, ViewInfo} = couch_mrview:get_info(Db, <<"_design/foo">>),
-    couch_db:close(Db),
-    case (couch_util:get_value(compact_running, ViewInfo) =:= true) orelse
-        (couch_util:get_value(compact_running, DbInfo) =:= true) of
-        false ->
-            Parent ! {done, self()};
-        true ->
-            ok = timer:sleep(?DELAY),
-            wait_loop(DbName, Parent)
-    end.
+%% start() ->
+%%     ok = test_util:start_couch(),
+%%     config:set("compaction_daemon", "check_interval", "3", false),
+%%     config:set("compaction_daemon", "min_file_size", "100000", false),
+%%     ok.
+
+%% setup() ->
+%%     DbName = ?tempdb(),
+%%     {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+%%     create_design_doc(Db),
+%%     ok = couch_db:close(Db),
+%%     DbName.
+
+%% teardown(DbName) ->
+%%     Configs = config:get("compactions"),
+%%     lists:foreach(
+%%         fun({Key, _}) ->
+%%             ok = config:delete("compactions", Key, false)
+%%         end,
+%%         Configs),
+%%     couch_server:delete(DbName, [?ADMIN_USER]),
+%%     ok.
+
+
+%% compaction_daemon_test_() ->
+%%     {
+%%         "Compaction daemon tests",
+%%         {
+%%             setup,
+%%             fun start/0, fun test_util:stop_couch/1,
+%%             {
+%%                 foreach,
+%%                 fun setup/0, fun teardown/1,
+%%                 [
+%%                     fun should_compact_by_default_rule/1,
+%%                     fun should_compact_by_dbname_rule/1
+%%                 ]
+%%             }
+%%         }
+%%     }.
+
+
+%% should_compact_by_default_rule(DbName) ->
+%%     {timeout, ?TIMEOUT_S, ?_test(begin
+%%         {ok, Db} = couch_db:open_int(DbName, []),
+%%         populate(DbName, 70, 70, 200 * 1024),
+
+%%         {_, DbFileSize} = get_db_frag(DbName),
+%%         {_, ViewFileSize} = get_view_frag(DbName),
+
+%%         ok = config:set("compactions", "_default",
+%%             "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]",
+%%             false),
+
+%%         ok = timer:sleep(4000), % something >= check_interval
+%%         wait_compaction_finished(DbName),
+%%         ok = config:delete("compactions", "_default", false),
+
+%%         {DbFrag2, DbFileSize2} = get_db_frag(DbName),
+%%         {ViewFrag2, ViewFileSize2} = get_view_frag(DbName),
+
+%%         ?assert(DbFrag2 < 70),
+%%         ?assert(ViewFrag2 < 70),
+
+%%         ?assert(DbFileSize > DbFileSize2),
+%%         ?assert(ViewFileSize > ViewFileSize2),
+
+%%         ?assert(couch_db:is_idle(Db)),
+%%         ok = couch_db:close(Db)
+%%     end)}.
+
+%% should_compact_by_dbname_rule(DbName) ->
+%%     {timeout, ?TIMEOUT_S, ?_test(begin
+%%         {ok, Db} = couch_db:open_int(DbName, []),
+%%         populate(DbName, 70, 70, 200 * 1024),
+
+%%         {_, DbFileSize} = get_db_frag(DbName),
+%%         {_, ViewFileSize} = get_view_frag(DbName),
+
+%%         ok = config:set("compactions", ?b2l(DbName),
+%%             "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]",
+%%             false),
+
+%%         ok = timer:sleep(4000), % something >= check_interval
+%%         wait_compaction_finished(DbName),
+%%         ok = config:delete("compactions", ?b2l(DbName), false),
+
+%%         {DbFrag2, DbFileSize2} = get_db_frag(DbName),
+%%         {ViewFrag2, ViewFileSize2} = get_view_frag(DbName),
+
+%%         ?assert(DbFrag2 < 70),
+%%         ?assert(ViewFrag2 < 70),
+
+%%         ?assert(DbFileSize > DbFileSize2),
+%%         ?assert(ViewFileSize > ViewFileSize2),
+
+%%         ?assert(couch_db:is_idle(Db)),
+%%         ok = couch_db:close(Db)
+%%     end)}.
+
+
+%% create_design_doc(Db) ->
+%%     DDoc = couch_doc:from_json_obj({[
+%%         {<<"_id">>, <<"_design/foo">>},
+%%         {<<"language">>, <<"javascript">>},
+%%         {<<"views">>, {[
+%%             {<<"foo">>, {[
+%%                 {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>}
+%%             ]}},
+%%             {<<"foo2">>, {[
+%%                 {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>}
+%%             ]}},
+%%             {<<"foo3">>, {[
+%%                 {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>}
+%%             ]}}
+%%         ]}}
+%%     ]}),
+%%     {ok, _} = couch_db:update_docs(Db, [DDoc]),
+%%     {ok, _} = couch_db:ensure_full_commit(Db),
+%%     ok.
+
+%% populate(DbName, DbFrag, ViewFrag, MinFileSize) ->
+%%     {CurDbFrag, DbFileSize} = get_db_frag(DbName),
+%%     {CurViewFrag, ViewFileSize} = get_view_frag(DbName),
+%%     populate(DbName, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag,
+%%              lists:min([DbFileSize, ViewFileSize])).
+
+%% populate(_Db, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag, FileSize)
+%%     when CurDbFrag >= DbFrag, CurViewFrag >= ViewFrag, FileSize >= MinFileSize ->
+%%     ok;
+%% populate(DbName, DbFrag, ViewFrag, MinFileSize, _, _, _) ->
+%%     update(DbName),
+%%     {CurDbFrag, DbFileSize} = get_db_frag(DbName),
+%%     {CurViewFrag, ViewFileSize} = get_view_frag(DbName),
+%%     populate(DbName, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag,
+%%              lists:min([DbFileSize, ViewFileSize])).
+
+%% update(DbName) ->
+%%     {ok, Db} = couch_db:open_int(DbName, []),
+%%     lists:foreach(fun(_) ->
+%%         Doc = couch_doc:from_json_obj({[{<<"_id">>, couch_uuids:new()}]}),
+%%         {ok, _} = couch_db:update_docs(Db, [Doc]),
+%%         query_view(Db#db.name)
+%%     end, lists:seq(1, 200)),
+%%     couch_db:close(Db).
+
+%% db_url(DbName) ->
+%%     Addr = config:get("httpd", "bind_address", "127.0.0.1"),
+%%     Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+%%     "http://" ++ Addr ++ ":" ++ Port ++ "/" ++ ?b2l(DbName).
+
+%% query_view(DbName) ->
+%%     {ok, Code, _Headers, _Body} = test_request:get(
+%%         db_url(DbName) ++ "/_design/foo/_view/foo"),
+%%     ?assertEqual(200, Code).
+
+%% get_db_frag(DbName) ->
+%%     {ok, Db} = couch_db:open_int(DbName, []),
+%%     {ok, Info} = couch_db:get_db_info(Db),
+%%     couch_db:close(Db),
+%%     FileSize = couch_util:get_value(disk_size, Info),
+%%     DataSize = couch_util:get_value(data_size, Info),
+%%     {round((FileSize - DataSize) / FileSize * 100), FileSize}.
+
+%% get_view_frag(DbName) ->
+%%     {ok, Db} = couch_db:open_int(DbName, []),
+%%     {ok, Info} = couch_mrview:get_info(Db, <<"_design/foo">>),
+%%     couch_db:close(Db),
+%%     FileSize = couch_util:get_value(disk_size, Info),
+%%     DataSize = couch_util:get_value(data_size, Info),
+%%     {round((FileSize - DataSize) / FileSize * 100), FileSize}.
+
+%% wait_compaction_finished(DbName) ->
+%%     Parent = self(),
+%%     Loop = spawn_link(fun() -> wait_loop(DbName, Parent) end),
+%%     receive
+%%         {done, Loop} ->
+%%             ok
+%%     after ?TIMEOUT ->
+%%         erlang:error(
+%%             {assertion_failed,
+%%              [{module, ?MODULE}, {line, ?LINE},
+%%               {reason, "Compaction timeout"}]})
+%%     end.
+
+%% wait_loop(DbName, Parent) ->
+%%     {ok, Db} = couch_db:open_int(DbName, []),
+%%     {ok, DbInfo} = couch_db:get_db_info(Db),
+%%     {ok, ViewInfo} = couch_mrview:get_info(Db, <<"_design/foo">>),
+%%     couch_db:close(Db),
+%%     case (couch_util:get_value(compact_running, ViewInfo) =:= true) orelse
+%%         (couch_util:get_value(compact_running, DbInfo) =:= true) of
+%%         false ->
+%%             Parent ! {done, self()};
+%%         true ->
+%%             ok = timer:sleep(?DELAY),
+%%             wait_loop(DbName, Parent)
+%%     end.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/6179af60/test/couchdb_os_daemons_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_os_daemons_tests.erl b/test/couchdb_os_daemons_tests.erl
index 3eeb7d7..68de6f7 100644
--- a/test/couchdb_os_daemons_tests.erl
+++ b/test/couchdb_os_daemons_tests.erl
@@ -36,193 +36,193 @@
 -define(TIMEOUT, 1000).
 
 
-setup(DName) ->
-    {ok, CfgPid} = config:start_link(?CONFIG_CHAIN),
-    {ok, OsDPid} = couch_os_daemons:start_link(),
-    config:set("os_daemons", DName,
-                     filename:join([?FIXTURESDIR, DName]), false),
-    timer:sleep(?DELAY),  % sleep a bit to let daemon set kill flag
-    {CfgPid, OsDPid}.
-
-teardown(_, {CfgPid, OsDPid}) ->
-    erlang:monitor(process, CfgPid),
-    config:stop(),
-    receive
-        {'DOWN', _, _, CfgPid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, config_stop})
-    end,
-
-    erlang:monitor(process, OsDPid),
-    exit(OsDPid, normal),
-    receive
-        {'DOWN', _, _, OsDPid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, os_daemon_stop})
-    end.
-
-
-os_daemons_test_() ->
-    {
-        "OS Daemons tests",
-        {
-            foreachx,
-            fun setup/1, fun teardown/2,
-            [{?DAEMON_LOOPER, Fun} || Fun <- [
-                fun should_check_daemon/2,
-                fun should_check_daemon_table_form/2,
-                fun should_clean_tables_on_daemon_remove/2,
-                fun should_spawn_multiple_daemons/2,
-                fun should_keep_alive_one_daemon_on_killing_other/2
-            ]]
-        }
-    }.
-
-configuration_reader_test_() ->
-    {
-        "OS Daemon requests CouchDB configuration",
-        {
-            foreachx,
-            fun setup/1, fun teardown/2,
-            [{?DAEMON_CONFIGER,
-              fun should_read_write_config_settings_by_daemon/2}]
-
-        }
-    }.
-
-error_test_() ->
-    {
-        "OS Daemon process error tests",
-        {
-            foreachx,
-            fun setup/1, fun teardown/2,
-            [{?DAEMON_BAD_PERM, fun should_fail_due_to_lack_of_permissions/2},
-             {?DAEMON_DIE_ON_BOOT, fun should_die_on_boot/2},
-             {?DAEMON_DIE_QUICKLY, fun should_die_quickly/2},
-             {?DAEMON_CAN_REBOOT, fun should_not_being_halted/2}]
-        }
-    }.
-
-
-should_check_daemon(DName, _) ->
-    ?_test(begin
-        {ok, [D]} = couch_os_daemons:info([table]),
-        check_daemon(D, DName)
-    end).
-
-should_check_daemon_table_form(DName, _) ->
-    ?_test(begin
-        {ok, Tab} = couch_os_daemons:info(),
-        [D] = ets:tab2list(Tab),
-        check_daemon(D, DName)
-    end).
-
-should_clean_tables_on_daemon_remove(DName, _) ->
-    ?_test(begin
-        config:delete("os_daemons", DName, false),
-        {ok, Tab2} = couch_os_daemons:info(),
-        ?_assertEqual([], ets:tab2list(Tab2))
-    end).
-
-should_spawn_multiple_daemons(DName, _) ->
-    ?_test(begin
-        config:set("os_daemons", "bar",
-                         filename:join([?FIXTURESDIR, DName]), false),
-        config:set("os_daemons", "baz",
-                         filename:join([?FIXTURESDIR, DName]), false),
-        timer:sleep(?DELAY),
-        {ok, Daemons} = couch_os_daemons:info([table]),
-        lists:foreach(fun(D) ->
-            check_daemon(D)
-        end, Daemons),
-        {ok, Tab} = couch_os_daemons:info(),
-        lists:foreach(fun(D) ->
-            check_daemon(D)
-        end, ets:tab2list(Tab))
-    end).
-
-should_keep_alive_one_daemon_on_killing_other(DName, _) ->
-    ?_test(begin
-        config:set("os_daemons", "bar",
-                         filename:join([?FIXTURESDIR, DName]), false),
-        timer:sleep(?DELAY),
-        {ok, Daemons} = couch_os_daemons:info([table]),
-        lists:foreach(fun(D) ->
-            check_daemon(D)
-        end, Daemons),
-
-        config:delete("os_daemons", "bar", false),
-        timer:sleep(?DELAY),
-        {ok, [D2]} = couch_os_daemons:info([table]),
-        check_daemon(D2, DName),
-
-        {ok, Tab} = couch_os_daemons:info(),
-        [T] = ets:tab2list(Tab),
-        check_daemon(T, DName)
-    end).
-
-should_read_write_config_settings_by_daemon(DName, _) ->
-    ?_test(begin
-        % have to wait till daemon run all his tests
-        % see daemon's script for more info
-        timer:sleep(?TIMEOUT),
-        {ok, [D]} = couch_os_daemons:info([table]),
-        check_daemon(D, DName)
-    end).
-
-should_fail_due_to_lack_of_permissions(DName, _) ->
-    ?_test(should_halts(DName, 1000)).
-
-should_die_on_boot(DName, _) ->
-    ?_test(should_halts(DName, 1000)).
-
-should_die_quickly(DName, _) ->
-    ?_test(should_halts(DName, 4000)).
-
-should_not_being_halted(DName, _) ->
-    ?_test(begin
-        timer:sleep(1000),
-        {ok, [D1]} = couch_os_daemons:info([table]),
-        check_daemon(D1, DName, 0),
-
-        % Should reboot every two seconds. We're at 1s, so wait
-        % until 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, DName, 1),
-
-        % If the kill command changed, that means we rebooted the process.
-        ?assertNotEqual(D1#daemon.kill, D2#daemon.kill)
-    end).
-
-should_halts(DName, Time) ->
-    timer:sleep(Time),
-    {ok, [D]} = couch_os_daemons:info([table]),
-    check_dead(D, DName),
-    config:delete("os_daemons", DName, false).
-
-check_daemon(D) ->
-    check_daemon(D, D#daemon.name).
-
-check_daemon(D, Name) ->
-    check_daemon(D, Name, 0).
-
-check_daemon(D, Name, Errs) ->
-    ?assert(is_port(D#daemon.port)),
-    ?assertEqual(Name, D#daemon.name),
-    ?assertNotEqual(undefined, D#daemon.kill),
-    ?assertEqual(running, D#daemon.status),
-    ?assertEqual(Errs, length(D#daemon.errors)),
-    ?assertEqual([], D#daemon.buf).
-
-check_dead(D, Name) ->
-    ?assert(is_port(D#daemon.port)),
-    ?assertEqual(Name, D#daemon.name),
-    ?assertNotEqual(undefined, D#daemon.kill),
-    ?assertEqual(halted, D#daemon.status),
-    ?assertEqual(nil, D#daemon.errors),
-    ?assertEqual(nil, D#daemon.buf).
+%% setup(DName) ->
+%%     {ok, CfgPid} = config:start_link(?CONFIG_CHAIN),
+%%     {ok, OsDPid} = couch_os_daemons:start_link(),
+%%     config:set("os_daemons", DName,
+%%                      filename:join([?FIXTURESDIR, DName]), false),
+%%     timer:sleep(?DELAY),  % sleep a bit to let daemon set kill flag
+%%     {CfgPid, OsDPid}.
+
+%% teardown(_, {CfgPid, OsDPid}) ->
+%%     erlang:monitor(process, CfgPid),
+%%     config:stop(),
+%%     receive
+%%         {'DOWN', _, _, CfgPid, _} ->
+%%             ok
+%%     after ?TIMEOUT ->
+%%         throw({timeout, config_stop})
+%%     end,
+
+%%     erlang:monitor(process, OsDPid),
+%%     exit(OsDPid, normal),
+%%     receive
+%%         {'DOWN', _, _, OsDPid, _} ->
+%%             ok
+%%     after ?TIMEOUT ->
+%%         throw({timeout, os_daemon_stop})
+%%     end.
+
+
+%% os_daemons_test_() ->
+%%     {
+%%         "OS Daemons tests",
+%%         {
+%%             foreachx,
+%%             fun setup/1, fun teardown/2,
+%%             [{?DAEMON_LOOPER, Fun} || Fun <- [
+%%                 fun should_check_daemon/2,
+%%                 fun should_check_daemon_table_form/2,
+%%                 fun should_clean_tables_on_daemon_remove/2,
+%%                 fun should_spawn_multiple_daemons/2,
+%%                 fun should_keep_alive_one_daemon_on_killing_other/2
+%%             ]]
+%%         }
+%%     }.
+
+%% configuration_reader_test_() ->
+%%     {
+%%         "OS Daemon requests CouchDB configuration",
+%%         {
+%%             foreachx,
+%%             fun setup/1, fun teardown/2,
+%%             [{?DAEMON_CONFIGER,
+%%               fun should_read_write_config_settings_by_daemon/2}]
+
+%%         }
+%%     }.
+
+%% error_test_() ->
+%%     {
+%%         "OS Daemon process error tests",
+%%         {
+%%             foreachx,
+%%             fun setup/1, fun teardown/2,
+%%             [{?DAEMON_BAD_PERM, fun should_fail_due_to_lack_of_permissions/2},
+%%              {?DAEMON_DIE_ON_BOOT, fun should_die_on_boot/2},
+%%              {?DAEMON_DIE_QUICKLY, fun should_die_quickly/2},
+%%              {?DAEMON_CAN_REBOOT, fun should_not_being_halted/2}]
+%%         }
+%%     }.
+
+
+%% should_check_daemon(DName, _) ->
+%%     ?_test(begin
+%%         {ok, [D]} = couch_os_daemons:info([table]),
+%%         check_daemon(D, DName)
+%%     end).
+
+%% should_check_daemon_table_form(DName, _) ->
+%%     ?_test(begin
+%%         {ok, Tab} = couch_os_daemons:info(),
+%%         [D] = ets:tab2list(Tab),
+%%         check_daemon(D, DName)
+%%     end).
+
+%% should_clean_tables_on_daemon_remove(DName, _) ->
+%%     ?_test(begin
+%%         config:delete("os_daemons", DName, false),
+%%         {ok, Tab2} = couch_os_daemons:info(),
+%%         ?_assertEqual([], ets:tab2list(Tab2))
+%%     end).
+
+%% should_spawn_multiple_daemons(DName, _) ->
+%%     ?_test(begin
+%%         config:set("os_daemons", "bar",
+%%                          filename:join([?FIXTURESDIR, DName]), false),
+%%         config:set("os_daemons", "baz",
+%%                          filename:join([?FIXTURESDIR, DName]), false),
+%%         timer:sleep(?DELAY),
+%%         {ok, Daemons} = couch_os_daemons:info([table]),
+%%         lists:foreach(fun(D) ->
+%%             check_daemon(D)
+%%         end, Daemons),
+%%         {ok, Tab} = couch_os_daemons:info(),
+%%         lists:foreach(fun(D) ->
+%%             check_daemon(D)
+%%         end, ets:tab2list(Tab))
+%%     end).
+
+%% should_keep_alive_one_daemon_on_killing_other(DName, _) ->
+%%     ?_test(begin
+%%         config:set("os_daemons", "bar",
+%%                          filename:join([?FIXTURESDIR, DName]), false),
+%%         timer:sleep(?DELAY),
+%%         {ok, Daemons} = couch_os_daemons:info([table]),
+%%         lists:foreach(fun(D) ->
+%%             check_daemon(D)
+%%         end, Daemons),
+
+%%         config:delete("os_daemons", "bar", false),
+%%         timer:sleep(?DELAY),
+%%         {ok, [D2]} = couch_os_daemons:info([table]),
+%%         check_daemon(D2, DName),
+
+%%         {ok, Tab} = couch_os_daemons:info(),
+%%         [T] = ets:tab2list(Tab),
+%%         check_daemon(T, DName)
+%%     end).
+
+%% should_read_write_config_settings_by_daemon(DName, _) ->
+%%     ?_test(begin
+%%         % have to wait till daemon run all his tests
+%%         % see daemon's script for more info
+%%         timer:sleep(?TIMEOUT),
+%%         {ok, [D]} = couch_os_daemons:info([table]),
+%%         check_daemon(D, DName)
+%%     end).
+
+%% should_fail_due_to_lack_of_permissions(DName, _) ->
+%%     ?_test(should_halts(DName, 1000)).
+
+%% should_die_on_boot(DName, _) ->
+%%     ?_test(should_halts(DName, 1000)).
+
+%% should_die_quickly(DName, _) ->
+%%     ?_test(should_halts(DName, 4000)).
+
+%% should_not_being_halted(DName, _) ->
+%%     ?_test(begin
+%%         timer:sleep(1000),
+%%         {ok, [D1]} = couch_os_daemons:info([table]),
+%%         check_daemon(D1, DName, 0),
+
+%%         % Should reboot every two seconds. We're at 1s, so wait
+%%         % until 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, DName, 1),
+
+%%         % If the kill command changed, that means we rebooted the process.
+%%         ?assertNotEqual(D1#daemon.kill, D2#daemon.kill)
+%%     end).
+
+%% should_halts(DName, Time) ->
+%%     timer:sleep(Time),
+%%     {ok, [D]} = couch_os_daemons:info([table]),
+%%     check_dead(D, DName),
+%%     config:delete("os_daemons", DName, false).
+
+%% check_daemon(D) ->
+%%     check_daemon(D, D#daemon.name).
+
+%% check_daemon(D, Name) ->
+%%     check_daemon(D, Name, 0).
+
+%% check_daemon(D, Name, Errs) ->
+%%     ?assert(is_port(D#daemon.port)),
+%%     ?assertEqual(Name, D#daemon.name),
+%%     ?assertNotEqual(undefined, D#daemon.kill),
+%%     ?assertEqual(running, D#daemon.status),
+%%     ?assertEqual(Errs, length(D#daemon.errors)),
+%%     ?assertEqual([], D#daemon.buf).
+
+%% check_dead(D, Name) ->
+%%     ?assert(is_port(D#daemon.port)),
+%%     ?assertEqual(Name, D#daemon.name),
+%%     ?assertNotEqual(undefined, D#daemon.kill),
+%%     ?assertEqual(halted, D#daemon.status),
+%%     ?assertEqual(nil, D#daemon.errors),
+%%     ?assertEqual(nil, D#daemon.buf).


[30/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 230-pbkfd2.t etap test suite to eunit


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/ffb002cc
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/ffb002cc
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/ffb002cc

Branch: refs/heads/1963-eunit-bigcouch
Commit: ffb002cc7bf93df15430050933eb87c6b7b3c6c8
Parents: 3ca50ad
Author: Alexander Shorin <kx...@apache.org>
Authored: Tue Jun 10 00:19:52 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:45 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couch_passwords_tests.erl | 54 +++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/ffb002cc/test/couchdb/couch_passwords_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_passwords_tests.erl b/test/couchdb/couch_passwords_tests.erl
new file mode 100644
index 0000000..116265c
--- /dev/null
+++ b/test/couchdb/couch_passwords_tests.erl
@@ -0,0 +1,54 @@
+% 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(couch_passwords_tests).
+
+-include("couch_eunit.hrl").
+
+
+pbkdf2_test_()->
+    {"PBKDF2",
+     [
+         {"Iterations: 1, length: 20",
+          ?_assertEqual(
+              {ok, <<"0c60c80f961f0e71f3a9b524af6012062fe037a6">>},
+              couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 1, 20))},
+
+         {"Iterations: 2, length: 20",
+          ?_assertEqual(
+              {ok, <<"ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957">>},
+              couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 2, 20))},
+
+         {"Iterations: 4096, length: 20",
+          ?_assertEqual(
+              {ok, <<"4b007901b765489abead49d926f721d065a429c1">>},
+              couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 4096, 20))},
+
+         {"Iterations: 4096, length: 25",
+          ?_assertEqual(
+              {ok, <<"3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038">>},
+              couch_passwords:pbkdf2(<<"passwordPASSWORDpassword">>,
+                                     <<"saltSALTsaltSALTsaltSALTsaltSALTsalt">>,
+                                     4096, 25))},
+         {"Null byte",
+          ?_assertEqual(
+              {ok, <<"56fa6aa75548099dcc37d7f03425e0c3">>},
+              couch_passwords:pbkdf2(<<"pass\0word">>,
+                                     <<"sa\0lt">>,
+                                     4096, 16))},
+
+         {timeout, 180,  %% this may runs too long on slow hosts
+          {"Iterations: 16777216 - this may take some time",
+           ?_assertEqual(
+               {ok, <<"eefe3d61cd4da4e4e9945b3d6ba2158c2634e984">>},
+               couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 16777216, 20)
+           )}}]}.


[21/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 171-os-daemons-config.t etap test suite to eunit

Merged into couchdb_os_daemons_tests suite.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/a8a38c94
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/a8a38c94
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/a8a38c94

Branch: refs/heads/1963-eunit-bigcouch
Commit: a8a38c9424d02d46f4b4571a39a975b4f8e239af
Parents: 77a6a90
Author: Alexander Shorin <kx...@apache.org>
Authored: Tue Jun 3 14:10:25 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:44 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couch_auth_cache_tests.erl         |  40 +++-----
 test/couchdb/couchdb_os_daemons_tests.erl       |  21 ++++
 .../couchdb/fixtures/os_daemon_configer.escript | 101 +++++++++++++++++++
 3 files changed, 138 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/a8a38c94/test/couchdb/couch_auth_cache_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_auth_cache_tests.erl b/test/couchdb/couch_auth_cache_tests.erl
index 34f7127..3b2321c 100644
--- a/test/couchdb/couch_auth_cache_tests.erl
+++ b/test/couchdb/couch_auth_cache_tests.erl
@@ -74,47 +74,43 @@ should_get_nil_on_missed_cache(_) ->
     ?_assertEqual(nil, couch_auth_cache:get_user_creds("joe")).
 
 should_get_right_password_hash(DbName) ->
-    ?_assert(begin
+    ?_test(begin
         PasswordHash = hash_password("pass1"),
         {ok, _} = update_user_doc(DbName, "joe", "pass1"),
         Creds = couch_auth_cache:get_user_creds("joe"),
         ?assertEqual(PasswordHash,
-                      couch_util:get_value(<<"password_sha">>, Creds)),
-        true
+                      couch_util:get_value(<<"password_sha">>, Creds))
     end).
 
 should_ensure_doc_hash_equals_cached_one(DbName) ->
-    ?_assert(begin
+    ?_test(begin
         {ok, _} = update_user_doc(DbName, "joe", "pass1"),
         Creds = couch_auth_cache:get_user_creds("joe"),
 
         CachedHash = couch_util:get_value(<<"password_sha">>, Creds),
         StoredHash = get_user_doc_password_sha(DbName, "joe"),
-        ?assertEqual(StoredHash, CachedHash),
-        true
+        ?assertEqual(StoredHash, CachedHash)
     end).
 
 should_update_password(DbName) ->
-    ?_assert(begin
+    ?_test(begin
         PasswordHash = hash_password("pass2"),
         {ok, Rev} = update_user_doc(DbName, "joe", "pass1"),
         {ok, _} = update_user_doc(DbName, "joe", "pass2", Rev),
         Creds = couch_auth_cache:get_user_creds("joe"),
         ?assertEqual(PasswordHash,
-                      couch_util:get_value(<<"password_sha">>, Creds)),
-        true
+                      couch_util:get_value(<<"password_sha">>, Creds))
     end).
 
 should_cleanup_cache_after_userdoc_deletion(DbName) ->
-    ?_assert(begin
+    ?_test(begin
         {ok, _} = update_user_doc(DbName, "joe", "pass1"),
         delete_user_doc(DbName, "joe"),
-        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe")),
-        true
+        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe"))
     end).
 
 should_restore_cache_after_userdoc_recreation(DbName) ->
-    ?_assert(begin
+    ?_test(begin
         PasswordHash = hash_password("pass5"),
         {ok, _} = update_user_doc(DbName, "joe", "pass1"),
         delete_user_doc(DbName, "joe"),
@@ -124,22 +120,20 @@ should_restore_cache_after_userdoc_recreation(DbName) ->
         Creds = couch_auth_cache:get_user_creds("joe"),
 
         ?assertEqual(PasswordHash,
-                      couch_util:get_value(<<"password_sha">>, Creds)),
-        true
+                      couch_util:get_value(<<"password_sha">>, Creds))
     end).
 
 should_drop_cache_on_auth_db_change(DbName) ->
-    ?_assert(begin
+    ?_test(begin
         {ok, _} = update_user_doc(DbName, "joe", "pass1"),
         full_commit(DbName),
         couch_config:set("couch_httpd_auth", "authentication_db",
                          ?b2l(?tempdb()), false),
-        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe")),
-        true
+        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe"))
     end).
 
 should_restore_cache_on_auth_db_change(DbName) ->
-    ?_assert(begin
+    ?_test(begin
         PasswordHash = hash_password("pass1"),
         {ok, _} = update_user_doc(DbName, "joe", "pass1"),
         Creds = couch_auth_cache:get_user_creds("joe"),
@@ -157,20 +151,18 @@ should_restore_cache_on_auth_db_change(DbName) ->
 
         Creds = couch_auth_cache:get_user_creds("joe"),
         ?assertEqual(PasswordHash,
-                      couch_util:get_value(<<"password_sha">>, Creds)),
-        true
+                      couch_util:get_value(<<"password_sha">>, Creds))
     end).
 
 should_recover_cache_after_shutdown(DbName) ->
-    ?_assert(begin
+    ?_test(begin
         PasswordHash = hash_password("pass2"),
         {ok, Rev0} = update_user_doc(DbName, "joe", "pass1"),
         {ok, Rev1} = update_user_doc(DbName, "joe", "pass2", Rev0),
         full_commit(DbName),
         shutdown_db(DbName),
         {ok, Rev1} = get_doc_rev(DbName, "joe"),
-        ?assertEqual(PasswordHash, get_user_doc_password_sha(DbName, "joe")),
-        true
+        ?assertEqual(PasswordHash, get_user_doc_password_sha(DbName, "joe"))
     end).
 
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/a8a38c94/test/couchdb/couchdb_os_daemons_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_os_daemons_tests.erl b/test/couchdb/couchdb_os_daemons_tests.erl
index 1f9f6be..dd07e82 100644
--- a/test/couchdb/couchdb_os_daemons_tests.erl
+++ b/test/couchdb/couchdb_os_daemons_tests.erl
@@ -26,6 +26,7 @@
     buf=[]
 }).
 
+-define(DAEMON_CONFIGER, "os_daemon_configer.escript").
 -define(DAEMON_LOOPER, "os_daemon_looper.escript").
 -define(DELAY, 100).
 -define(TIMEOUT, 1000).
@@ -75,6 +76,17 @@ os_daemons_test_() ->
         }
     }.
 
+configuration_reader_test_() ->
+    {
+        "OS Daemon requests CouchDB configuration",
+        {
+            foreachx,
+            fun setup/1, fun teardown/2,
+            [{?DAEMON_CONFIGER,
+              fun should_read_write_config_settings_by_daemon/2}]
+        }
+    }.
+
 
 should_check_daemon(DName, _) ->
     ?_test(begin
@@ -133,6 +145,15 @@ should_keep_alive_one_daemon_on_killing_other(DName, _) ->
         check_daemon(T, DName)
     end).
 
+should_read_write_config_settings_by_daemon(DName, _) ->
+    ?_test(begin
+        % have to wait till daemon run all his tests
+        % see daemon's script for more info
+        timer:sleep(?TIMEOUT),
+        {ok, [D]} = couch_os_daemons:info([table]),
+        check_daemon(D, DName)
+    end).
+
 
 check_daemon(D) ->
     check_daemon(D, D#daemon.name).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/a8a38c94/test/couchdb/fixtures/os_daemon_configer.escript
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/os_daemon_configer.escript b/test/couchdb/fixtures/os_daemon_configer.escript
new file mode 100755
index 0000000..d437423
--- /dev/null
+++ b/test/couchdb/fixtures/os_daemon_configer.escript
@@ -0,0 +1,101 @@
+#! /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.
+
+-include("../couch_eunit.hrl").
+
+
+read() ->
+    case io:get_line('') of
+        eof ->
+            stop;
+        Data ->
+            ejson:decode(Data)
+    end.
+
+write(Mesg) ->
+    Data = iolist_to_binary(ejson: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() ->
+    Path = list_to_binary(?FILE),
+    FileName = list_to_binary(filename:basename(?FILE)),
+    {[{FileName, Path}]} = get_cfg(<<"os_daemons">>).
+
+test_get_cfg2() ->
+    Path = list_to_binary(?FILE),
+    FileName = list_to_binary(filename:basename(?FILE)),
+    Path = get_cfg(<<"os_daemons">>, FileName),
+    <<"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([]) ->
+    init_code_path(),
+    couch_config:start_link(?CONFIG_CHAIN),
+    couch_drv:start_link(),
+    do_tests().
+
+init_code_path() ->
+    Paths = [
+        "couchdb",
+        "ejson",
+        "erlang-oauth",
+        "ibrowse",
+        "mochiweb",
+        "snappy"
+    ],
+    lists:foreach(fun(Name) ->
+        code:add_patha(filename:join([?BUILDDIR, "src", Name]))
+    end, Paths).


[43/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
WIP: Switch to using test_util:start_config


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/fbad3c9c
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/fbad3c9c
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/fbad3c9c

Branch: refs/heads/1963-eunit-bigcouch
Commit: fbad3c9c82b655261f03519fab513e358fbbb2a5
Parents: dc041fe
Author: Russell Branca <ch...@apache.org>
Authored: Fri Aug 15 13:01:56 2014 -0700
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:24:06 2014 -0700

----------------------------------------------------------------------
 test/couch_config_tests.erl   | 2 +-
 test/couch_doc_json_tests.erl | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/fbad3c9c/test/couch_config_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_config_tests.erl b/test/couch_config_tests.erl
index 3b7a63f..50a91a6 100644
--- a/test/couch_config_tests.erl
+++ b/test/couch_config_tests.erl
@@ -41,7 +41,7 @@ setup({temporary, Chain}) ->
 setup({persistent, Chain}) ->
     setup(lists:append(Chain, [?CONFIG_FIXTURE_TEMP]));
 setup(Chain) ->
-    {ok, Pid} = config:start_link(Chain),
+    {ok, Pid} = test_util:start_config(Chain),
     Pid.
 
 setup_empty() ->

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/fbad3c9c/test/couch_doc_json_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_doc_json_tests.erl b/test/couch_doc_json_tests.erl
index ef5d0f2..64dea96 100644
--- a/test/couch_doc_json_tests.erl
+++ b/test/couch_doc_json_tests.erl
@@ -17,12 +17,12 @@
 
 
 setup() ->
-    config:start_link(?CONFIG_CHAIN),
+    {ok, Pid} = test_util:start_config(?CONFIG_CHAIN),
     config:set("attachments", "compression_level", "0", false),
-    ok.
+    Pid.
 
 teardown(_) ->
-    config:stop().
+    test_util:stop_config().
 
 
 json_doc_test_() ->


[42/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Switch to using config instead of couch_config


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/0456db3c
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/0456db3c
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/0456db3c

Branch: refs/heads/1963-eunit-bigcouch
Commit: 0456db3c0d9f0094cae69dd9877bdf0ced2a2d23
Parents: c237090
Author: Russell Branca <ch...@apache.org>
Authored: Mon Aug 11 15:52:57 2014 -0700
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:24:05 2014 -0700

----------------------------------------------------------------------
 test/couch_auth_cache_tests.erl          |   8 +-
 test/couch_config_tests.erl              | 112 +++++++++++++-------------
 test/couch_db_tests.erl                  |   2 +-
 test/couch_doc_json_tests.erl            |   6 +-
 test/couch_stats_tests.erl               |   4 +-
 test/couch_util_tests.erl                |   4 +-
 test/couch_uuids_tests.erl               |   6 +-
 test/couchdb_attachments_tests.erl       |   8 +-
 test/couchdb_compaction_daemon.erl       |  18 ++---
 test/couchdb_cors_tests.erl              |  28 +++----
 test/couchdb_csp_tests.erl               |  10 +--
 test/couchdb_file_compression_tests.erl  |  18 ++---
 test/couchdb_http_proxy_tests.erl        |   6 +-
 test/couchdb_os_daemons_tests.erl        |  18 ++---
 test/couchdb_os_proc_pool.erl            |   2 +-
 test/couchdb_update_conflicts_tests.erl  |   2 +-
 test/couchdb_vhosts_tests.erl            |  44 +++++-----
 test/couchdb_views_tests.erl             |  18 ++---
 test/fixtures/os_daemon_configer.escript |   2 +-
 19 files changed, 158 insertions(+), 158 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couch_auth_cache_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_auth_cache_tests.erl b/test/couch_auth_cache_tests.erl
index 371cb63..83531ff 100644
--- a/test/couch_auth_cache_tests.erl
+++ b/test/couch_auth_cache_tests.erl
@@ -22,7 +22,7 @@
 
 setup() ->
     DbName = ?tempdb(),
-    couch_config:set("couch_httpd_auth", "authentication_db",
+    config:set("couch_httpd_auth", "authentication_db",
                      ?b2l(DbName), false),
     DbName.
 
@@ -113,7 +113,7 @@ should_drop_cache_on_auth_db_change(DbName) ->
     ?_test(begin
         {ok, _} = update_user_doc(DbName, "joe", "pass1"),
         full_commit(DbName),
-        couch_config:set("couch_httpd_auth", "authentication_db",
+        config:set("couch_httpd_auth", "authentication_db",
                          ?b2l(?tempdb()), false),
         ?assertEqual(nil, couch_auth_cache:get_user_creds("joe"))
     end).
@@ -126,13 +126,13 @@ should_restore_cache_on_auth_db_change(DbName) ->
         full_commit(DbName),
 
         DbName1 = ?tempdb(),
-        couch_config:set("couch_httpd_auth", "authentication_db",
+        config:set("couch_httpd_auth", "authentication_db",
                          ?b2l(DbName1), false),
 
         {ok, _} = update_user_doc(DbName1, "joe", "pass5"),
         full_commit(DbName1),
 
-        couch_config:set("couch_httpd_auth", "authentication_db",
+        config:set("couch_httpd_auth", "authentication_db",
                          ?b2l(DbName), false),
 
         Creds = couch_auth_cache:get_user_creds("joe"),

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couch_config_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_config_tests.erl b/test/couch_config_tests.erl
index 91ec5e6..3b7a63f 100644
--- a/test/couch_config_tests.erl
+++ b/test/couch_config_tests.erl
@@ -41,7 +41,7 @@ setup({temporary, Chain}) ->
 setup({persistent, Chain}) ->
     setup(lists:append(Chain, [?CONFIG_FIXTURE_TEMP]));
 setup(Chain) ->
-    {ok, Pid} = couch_config:start_link(Chain),
+    {ok, Pid} = config:start_link(Chain),
     Pid.
 
 setup_empty() ->
@@ -74,7 +74,7 @@ teardown({ConfigPid, SentinelPid}) ->
             end
     end;
 teardown(Pid) ->
-    couch_config:stop(),
+    config:stop(),
     erlang:monitor(process, Pid),
     receive
         {'DOWN', _, _, Pid, _} ->
@@ -201,7 +201,7 @@ config_register_tests() ->
 
 config_no_files_tests() ->
     {
-        "Test couch_config with no files",
+        "Test config with no files",
         {
             foreach,
             fun setup_empty/0, fun teardown/1,
@@ -215,132 +215,132 @@ config_no_files_tests() ->
 
 
 should_load_all_configs() ->
-    ?_assert(length(couch_config:all()) > 0).
+    ?_assert(length(config:all()) > 0).
 
 should_locate_daemons_section() ->
-    ?_assert(length(couch_config:get("daemons")) > 0).
+    ?_assert(length(config:get("daemons")) > 0).
 
 should_locate_mrview_handler() ->
     ?_assertEqual("{couch_mrview_http, handle_view_req}",
-                  couch_config:get("httpd_design_handlers", "_view")).
+                  config:get("httpd_design_handlers", "_view")).
 
 should_return_undefined_atom_on_missed_section() ->
     ?_assertEqual(undefined,
-                  couch_config:get("foo", "bar")).
+                  config:get("foo", "bar")).
 
 should_return_undefined_atom_on_missed_option() ->
     ?_assertEqual(undefined,
-                  couch_config:get("httpd", "foo")).
+                  config:get("httpd", "foo")).
 
 should_return_custom_default_value_on_missed_option() ->
     ?_assertEqual("bar",
-                  couch_config:get("httpd", "foo", "bar")).
+                  config:get("httpd", "foo", "bar")).
 
 should_only_return_default_on_missed_option() ->
     ?_assertEqual("0",
-                  couch_config:get("httpd", "port", "bar")).
+                  config:get("httpd", "port", "bar")).
 
 should_get_binary_option() ->
     ?_assertEqual(<<"baz">>,
-                  couch_config:get(<<"foo">>, <<"bar">>, <<"baz">>)).
+                  config:get(<<"foo">>, <<"bar">>, <<"baz">>)).
 
 should_update_option() ->
     ?_assertEqual("severe",
         begin
-            ok = couch_config:set("log", "level", "severe", false),
-            couch_config:get("log", "level")
+            ok = config:set("log", "level", "severe", false),
+            config:get("log", "level")
         end).
 
 should_create_new_section() ->
     ?_assertEqual("bang",
         begin
-            undefined = couch_config:get("new_section", "bizzle"),
-            ok = couch_config:set("new_section", "bizzle", "bang", false),
-            couch_config:get("new_section", "bizzle")
+            undefined = config:get("new_section", "bizzle"),
+            ok = config:set("new_section", "bizzle", "bang", false),
+            config:get("new_section", "bizzle")
         end).
 
 should_set_binary_option() ->
     ?_assertEqual(<<"baz">>,
         begin
-            ok = couch_config:set(<<"foo">>, <<"bar">>, <<"baz">>, false),
-            couch_config:get(<<"foo">>, <<"bar">>)
+            ok = config:set(<<"foo">>, <<"bar">>, <<"baz">>, false),
+            config:get(<<"foo">>, <<"bar">>)
         end).
 
 should_return_undefined_atom_after_option_deletion() ->
     ?_assertEqual(undefined,
         begin
-            ok = couch_config:delete("log", "level", false),
-            couch_config:get("log", "level")
+            ok = config:delete("log", "level", false),
+            config:get("log", "level")
         end).
 
 should_be_ok_on_deleting_unknown_options() ->
-    ?_assertEqual(ok, couch_config:delete("zoo", "boo", false)).
+    ?_assertEqual(ok, config:delete("zoo", "boo", false)).
 
 should_delete_binary_option() ->
     ?_assertEqual(undefined,
         begin
-            ok = couch_config:set(<<"foo">>, <<"bar">>, <<"baz">>, false),
-            ok = couch_config:delete(<<"foo">>, <<"bar">>, false),
-            couch_config:get(<<"foo">>, <<"bar">>)
+            ok = config:set(<<"foo">>, <<"bar">>, <<"baz">>, false),
+            ok = config:delete(<<"foo">>, <<"bar">>, false),
+            config:get(<<"foo">>, <<"bar">>)
         end).
 
 should_ensure_in_defaults(_, _) ->
     ?_test(begin
         ?assertEqual("100",
-                     couch_config:get("couchdb", "max_dbs_open")),
+                     config:get("couchdb", "max_dbs_open")),
         ?assertEqual("5984",
-                     couch_config:get("httpd", "port")),
+                     config:get("httpd", "port")),
         ?assertEqual(undefined,
-                     couch_config:get("fizbang", "unicode"))
+                     config:get("fizbang", "unicode"))
     end).
 
 should_override_options(_, _) ->
     ?_test(begin
         ?assertEqual("10",
-                     couch_config:get("couchdb", "max_dbs_open")),
+                     config:get("couchdb", "max_dbs_open")),
         ?assertEqual("4895",
-                     couch_config:get("httpd", "port"))
+                     config:get("httpd", "port"))
     end).
 
 should_create_new_sections_on_override(_, _) ->
     ?_test(begin
         ?assertEqual("80",
-                     couch_config:get("httpd", "port")),
+                     config:get("httpd", "port")),
         ?assertEqual("normalized",
-                     couch_config:get("fizbang", "unicode"))
+                     config:get("fizbang", "unicode"))
     end).
 
 should_win_last_in_chain(_, _) ->
-    ?_assertEqual("80", couch_config:get("httpd", "port")).
+    ?_assertEqual("80", config:get("httpd", "port")).
 
 should_write_changes(_, _) ->
     ?_test(begin
         ?assertEqual("5984",
-                     couch_config:get("httpd", "port")),
+                     config:get("httpd", "port")),
         ?assertEqual(ok,
-                     couch_config:set("httpd", "port", "8080")),
+                     config:set("httpd", "port", "8080")),
         ?assertEqual("8080",
-                     couch_config:get("httpd", "port")),
+                     config:get("httpd", "port")),
         ?assertEqual(ok,
-                     couch_config:delete("httpd", "bind_address", "8080")),
+                     config:delete("httpd", "bind_address", "8080")),
         ?assertEqual(undefined,
-                     couch_config:get("httpd", "bind_address"))
+                     config:get("httpd", "bind_address"))
     end).
 
 should_ensure_that_default_wasnt_modified(_, _) ->
     ?_test(begin
         ?assertEqual("5984",
-                     couch_config:get("httpd", "port")),
+                     config:get("httpd", "port")),
         ?assertEqual("127.0.0.1",
-                     couch_config:get("httpd", "bind_address"))
+                     config:get("httpd", "bind_address"))
     end).
 
 should_ensure_that_written_to_last_config_in_chain(_, _) ->
     ?_test(begin
         ?assertEqual("8080",
-                     couch_config:get("httpd", "port")),
+                     config:get("httpd", "port")),
         ?assertEqual(undefined,
-                     couch_config:get("httpd", "bind_address"))
+                     config:get("httpd", "bind_address"))
     end).
 
 should_handle_port_changes({_, SentinelPid}) ->
@@ -348,16 +348,16 @@ should_handle_port_changes({_, SentinelPid}) ->
         MainProc = self(),
         Port = "8080",
 
-        couch_config:register(
+        config:register(
             fun("httpd", "port", Value) ->
-                % couch_config catches every error raised from handler
+                % config catches every error raised from handler
                 % so it's not possible to just assert on wrong value.
                 % We have to return the result as message
                 MainProc ! (Value =:= Port)
             end,
             SentinelPid
         ),
-        ok = couch_config:set("httpd", "port", Port, false),
+        ok = config:set("httpd", "port", Port, false),
 
         receive
             R ->
@@ -374,16 +374,16 @@ should_pass_persistent_flag({_, SentinelPid}) ->
     ?_assert(begin
         MainProc = self(),
 
-        couch_config:register(
+        config:register(
             fun("httpd", "port", _, Persist) ->
-                % couch_config catches every error raised from handler
+                % config catches every error raised from handler
                 % so it's not possible to just assert on wrong value.
                 % We have to return the result as message
                 MainProc ! Persist
             end,
             SentinelPid
         ),
-        ok = couch_config:set("httpd", "port", "8080", false),
+        ok = config:set("httpd", "port", "8080", false),
 
         receive
             false ->
@@ -397,13 +397,13 @@ should_not_trigger_handler_on_other_options_changes({_, SentinelPid}) ->
     ?_assert(begin
         MainProc = self(),
 
-        couch_config:register(
+        config:register(
             fun("httpd", "port", _) ->
                 MainProc ! ok
             end,
             SentinelPid
         ),
-        ok = couch_config:set("httpd", "bind_address", "0.0.0.0", false),
+        ok = config:set("httpd", "bind_address", "0.0.0.0", false),
 
         receive
             ok ->
@@ -417,7 +417,7 @@ should_not_trigger_handler_after_related_process_death({_, SentinelPid}) ->
     ?_assert(begin
         MainProc = self(),
 
-        couch_config:register(
+        config:register(
             fun("httpd", "port", _) ->
                 MainProc ! ok
             end,
@@ -435,7 +435,7 @@ should_not_trigger_handler_after_related_process_death({_, SentinelPid}) ->
                             {reason, "Timeout"}]})
         end,
 
-        ok = couch_config:set("httpd", "port", "12345", false),
+        ok = config:set("httpd", "port", "12345", false),
 
         receive
             ok ->
@@ -446,18 +446,18 @@ should_not_trigger_handler_after_related_process_death({_, SentinelPid}) ->
     end).
 
 should_ensure_that_no_ini_files_loaded() ->
-    ?_assertEqual(0, length(couch_config:all())).
+    ?_assertEqual(0, length(config:all())).
 
 should_create_non_persistent_option() ->
     ?_assertEqual("80",
         begin
-            ok = couch_config:set("httpd", "port", "80", false),
-            couch_config:get("httpd", "port")
+            ok = config:set("httpd", "port", "80", false),
+            config:get("httpd", "port")
         end).
 
 should_create_persistent_option() ->
     ?_assertEqual("127.0.0.1",
         begin
-            ok = couch_config:set("httpd", "bind_address", "127.0.0.1"),
-            couch_config:get("httpd", "bind_address")
+            ok = config:set("httpd", "bind_address", "127.0.0.1"),
+            config:get("httpd", "bind_address")
         end).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couch_db_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_db_tests.erl b/test/couch_db_tests.erl
index 90f0537..83d6a81 100644
--- a/test/couch_db_tests.erl
+++ b/test/couch_db_tests.erl
@@ -19,7 +19,7 @@
 
 setup() ->
     ok = test_util:start_couch(),
-    couch_config:set("log", "include_sasl", "false", false),
+    config:set("log", "include_sasl", "false", false),
     ok.
 
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couch_doc_json_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_doc_json_tests.erl b/test/couch_doc_json_tests.erl
index 23fc961..ef5d0f2 100644
--- a/test/couch_doc_json_tests.erl
+++ b/test/couch_doc_json_tests.erl
@@ -17,12 +17,12 @@
 
 
 setup() ->
-    couch_config:start_link(?CONFIG_CHAIN),
-    couch_config:set("attachments", "compression_level", "0", false),
+    config:start_link(?CONFIG_CHAIN),
+    config:set("attachments", "compression_level", "0", false),
     ok.
 
 teardown(_) ->
-    couch_config:stop().
+    config:stop().
 
 
 json_doc_test_() ->

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couch_stats_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_stats_tests.erl b/test/couch_stats_tests.erl
index 6dbbb6a..d62afaf 100644
--- a/test/couch_stats_tests.erl
+++ b/test/couch_stats_tests.erl
@@ -28,7 +28,7 @@ setup_collector() ->
     ok.
 
 setup_aggregator(_) ->
-    {ok, Pid} = couch_config:start_link([?STATS_INI_FIXTURE]),
+    {ok, Pid} = config:start_link([?STATS_INI_FIXTURE]),
     {ok, _} = couch_stats_collector:start(),
     {ok, _} = couch_stats_aggregator:start(?STATS_CFG_FIXTURE),
     Pid.
@@ -41,7 +41,7 @@ teardown_aggregator(_, Pid) ->
     couch_stats_aggregator:stop(),
     couch_stats_collector:stop(),
     erlang:monitor(process, Pid),
-    couch_config:stop(),
+    config:stop(),
     receive
         {'DOWN', _, _, Pid, _} ->
             ok

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couch_util_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_util_tests.erl b/test/couch_util_tests.erl
index c5689af..4c313a2 100644
--- a/test/couch_util_tests.erl
+++ b/test/couch_util_tests.erl
@@ -24,13 +24,13 @@ setup() ->
     %% {error, not_loaded_by_this_process} while it is. Any ideas is welcome.
     %%
     ok = test_util:start_couch(),
-    %% couch_config:start_link(?CONFIG_CHAIN),
+    %% config:start_link(?CONFIG_CHAIN),
     %% {ok, _} = couch_drv:start_link(),
     ok.
 
 teardown(_) ->
     ok = test_util:stop_couch(),
-    %% couch_config:stop(),
+    %% config:stop(),
     %% erl_ddll:unload_driver(couch_icu_driver),
     ok.
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couch_uuids_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_uuids_tests.erl b/test/couch_uuids_tests.erl
index 754a49b..27c5cb8 100644
--- a/test/couch_uuids_tests.erl
+++ b/test/couch_uuids_tests.erl
@@ -18,7 +18,7 @@
 
 
 setup() ->
-    {ok, Pid} = couch_config:start_link(?CONFIG_CHAIN),
+    {ok, Pid} = config:start_link(?CONFIG_CHAIN),
     erlang:monitor(process, Pid),
     couch_uuids:start(),
     Pid.
@@ -27,13 +27,13 @@ setup(Opts) ->
     Pid = setup(),
     lists:foreach(
         fun({Option, Value}) ->
-            couch_config:set("uuids", Option, Value, false)
+            config:set("uuids", Option, Value, false)
         end, Opts),
     Pid.
 
 teardown(Pid) ->
     couch_uuids:stop(),
-    couch_config:stop(),
+    config:stop(),
     receive
         {'DOWN', _, _, Pid, _} -> ok
     after

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couchdb_attachments_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_attachments_tests.erl b/test/couchdb_attachments_tests.erl
index 0391822..b203a82 100644
--- a/test/couchdb_attachments_tests.erl
+++ b/test/couchdb_attachments_tests.erl
@@ -29,16 +29,16 @@
 start() ->
     ok = test_util:start_couch(),
     % ensure in default compression settings for attachments_compression_tests
-    couch_config:set("attachments", "compression_level",
+    config:set("attachments", "compression_level",
                      ?i2l(?COMPRESSION_LEVEL), false),
-    couch_config:set("attachments", "compressible_types", "text/*", false),
+    config:set("attachments", "compressible_types", "text/*", false),
     ok.
 
 setup() ->
     DbName = ?tempdb(),
     {ok, Db} = couch_db:create(DbName, []),
     ok = couch_db:close(Db),
-    Addr = couch_config:get("httpd", "bind_address", any),
+    Addr = config:get("httpd", "bind_address", any),
     Port = mochiweb_socket_server:get(couch_httpd, port),
     Host = Addr ++ ":" ++ ?i2l(Port),
     {Host, ?b2l(DbName)}.
@@ -540,7 +540,7 @@ chunked_body([Chunk | Rest], Acc) ->
 
 get_socket() ->
     Options = [binary, {packet, 0}, {active, false}],
-    Addr = couch_config:get("httpd", "bind_address", any),
+    Addr = config:get("httpd", "bind_address", any),
     Port = mochiweb_socket_server:get(couch_httpd, port),
     {ok, Sock} = gen_tcp:connect(Addr, Port, Options),
     Sock.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couchdb_compaction_daemon.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_compaction_daemon.erl b/test/couchdb_compaction_daemon.erl
index de166a4..24c5d7b 100644
--- a/test/couchdb_compaction_daemon.erl
+++ b/test/couchdb_compaction_daemon.erl
@@ -23,8 +23,8 @@
 
 start() ->
     ok = test_util:start_couch(),
-    couch_config:set("compaction_daemon", "check_interval", "3", false),
-    couch_config:set("compaction_daemon", "min_file_size", "100000", false),
+    config:set("compaction_daemon", "check_interval", "3", false),
+    config:set("compaction_daemon", "min_file_size", "100000", false),
     ok.
 
 setup() ->
@@ -35,10 +35,10 @@ setup() ->
     DbName.
 
 teardown(DbName) ->
-    Configs = couch_config:get("compactions"),
+    Configs = config:get("compactions"),
     lists:foreach(
         fun({Key, _}) ->
-            ok = couch_config:delete("compactions", Key, false)
+            ok = config:delete("compactions", Key, false)
         end,
         Configs),
     couch_server:delete(DbName, [?ADMIN_USER]),
@@ -71,13 +71,13 @@ should_compact_by_default_rule(DbName) ->
         {_, DbFileSize} = get_db_frag(DbName),
         {_, ViewFileSize} = get_view_frag(DbName),
 
-        ok = couch_config:set("compactions", "_default",
+        ok = config:set("compactions", "_default",
             "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]",
             false),
 
         ok = timer:sleep(4000), % something >= check_interval
         wait_compaction_finished(DbName),
-        ok = couch_config:delete("compactions", "_default", false),
+        ok = config:delete("compactions", "_default", false),
 
         {DbFrag2, DbFileSize2} = get_db_frag(DbName),
         {ViewFrag2, ViewFileSize2} = get_view_frag(DbName),
@@ -100,13 +100,13 @@ should_compact_by_dbname_rule(DbName) ->
         {_, DbFileSize} = get_db_frag(DbName),
         {_, ViewFileSize} = get_view_frag(DbName),
 
-        ok = couch_config:set("compactions", ?b2l(DbName),
+        ok = config:set("compactions", ?b2l(DbName),
             "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]",
             false),
 
         ok = timer:sleep(4000), % something >= check_interval
         wait_compaction_finished(DbName),
-        ok = couch_config:delete("compactions", ?b2l(DbName), false),
+        ok = config:delete("compactions", ?b2l(DbName), false),
 
         {DbFrag2, DbFileSize2} = get_db_frag(DbName),
         {ViewFrag2, ViewFileSize2} = get_view_frag(DbName),
@@ -168,7 +168,7 @@ update(DbName) ->
     couch_db:close(Db).
 
 db_url(DbName) ->
-    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Addr = config:get("httpd", "bind_address", "127.0.0.1"),
     Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
     "http://" ++ Addr ++ ":" ++ Port ++ "/" ++ ?b2l(DbName).
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couchdb_cors_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_cors_tests.erl b/test/couchdb_cors_tests.erl
index 336d5ee..02f9da9 100644
--- a/test/couchdb_cors_tests.erl
+++ b/test/couchdb_cors_tests.erl
@@ -24,8 +24,8 @@
 
 start() ->
     ok = test_util:start_couch(),
-    ok = couch_config:set("httpd", "enable_cors", "true", false),
-    ok = couch_config:set("vhosts", "example.com", "/", false),
+    ok = config:set("httpd", "enable_cors", "true", false),
+    ok = config:set("vhosts", "example.com", "/", false),
     ok.
 
 setup() ->
@@ -33,10 +33,10 @@ setup() ->
     {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
     couch_db:close(Db),
 
-    couch_config:set("cors", "credentials", "false", false),
-    couch_config:set("cors", "origins", "http://example.com", false),
+    config:set("cors", "credentials", "false", false),
+    config:set("cors", "origins", "http://example.com", false),
 
-    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Addr = config:get("httpd", "bind_address", "127.0.0.1"),
     Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
     Host = "http://" ++ Addr ++ ":" ++ Port,
     {Host, ?b2l(DbName)}.
@@ -136,7 +136,7 @@ make_test_case(Mod, UseVhost, Funs) ->
 should_not_allow_origin(_, {_, _, Url, Headers0}) ->
     ?_assertEqual(undefined,
         begin
-            couch_config:delete("cors", "origins", false),
+            config:delete("cors", "origins", false),
             Headers1 = proplists:delete("Origin", Headers0),
             Headers = [{"Origin", "http://127.0.0.1"}]
                       ++ Headers1,
@@ -200,7 +200,7 @@ should_make_preflight_request(_, {_, _, Url, DefaultHeaders}) ->
 should_make_prefligh_request_with_port({_, VHost}, {_, _, Url, _}) ->
     ?_assertEqual("http://example.com:5984",
         begin
-            couch_config:set("cors", "origins", "http://example.com:5984",
+            config:set("cors", "origins", "http://example.com:5984",
                              false),
             Headers = [{"Origin", "http://example.com:5984"},
                        {"Access-Control-Request-Method", "GET"}]
@@ -212,7 +212,7 @@ should_make_prefligh_request_with_port({_, VHost}, {_, _, Url, _}) ->
 should_make_prefligh_request_with_scheme({_, VHost}, {_, _, Url, _}) ->
     ?_assertEqual("https://example.com:5984",
         begin
-            couch_config:set("cors", "origins", "https://example.com:5984",
+            config:set("cors", "origins", "https://example.com:5984",
                              false),
             Headers = [{"Origin", "https://example.com:5984"},
                        {"Access-Control-Request-Method", "GET"}]
@@ -224,7 +224,7 @@ should_make_prefligh_request_with_scheme({_, VHost}, {_, _, Url, _}) ->
 should_make_prefligh_request_with_wildcard_origin({_, VHost}, {_, _, Url, _}) ->
     ?_assertEqual("https://example.com:5984",
         begin
-            couch_config:set("cors", "origins", "*", false),
+            config:set("cors", "origins", "*", false),
             Headers = [{"Origin", "https://example.com:5984"},
                        {"Access-Control-Request-Method", "GET"}]
                       ++ maybe_append_vhost(VHost),
@@ -235,7 +235,7 @@ should_make_prefligh_request_with_wildcard_origin({_, VHost}, {_, _, Url, _}) ->
 should_make_request_with_credentials(_, {_, _, Url, DefaultHeaders}) ->
     ?_assertEqual("true",
         begin
-            ok = couch_config:set("cors", "credentials", "true", false),
+            ok = config:set("cors", "credentials", "true", false),
             {ok, _, Resp, _} = test_request:options(Url, DefaultHeaders),
             proplists:get_value("Access-Control-Allow-Credentials", Resp)
         end).
@@ -244,10 +244,10 @@ should_make_origin_request_with_auth(_, {_, _, Url, DefaultHeaders}) ->
     ?_assertEqual("http://example.com",
         begin
             Hashed = couch_passwords:hash_admin_password(<<"test">>),
-            couch_config:set("admins", "test", Hashed, false),
+            config:set("admins", "test", Hashed, false),
             {ok, _, Resp, _} = test_request:get(
                 Url, DefaultHeaders, [{basic_auth, {"test", "test"}}]),
-            couch_config:delete("admins", "test", false),
+            config:delete("admins", "test", false),
             proplists:get_value("Access-Control-Allow-Origin", Resp)
         end).
 
@@ -255,12 +255,12 @@ should_make_preflight_request_with_auth(_, {_, _, Url, DefaultHeaders}) ->
     ?_assertEqual(?SUPPORTED_METHODS,
         begin
             Hashed = couch_passwords:hash_admin_password(<<"test">>),
-            couch_config:set("admins", "test", Hashed, false),
+            config:set("admins", "test", Hashed, false),
             Headers = DefaultHeaders
                       ++ [{"Access-Control-Request-Method", "GET"}],
             {ok, _, Resp, _} = test_request:options(
                 Url, Headers, [{basic_auth, {"test", "test"}}]),
-            couch_config:delete("admins", "test", false),
+            config:delete("admins", "test", false),
             proplists:get_value("Access-Control-Allow-Methods", Resp)
         end).
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couchdb_csp_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_csp_tests.erl b/test/couchdb_csp_tests.erl
index 0626a08..3dbe6e3 100644
--- a/test/couchdb_csp_tests.erl
+++ b/test/couchdb_csp_tests.erl
@@ -18,8 +18,8 @@
 
 
 setup() ->
-    ok = couch_config:set("csp", "enable", "true", false),
-    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    ok = config:set("csp", "enable", "true", false),
+    Addr = config:get("httpd", "bind_address", "127.0.0.1"),
     Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
     lists:concat(["http://", Addr, ":", Port, "/_utils/"]).
 
@@ -50,7 +50,7 @@ csp_test_() ->
 should_not_return_any_csp_headers_when_disabled(Url) ->
     ?_assertEqual(undefined,
         begin
-            ok = couch_config:set("csp", "enable", "false", false),
+            ok = config:set("csp", "enable", "false", false),
             {ok, _, Headers, _} = test_request:get(Url),
             proplists:get_value("Content-Security-Policy", Headers)
         end).
@@ -67,7 +67,7 @@ should_apply_default_policy(Url) ->
 should_return_custom_policy(Url) ->
     ?_assertEqual("default-src 'http://example.com';",
         begin
-            ok = couch_config:set("csp", "header_value",
+            ok = config:set("csp", "header_value",
                                   "default-src 'http://example.com';", false),
             {ok, _, Headers, _} = test_request:get(Url),
             proplists:get_value("Content-Security-Policy", Headers)
@@ -76,7 +76,7 @@ should_return_custom_policy(Url) ->
 should_only_enable_csp_when_true(Url) ->
     ?_assertEqual(undefined,
         begin
-            ok = couch_config:set("csp", "enable", "tru", false),
+            ok = config:set("csp", "enable", "tru", false),
             {ok, _, Headers, _} = test_request:get(Url),
             proplists:get_value("Content-Security-Policy", Headers)
         end).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couchdb_file_compression_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_file_compression_tests.erl b/test/couchdb_file_compression_tests.erl
index 5573dd8..5b12882 100644
--- a/test/couchdb_file_compression_tests.erl
+++ b/test/couchdb_file_compression_tests.erl
@@ -22,7 +22,7 @@
 
 
 setup() ->
-    couch_config:set("couchdb", "file_compression", "none", false),
+    config:set("couchdb", "file_compression", "none", false),
     DbName = ?tempdb(),
     {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
     ok = populate_db(Db, ?DOCS_COUNT),
@@ -68,7 +68,7 @@ couch_auth_cache_test_() ->
 
 
 should_use_none(DbName) ->
-    couch_config:set("couchdb", "file_compression", "none", false),
+    config:set("couchdb", "file_compression", "none", false),
     {
         "Use no compression",
         [
@@ -78,7 +78,7 @@ should_use_none(DbName) ->
     }.
 
 should_use_deflate_1(DbName) ->
-    couch_config:set("couchdb", "file_compression", "deflate_1", false),
+    config:set("couchdb", "file_compression", "deflate_1", false),
     {
         "Use deflate compression at level 1",
         [
@@ -88,7 +88,7 @@ should_use_deflate_1(DbName) ->
     }.
 
 should_use_deflate_9(DbName) ->
-    couch_config:set("couchdb", "file_compression", "deflate_9", false),
+    config:set("couchdb", "file_compression", "deflate_9", false),
     {
         "Use deflate compression at level 9",
         [
@@ -98,7 +98,7 @@ should_use_deflate_9(DbName) ->
     }.
 
 should_use_snappy(DbName) ->
-    couch_config:set("couchdb", "file_compression", "snappy", false),
+    config:set("couchdb", "file_compression", "snappy", false),
     {
         "Use snappy compression",
         [
@@ -112,13 +112,13 @@ should_compare_compression_methods(DbName) ->
      {timeout, ?TIMEOUT div 1000, ?_test(compare_compression_methods(DbName))}}.
 
 compare_compression_methods(DbName) ->
-    couch_config:set("couchdb", "file_compression", "none", false),
+    config:set("couchdb", "file_compression", "none", false),
     compact_db(DbName),
     compact_view(DbName),
     DbSizeNone = db_disk_size(DbName),
     ViewSizeNone = view_disk_size(DbName),
 
-    couch_config:set("couchdb", "file_compression", "snappy", false),
+    config:set("couchdb", "file_compression", "snappy", false),
     compact_db(DbName),
     compact_view(DbName),
     DbSizeSnappy = db_disk_size(DbName),
@@ -127,7 +127,7 @@ compare_compression_methods(DbName) ->
     ?assert(DbSizeNone > DbSizeSnappy),
     ?assert(ViewSizeNone > ViewSizeSnappy),
 
-    couch_config:set("couchdb", "file_compression", "deflate_1", false),
+    config:set("couchdb", "file_compression", "deflate_1", false),
     compact_db(DbName),
     compact_view(DbName),
     DbSizeDeflate1 = db_disk_size(DbName),
@@ -136,7 +136,7 @@ compare_compression_methods(DbName) ->
     ?assert(DbSizeSnappy > DbSizeDeflate1),
     ?assert(ViewSizeSnappy > ViewSizeDeflate1),
 
-    couch_config:set("couchdb", "file_compression", "deflate_9", false),
+    config:set("couchdb", "file_compression", "deflate_9", false),
     compact_db(DbName),
     compact_view(DbName),
     DbSizeDeflate9 = db_disk_size(DbName),

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couchdb_http_proxy_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_http_proxy_tests.erl b/test/couchdb_http_proxy_tests.erl
index 0c554ff..cee6a02 100644
--- a/test/couchdb_http_proxy_tests.erl
+++ b/test/couchdb_http_proxy_tests.erl
@@ -33,7 +33,7 @@ start() ->
     % (each httpd_global_handlers changes causes couch_httpd restart)
     ok = test_util:start_couch(test_util:config_files() ++ [?CONFIG_FIXTURE_TEMP]),
     % 49151 is IANA Reserved, let's assume no one is listening there
-    couch_config:set("httpd_global_handlers", "_error",
+    config:set("httpd_global_handlers", "_error",
         "{couch_httpd_proxy, handle_proxy_req, <<\"http://127.0.0.1:49151/\">>}"
     ),
     ok.
@@ -43,7 +43,7 @@ setup() ->
     Value = lists:flatten(io_lib:format(
         "{couch_httpd_proxy, handle_proxy_req, ~p}",
         [list_to_binary(proxy_url())])),
-    couch_config:set("httpd_global_handlers", "_test", Value),
+    config:set("httpd_global_handlers", "_test", Value),
     % let couch_httpd restart
     timer:sleep(100),
     Pid.
@@ -381,7 +381,7 @@ server_url() ->
     server_url("/_test").
 
 server_url(Resource) ->
-    Addr = couch_config:get("httpd", "bind_address"),
+    Addr = config:get("httpd", "bind_address"),
     Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
     lists:concat(["http://", Addr, ":", Port, Resource]).
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couchdb_os_daemons_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_os_daemons_tests.erl b/test/couchdb_os_daemons_tests.erl
index ef21f58..3eeb7d7 100644
--- a/test/couchdb_os_daemons_tests.erl
+++ b/test/couchdb_os_daemons_tests.erl
@@ -37,16 +37,16 @@
 
 
 setup(DName) ->
-    {ok, CfgPid} = couch_config:start_link(?CONFIG_CHAIN),
+    {ok, CfgPid} = config:start_link(?CONFIG_CHAIN),
     {ok, OsDPid} = couch_os_daemons:start_link(),
-    couch_config:set("os_daemons", DName,
+    config:set("os_daemons", DName,
                      filename:join([?FIXTURESDIR, DName]), false),
     timer:sleep(?DELAY),  % sleep a bit to let daemon set kill flag
     {CfgPid, OsDPid}.
 
 teardown(_, {CfgPid, OsDPid}) ->
     erlang:monitor(process, CfgPid),
-    couch_config:stop(),
+    config:stop(),
     receive
         {'DOWN', _, _, CfgPid, _} ->
             ok
@@ -121,16 +121,16 @@ should_check_daemon_table_form(DName, _) ->
 
 should_clean_tables_on_daemon_remove(DName, _) ->
     ?_test(begin
-        couch_config:delete("os_daemons", DName, false),
+        config:delete("os_daemons", DName, false),
         {ok, Tab2} = couch_os_daemons:info(),
         ?_assertEqual([], ets:tab2list(Tab2))
     end).
 
 should_spawn_multiple_daemons(DName, _) ->
     ?_test(begin
-        couch_config:set("os_daemons", "bar",
+        config:set("os_daemons", "bar",
                          filename:join([?FIXTURESDIR, DName]), false),
-        couch_config:set("os_daemons", "baz",
+        config:set("os_daemons", "baz",
                          filename:join([?FIXTURESDIR, DName]), false),
         timer:sleep(?DELAY),
         {ok, Daemons} = couch_os_daemons:info([table]),
@@ -145,7 +145,7 @@ should_spawn_multiple_daemons(DName, _) ->
 
 should_keep_alive_one_daemon_on_killing_other(DName, _) ->
     ?_test(begin
-        couch_config:set("os_daemons", "bar",
+        config:set("os_daemons", "bar",
                          filename:join([?FIXTURESDIR, DName]), false),
         timer:sleep(?DELAY),
         {ok, Daemons} = couch_os_daemons:info([table]),
@@ -153,7 +153,7 @@ should_keep_alive_one_daemon_on_killing_other(DName, _) ->
             check_daemon(D)
         end, Daemons),
 
-        couch_config:delete("os_daemons", "bar", false),
+        config:delete("os_daemons", "bar", false),
         timer:sleep(?DELAY),
         {ok, [D2]} = couch_os_daemons:info([table]),
         check_daemon(D2, DName),
@@ -203,7 +203,7 @@ should_halts(DName, Time) ->
     timer:sleep(Time),
     {ok, [D]} = couch_os_daemons:info([table]),
     check_dead(D, DName),
-    couch_config:delete("os_daemons", DName, false).
+    config:delete("os_daemons", DName, false).
 
 check_daemon(D) ->
     check_daemon(D, D#daemon.name).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couchdb_os_proc_pool.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_os_proc_pool.erl b/test/couchdb_os_proc_pool.erl
index ae07d58..a8ab752 100644
--- a/test/couchdb_os_proc_pool.erl
+++ b/test/couchdb_os_proc_pool.erl
@@ -20,7 +20,7 @@
 
 start() ->
     ok = test_util:start_couch(),
-    couch_config:set("query_server_config", "os_process_limit", "3", false),
+    config:set("query_server_config", "os_process_limit", "3", false),
     ok.
 
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couchdb_update_conflicts_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_update_conflicts_tests.erl b/test/couchdb_update_conflicts_tests.erl
index 2450313..7ac1187 100644
--- a/test/couchdb_update_conflicts_tests.erl
+++ b/test/couchdb_update_conflicts_tests.erl
@@ -24,7 +24,7 @@
 
 start() ->
     ok = test_util:start_couch(),
-    couch_config:set("couchdb", "delayed_commits", "true", false),
+    config:set("couchdb", "delayed_commits", "true", false),
     ok.
 
 setup() ->

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couchdb_vhosts_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_vhosts_tests.erl b/test/couchdb_vhosts_tests.erl
index 7432022..321012f 100644
--- a/test/couchdb_vhosts_tests.erl
+++ b/test/couchdb_vhosts_tests.erl
@@ -47,7 +47,7 @@ setup() ->
     couch_db:ensure_full_commit(Db),
     couch_db:close(Db),
 
-    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Addr = config:get("httpd", "bind_address", "127.0.0.1"),
     Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
     Url = "http://" ++ Addr ++ ":" ++ Port,
     {Url, ?b2l(DbName)}.
@@ -56,14 +56,14 @@ setup_oauth() ->
     DbName = ?tempdb(),
     {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
 
-    couch_config:set("couch_httpd_auth", "authentication_db",
+    config:set("couch_httpd_auth", "authentication_db",
                      ?b2l(?tempdb()), false),
-    couch_config:set("oauth_token_users", "otoksec1", "joe", false),
-    couch_config:set("oauth_consumer_secrets", "consec1", "foo", false),
-    couch_config:set("oauth_token_secrets", "otoksec1", "foobar", false),
-    couch_config:set("couch_httpd_auth", "require_valid_user", "true", false),
+    config:set("oauth_token_users", "otoksec1", "joe", false),
+    config:set("oauth_consumer_secrets", "consec1", "foo", false),
+    config:set("oauth_token_secrets", "otoksec1", "foobar", false),
+    config:set("couch_httpd_auth", "require_valid_user", "true", false),
 
-    ok = couch_config:set(
+    ok = config:set(
         "vhosts", "oauth-example.com",
         "/" ++ ?b2l(DbName) ++ "/_design/test/_rewrite/foobar", false),
 
@@ -82,7 +82,7 @@ setup_oauth() ->
     couch_db:ensure_full_commit(Db),
     couch_db:close(Db),
 
-    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Addr = config:get("httpd", "bind_address", "127.0.0.1"),
     Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
     Url = "http://" ++ Addr ++ ":" ++ Port,
     {Url, ?b2l(DbName)}.
@@ -140,7 +140,7 @@ oauth_test_() ->
 
 should_return_database_info({Url, DbName}) ->
     ?_test(begin
-        ok = couch_config:set("vhosts", "example.com", "/" ++ DbName, false),
+        ok = config:set("vhosts", "example.com", "/" ++ DbName, false),
         case test_request:get(Url, [], [{host_header, "example.com"}]) of
             {ok, _, _, Body} ->
                 {JsonBody} = ejson:decode(Body),
@@ -155,7 +155,7 @@ should_return_database_info({Url, DbName}) ->
 
 should_return_revs_info({Url, DbName}) ->
     ?_test(begin
-        ok = couch_config:set("vhosts", "example.com", "/" ++ DbName, false),
+        ok = config:set("vhosts", "example.com", "/" ++ DbName, false),
         case test_request:get(Url ++ "/doc1?revs_info=true", [],
                               [{host_header, "example.com"}]) of
             {ok, _, _, Body} ->
@@ -171,7 +171,7 @@ should_return_revs_info({Url, DbName}) ->
 
 should_serve_utils_for_vhost({Url, DbName}) ->
     ?_test(begin
-        ok = couch_config:set("vhosts", "example.com", "/" ++ DbName, false),
+        ok = config:set("vhosts", "example.com", "/" ++ DbName, false),
         case test_request:get(Url ++ "/_utils/index.html", [],
                               [{host_header, "example.com"}]) of
             {ok, _, _, Body} ->
@@ -186,7 +186,7 @@ should_serve_utils_for_vhost({Url, DbName}) ->
 
 should_return_virtual_request_path_field_in_request({Url, DbName}) ->
     ?_test(begin
-        ok = couch_config:set("vhosts", "example1.com",
+        ok = config:set("vhosts", "example1.com",
                               "/" ++ DbName ++ "/_design/doc1/_rewrite/",
                               false),
         case test_request:get(Url, [], [{host_header, "example1.com"}]) of
@@ -204,7 +204,7 @@ should_return_virtual_request_path_field_in_request({Url, DbName}) ->
 
 should_return_real_request_path_field_in_request({Url, DbName}) ->
     ?_test(begin
-        ok = couch_config:set("vhosts", "example1.com",
+        ok = config:set("vhosts", "example1.com",
                               "/" ++ DbName ++ "/_design/doc1/_rewrite/",
                               false),
         case test_request:get(Url, [], [{host_header, "example1.com"}]) of
@@ -222,7 +222,7 @@ should_return_real_request_path_field_in_request({Url, DbName}) ->
 
 should_match_wildcard_vhost({Url, DbName}) ->
     ?_test(begin
-        ok = couch_config:set("vhosts", "*.example.com",
+        ok = config:set("vhosts", "*.example.com",
                               "/" ++ DbName ++ "/_design/doc1/_rewrite", false),
         case test_request:get(Url, [], [{host_header, "test.example.com"}]) of
             {ok, _, _, Body} ->
@@ -239,7 +239,7 @@ should_match_wildcard_vhost({Url, DbName}) ->
 
 should_return_db_info_for_wildcard_vhost_for_custom_db({Url, DbName}) ->
     ?_test(begin
-        ok = couch_config:set("vhosts", ":dbname.example1.com",
+        ok = config:set("vhosts", ":dbname.example1.com",
                               "/:dbname", false),
         Host = DbName ++ ".example1.com",
         case test_request:get(Url, [], [{host_header, Host}]) of
@@ -256,7 +256,7 @@ should_return_db_info_for_wildcard_vhost_for_custom_db({Url, DbName}) ->
 
 should_replace_rewrite_variables_for_db_and_doc({Url, DbName}) ->
     ?_test(begin
-        ok = couch_config:set("vhosts",":appname.:dbname.example1.com",
+        ok = config:set("vhosts",":appname.:dbname.example1.com",
                               "/:dbname/_design/:appname/_rewrite/", false),
         Host = "doc1." ++ DbName ++ ".example1.com",
         case test_request:get(Url, [], [{host_header, Host}]) of
@@ -274,7 +274,7 @@ should_replace_rewrite_variables_for_db_and_doc({Url, DbName}) ->
 
 should_return_db_info_for_vhost_with_resource({Url, DbName}) ->
     ?_test(begin
-        ok = couch_config:set("vhosts",
+        ok = config:set("vhosts",
                               "example.com/test", "/" ++ DbName, false),
         ReqUrl = Url ++ "/test",
         case test_request:get(ReqUrl, [], [{host_header, "example.com"}]) of
@@ -292,7 +292,7 @@ should_return_db_info_for_vhost_with_resource({Url, DbName}) ->
 
 should_return_revs_info_for_vhost_with_resource({Url, DbName}) ->
     ?_test(begin
-        ok = couch_config:set("vhosts",
+        ok = config:set("vhosts",
                               "example.com/test", "/" ++ DbName, false),
         ReqUrl = Url ++ "/test/doc1?revs_info=true",
         case test_request:get(ReqUrl, [], [{host_header, "example.com"}]) of
@@ -309,7 +309,7 @@ should_return_revs_info_for_vhost_with_resource({Url, DbName}) ->
 
 should_return_db_info_for_vhost_with_wildcard_resource({Url, DbName}) ->
     ?_test(begin
-        ok = couch_config:set("vhosts", "*.example2.com/test", "/*", false),
+        ok = config:set("vhosts", "*.example2.com/test", "/*", false),
         ReqUrl = Url ++ "/test",
         Host = DbName ++ ".example2.com",
         case test_request:get(ReqUrl, [], [{host_header, Host}]) of
@@ -326,7 +326,7 @@ should_return_db_info_for_vhost_with_wildcard_resource({Url, DbName}) ->
 
 should_return_path_for_vhost_with_wildcard_host({Url, DbName}) ->
     ?_test(begin
-        ok = couch_config:set("vhosts", "*/test1",
+        ok = config:set("vhosts", "*/test1",
                               "/" ++ DbName ++ "/_design/doc1/_show/test",
                               false),
         case test_request:get(Url ++ "/test1") of
@@ -360,7 +360,7 @@ should_require_auth({Url, _}) ->
 
 should_succeed_oauth({Url, _}) ->
     ?_test(begin
-        AuthDbName = couch_config:get("couch_httpd_auth", "authentication_db"),
+        AuthDbName = config:get("couch_httpd_auth", "authentication_db"),
         JoeDoc = couch_doc:from_json_obj({[
             {<<"_id">>, <<"org.couchdb.user:joe">>},
             {<<"type">>, <<"user">>},
@@ -394,7 +394,7 @@ should_succeed_oauth({Url, _}) ->
 
 should_fail_oauth_with_wrong_credentials({Url, _}) ->
     ?_test(begin
-        AuthDbName = couch_config:get("couch_httpd_auth", "authentication_db"),
+        AuthDbName = config:get("couch_httpd_auth", "authentication_db"),
         JoeDoc = couch_doc:from_json_obj({[
             {<<"_id">>, <<"org.couchdb.user:joe">>},
             {<<"type">>, <<"user">>},

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/couchdb_views_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_views_tests.erl b/test/couchdb_views_tests.erl
index 6efa7a1..03fb9cc 100644
--- a/test/couchdb_views_tests.erl
+++ b/test/couchdb_views_tests.erl
@@ -121,7 +121,7 @@ should_not_remember_docs_in_index_after_backup_restore_test() ->
 should_upgrade_legacy_view_files_test() ->
     start(),
 
-    ok = couch_config:set("query_server_config", "commit_freq", "0", false),
+    ok = config:set("query_server_config", "commit_freq", "0", false),
 
     DbName = <<"test">>,
     DbFileName = "test.couch",
@@ -130,8 +130,8 @@ should_upgrade_legacy_view_files_test() ->
     FixtureViewFilePath = filename:join([?FIXTURESDIR, OldViewName]),
     NewViewName = "a1c5929f912aca32f13446122cc6ce50.view",
 
-    DbDir = couch_config:get("couchdb", "database_dir"),
-    ViewDir = couch_config:get("couchdb", "view_index_dir"),
+    DbDir = config:get("couchdb", "database_dir"),
+    ViewDir = config:get("couchdb", "view_index_dir"),
     OldViewFilePath = filename:join([ViewDir, ".test_design", OldViewName]),
     NewViewFilePath = filename:join([ViewDir, ".test_design", "mrview",
                                      NewViewName]),
@@ -290,8 +290,8 @@ couchdb_1309(DbName) ->
 
 couchdb_1283() ->
     ?_test(begin
-        ok = couch_config:set("couchdb", "max_dbs_open", "3", false),
-        ok = couch_config:set("couchdb", "delayed_commits", "false", false),
+        ok = config:set("couchdb", "max_dbs_open", "3", false),
+        ok = config:set("couchdb", "delayed_commits", "false", false),
 
         {ok, MDb1} = couch_db:create(?tempdb(), [?ADMIN_USER]),
         DDoc = couch_doc:from_json_obj({[
@@ -463,7 +463,7 @@ delete_design_doc(DbName, DDName, Rev) ->
     couch_db:close(Db).
 
 db_url(DbName) ->
-    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Addr = config:get("httpd", "bind_address", "127.0.0.1"),
     Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
     "http://" ++ Addr ++ ":" ++ Port ++ "/" ++ ?b2l(DbName).
 
@@ -507,7 +507,7 @@ count_db_refs(DbName) ->
 
 count_index_files(DbName) ->
     % call server to fetch the index files
-    RootDir = couch_config:get("couchdb", "view_index_dir"),
+    RootDir = config:get("couchdb", "view_index_dir"),
     length(filelib:wildcard(RootDir ++ "/." ++
         binary_to_list(DbName) ++ "_design"++"/mrview/*")).
 
@@ -516,13 +516,13 @@ has_doc(DocId1, Rows) ->
     lists:any(fun({R}) -> lists:member({<<"id">>, DocId}, R) end, Rows).
 
 backup_db_file(DbName) ->
-    DbDir = couch_config:get("couchdb", "database_dir"),
+    DbDir = config:get("couchdb", "database_dir"),
     DbFile = filename:join([DbDir, ?b2l(DbName) ++ ".couch"]),
     {ok, _} = file:copy(DbFile, DbFile ++ ".backup"),
     ok.
 
 restore_backup_db_file(DbName) ->
-    DbDir = couch_config:get("couchdb", "database_dir"),
+    DbDir = config:get("couchdb", "database_dir"),
     stop(whereis(couch_server_sup)),
     DbFile = filename:join([DbDir, ?b2l(DbName) ++ ".couch"]),
     ok = file:delete(DbFile),

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0456db3c/test/fixtures/os_daemon_configer.escript
----------------------------------------------------------------------
diff --git a/test/fixtures/os_daemon_configer.escript b/test/fixtures/os_daemon_configer.escript
index d437423..0074fc0 100755
--- a/test/fixtures/os_daemon_configer.escript
+++ b/test/fixtures/os_daemon_configer.escript
@@ -83,7 +83,7 @@ loop({error, _Reason}) ->
 
 main([]) ->
     init_code_path(),
-    couch_config:start_link(?CONFIG_CHAIN),
+    config:start_link(?CONFIG_CHAIN),
     couch_drv:start_link(),
     do_tests().
 


[26/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 201-view-group-shutdown.t etap test suite to eunit

Merged into couchdb_views_tests suite. Database population reduced
to speedup test and removed second view index call which leaded to
race condition when compaction becomes completed in time of view index
update call and before assertion check for {error, all_dbs_active}.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/ffc32ef2
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/ffc32ef2
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/ffc32ef2

Branch: refs/heads/1963-eunit-bigcouch
Commit: ffc32ef2f3685af383676488168c7830a6bc1c8c
Parents: dee39e7
Author: Alexander Shorin <kx...@apache.org>
Authored: Sat Jun 7 01:23:38 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:44 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_views_tests.erl | 175 ++++++++++++++++++++++++++++++
 1 file changed, 175 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/ffc32ef2/test/couchdb/couchdb_views_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_views_tests.erl b/test/couchdb/couchdb_views_tests.erl
index 77ee4f5..57d5a14 100644
--- a/test/couchdb/couchdb_views_tests.erl
+++ b/test/couchdb/couchdb_views_tests.erl
@@ -94,6 +94,16 @@ view_group_db_leaks_test_() ->
         }
     }.
 
+view_group_shutdown_test_() ->
+    {
+        "View group shutdown",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            [couchdb_1283()]
+        }
+    }.
+
 
 should_not_remember_docs_in_index_after_backup_restore_test() ->
     %% COUCHDB-640
@@ -229,6 +239,87 @@ couchdb_1309(DbName) ->
         end
     end).
 
+couchdb_1283() ->
+    ?_test(begin
+        ok = couch_config:set("couchdb", "max_dbs_open", "3", false),
+        ok = couch_config:set("couchdb", "delayed_commits", "false", false),
+
+        {ok, MDb1} = couch_db:create(?tempdb(), [?ADMIN_USER]),
+        DDoc = couch_doc:from_json_obj({[
+            {<<"_id">>, <<"_design/foo">>},
+            {<<"language">>, <<"javascript">>},
+            {<<"views">>, {[
+                {<<"foo">>, {[
+                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
+                ]}},
+                {<<"foo2">>, {[
+                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
+                ]}},
+                {<<"foo3">>, {[
+                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
+                ]}},
+                {<<"foo4">>, {[
+                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
+                ]}},
+                {<<"foo5">>, {[
+                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
+                ]}}
+            ]}}
+        ]}),
+        {ok, _} = couch_db:update_doc(MDb1, DDoc, []),
+        ok = populate_db(MDb1, 100, 100),
+        query_view(MDb1#db.name, "foo", "foo"),
+        ok = couch_db:close(MDb1),
+
+        {ok, Db1} = couch_db:create(?tempdb(), [?ADMIN_USER]),
+        ok = couch_db:close(Db1),
+        {ok, Db2} = couch_db:create(?tempdb(), [?ADMIN_USER]),
+        ok = couch_db:close(Db2),
+        {ok, Db3} = couch_db:create(?tempdb(), [?ADMIN_USER]),
+        ok = couch_db:close(Db3),
+
+        Writer1 = spawn_writer(Db1#db.name),
+        Writer2 = spawn_writer(Db2#db.name),
+
+        ?assert(is_process_alive(Writer1)),
+        ?assert(is_process_alive(Writer2)),
+
+        ?assertEqual(ok, get_writer_status(Writer1)),
+        ?assertEqual(ok, get_writer_status(Writer2)),
+
+        {ok, MonRef} = couch_mrview:compact(MDb1#db.name, <<"_design/foo">>,
+                                            [monitor]),
+
+        Writer3 = spawn_writer(Db3#db.name),
+        ?assert(is_process_alive(Writer3)),
+        ?assertEqual({error, all_dbs_active}, get_writer_status(Writer3)),
+
+        ?assert(is_process_alive(Writer1)),
+        ?assert(is_process_alive(Writer2)),
+        ?assert(is_process_alive(Writer3)),
+
+        receive
+            {'DOWN', MonRef, process, _, Reason} ->
+                ?assertEqual(normal, Reason)
+        after ?TIMEOUT ->
+            erlang:error(
+                {assertion_failed,
+                 [{module, ?MODULE}, {line, ?LINE},
+                  {reason, "Failure compacting view group"}]})
+        end,
+
+        ?assertEqual(ok, writer_try_again(Writer3)),
+        ?assertEqual(ok, get_writer_status(Writer3)),
+
+        ?assert(is_process_alive(Writer1)),
+        ?assert(is_process_alive(Writer2)),
+        ?assert(is_process_alive(Writer3)),
+
+        ?assertEqual(ok, stop_writer(Writer1)),
+        ?assertEqual(ok, stop_writer(Writer2)),
+        ?assertEqual(ok, stop_writer(Writer3))
+    end).
+
 create_doc(DbName, DocId) when is_list(DocId) ->
     create_doc(DbName, ?l2b(DocId));
 create_doc(DbName, DocId) when is_binary(DocId) ->
@@ -262,6 +353,20 @@ create_docs(DbName) ->
     couch_db:ensure_full_commit(Db),
     couch_db:close(Db).
 
+populate_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_db(Db, BatchSize, N - length(Docs));
+populate_db(_Db, _, _) ->
+    ok.
+
 create_design_doc(DbName, DDName, ViewName) ->
     {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
     DDoc = couch_doc:from_json_obj({[
@@ -423,3 +528,73 @@ wait_view_compact_done(DbName, DDocId, N) ->
             ok = timer:sleep(?DELAY),
             wait_view_compact_done(DbName, DDocId, N - 1)
     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 ?TIMEOUT ->
+        timeout
+    end.
+
+writer_try_again(Writer) ->
+    Ref = make_ref(),
+    Writer ! {try_again, Ref},
+    receive
+        {ok, Ref} ->
+            ok
+    after ?TIMEOUT ->
+        timeout
+    end.
+
+stop_writer(Writer) ->
+    Ref = make_ref(),
+    Writer ! {stop, Ref},
+    receive
+        {ok, Ref} ->
+            ok
+    after ?TIMEOUT ->
+        erlang:error({assertion_failed,
+                      [{module, ?MODULE},
+                       {line, ?LINE},
+                       {reason, "Timeout on stopping process"}]})
+    end.
+
+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.


[37/50] [abbrv] Move files out of test/couchdb into top level test/ folder

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_file_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_file_tests.erl b/test/couch_file_tests.erl
new file mode 100644
index 0000000..ad13383
--- /dev/null
+++ b/test/couch_file_tests.erl
@@ -0,0 +1,265 @@
+% 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(couch_file_tests).
+
+-include("couch_eunit.hrl").
+
+-define(BLOCK_SIZE, 4096).
+-define(setup(F), {setup, fun setup/0, fun teardown/1, F}).
+-define(foreach(Fs), {foreach, fun setup/0, fun teardown/1, Fs}).
+
+
+setup() ->
+    {ok, Fd} = couch_file:open(?tempfile(), [create, overwrite]),
+    Fd.
+
+teardown(Fd) ->
+    ok = couch_file:close(Fd).
+
+
+open_close_test_() ->
+    {
+        "Test for proper file open and close",
+        [
+            should_return_enoent_if_missed(),
+            should_ignore_invalid_flags_with_open(),
+            ?setup(fun should_return_pid_on_file_open/1),
+            should_close_file_properly(),
+            ?setup(fun should_create_empty_new_files/1)
+        ]
+    }.
+
+should_return_enoent_if_missed() ->
+    ?_assertEqual({error, enoent}, couch_file:open("not a real file")).
+
+should_ignore_invalid_flags_with_open() ->
+    ?_assertMatch({ok, _},
+                  couch_file:open(?tempfile(), [create, invalid_option])).
+
+should_return_pid_on_file_open(Fd) ->
+    ?_assert(is_pid(Fd)).
+
+should_close_file_properly() ->
+    {ok, Fd} = couch_file:open(?tempfile(), [create, overwrite]),
+    ok = couch_file:close(Fd),
+    ?_assert(true).
+
+should_create_empty_new_files(Fd) ->
+    ?_assertMatch({ok, 0}, couch_file:bytes(Fd)).
+
+
+read_write_test_() ->
+    {
+        "Common file read/write tests",
+        ?foreach([
+            fun should_increase_file_size_on_write/1,
+            fun should_return_current_file_size_on_write/1,
+            fun should_write_and_read_term/1,
+            fun should_write_and_read_binary/1,
+            fun should_write_and_read_large_binary/1,
+            fun should_return_term_as_binary_for_reading_binary/1,
+            fun should_read_term_written_as_binary/1,
+            fun should_read_iolist/1,
+            fun should_fsync/1,
+            fun should_not_read_beyond_eof/1,
+            fun should_truncate/1
+        ])
+    }.
+
+
+should_increase_file_size_on_write(Fd) ->
+    {ok, 0, _} = couch_file:append_term(Fd, foo),
+    {ok, Size} = couch_file:bytes(Fd),
+    ?_assert(Size > 0).
+
+should_return_current_file_size_on_write(Fd) ->
+    {ok, 0, _} = couch_file:append_term(Fd, foo),
+    {ok, Size} = couch_file:bytes(Fd),
+    ?_assertMatch({ok, Size, _}, couch_file:append_term(Fd, bar)).
+
+should_write_and_read_term(Fd) ->
+    {ok, Pos, _} = couch_file:append_term(Fd, foo),
+    ?_assertMatch({ok, foo}, couch_file:pread_term(Fd, Pos)).
+
+should_write_and_read_binary(Fd) ->
+    {ok, Pos, _} = couch_file:append_binary(Fd, <<"fancy!">>),
+    ?_assertMatch({ok, <<"fancy!">>}, couch_file:pread_binary(Fd, Pos)).
+
+should_return_term_as_binary_for_reading_binary(Fd) ->
+    {ok, Pos, _} = couch_file:append_term(Fd, foo),
+    Foo = couch_compress:compress(foo, snappy),
+    ?_assertMatch({ok, Foo}, couch_file:pread_binary(Fd, Pos)).
+
+should_read_term_written_as_binary(Fd) ->
+    {ok, Pos, _} = couch_file:append_binary(Fd, <<131,100,0,3,102,111,111>>),
+    ?_assertMatch({ok, foo}, couch_file:pread_term(Fd, Pos)).
+
+should_write_and_read_large_binary(Fd) ->
+    BigBin = list_to_binary(lists:duplicate(100000, 0)),
+    {ok, Pos, _} = couch_file:append_binary(Fd, BigBin),
+    ?_assertMatch({ok, BigBin}, couch_file:pread_binary(Fd, Pos)).
+
+should_read_iolist(Fd) ->
+    %% append_binary == append_iolist?
+    %% Possible bug in pread_iolist or iolist() -> append_binary
+    {ok, Pos, _} = couch_file:append_binary(Fd, ["foo", $m, <<"bam">>]),
+    {ok, IoList} = couch_file:pread_iolist(Fd, Pos),
+    ?_assertMatch(<<"foombam">>, iolist_to_binary(IoList)).
+
+should_fsync(Fd) ->
+    {"How does on test fsync?", ?_assertMatch(ok, couch_file:sync(Fd))}.
+
+should_not_read_beyond_eof(_) ->
+    {"No idea how to test reading beyond EOF", ?_assert(true)}.
+
+should_truncate(Fd) ->
+    {ok, 0, _} = couch_file:append_term(Fd, foo),
+    {ok, Size} = couch_file:bytes(Fd),
+    BigBin = list_to_binary(lists:duplicate(100000, 0)),
+    {ok, _, _} = couch_file:append_binary(Fd, BigBin),
+    ok = couch_file:truncate(Fd, Size),
+    ?_assertMatch({ok, foo}, couch_file:pread_term(Fd, 0)).
+
+
+header_test_() ->
+    {
+        "File header read/write tests",
+        [
+            ?foreach([
+                fun should_write_and_read_atom_header/1,
+                fun should_write_and_read_tuple_header/1,
+                fun should_write_and_read_second_header/1,
+                fun should_truncate_second_header/1,
+                fun should_produce_same_file_size_on_rewrite/1,
+                fun should_save_headers_larger_than_block_size/1
+            ]),
+            should_recover_header_marker_corruption(),
+            should_recover_header_size_corruption(),
+            should_recover_header_md5sig_corruption(),
+            should_recover_header_data_corruption()
+        ]
+    }.
+
+
+should_write_and_read_atom_header(Fd) ->
+    ok = couch_file:write_header(Fd, hello),
+    ?_assertMatch({ok, hello}, couch_file:read_header(Fd)).
+
+should_write_and_read_tuple_header(Fd) ->
+    ok = couch_file:write_header(Fd, {<<"some_data">>, 32}),
+    ?_assertMatch({ok, {<<"some_data">>, 32}}, couch_file:read_header(Fd)).
+
+should_write_and_read_second_header(Fd) ->
+    ok = couch_file:write_header(Fd, {<<"some_data">>, 32}),
+    ok = couch_file:write_header(Fd, [foo, <<"more">>]),
+    ?_assertMatch({ok, [foo, <<"more">>]}, couch_file:read_header(Fd)).
+
+should_truncate_second_header(Fd) ->
+    ok = couch_file:write_header(Fd, {<<"some_data">>, 32}),
+    {ok, Size} = couch_file:bytes(Fd),
+    ok = couch_file:write_header(Fd, [foo, <<"more">>]),
+    ok = couch_file:truncate(Fd, Size),
+    ?_assertMatch({ok, {<<"some_data">>, 32}}, couch_file:read_header(Fd)).
+
+should_produce_same_file_size_on_rewrite(Fd) ->
+    ok = couch_file:write_header(Fd, {<<"some_data">>, 32}),
+    {ok, Size1} = couch_file:bytes(Fd),
+    ok = couch_file:write_header(Fd, [foo, <<"more">>]),
+    {ok, Size2} = couch_file:bytes(Fd),
+    ok = couch_file:truncate(Fd, Size1),
+    ok = couch_file:write_header(Fd, [foo, <<"more">>]),
+    ?_assertMatch({ok, Size2}, couch_file:bytes(Fd)).
+
+should_save_headers_larger_than_block_size(Fd) ->
+    Header = erlang:make_tuple(5000, <<"CouchDB">>),
+    couch_file:write_header(Fd, Header),
+    {"COUCHDB-1319", ?_assertMatch({ok, Header}, couch_file:read_header(Fd))}.
+
+
+should_recover_header_marker_corruption() ->
+    ?_assertMatch(
+        ok,
+        check_header_recovery(
+            fun(CouchFd, RawFd, Expect, HeaderPos) ->
+                ?assertNotMatch(Expect, couch_file:read_header(CouchFd)),
+                file:pwrite(RawFd, HeaderPos, <<0>>),
+                ?assertMatch(Expect, couch_file:read_header(CouchFd))
+            end)
+    ).
+
+should_recover_header_size_corruption() ->
+    ?_assertMatch(
+        ok,
+        check_header_recovery(
+            fun(CouchFd, RawFd, Expect, HeaderPos) ->
+                ?assertNotMatch(Expect, couch_file:read_header(CouchFd)),
+                % +1 for 0x1 byte marker
+                file:pwrite(RawFd, HeaderPos + 1, <<10/integer>>),
+                ?assertMatch(Expect, couch_file:read_header(CouchFd))
+            end)
+    ).
+
+should_recover_header_md5sig_corruption() ->
+    ?_assertMatch(
+        ok,
+        check_header_recovery(
+            fun(CouchFd, RawFd, Expect, HeaderPos) ->
+                ?assertNotMatch(Expect, couch_file:read_header(CouchFd)),
+                % +5 = +1 for 0x1 byte and +4 for term size.
+                file:pwrite(RawFd, HeaderPos + 5, <<"F01034F88D320B22">>),
+                ?assertMatch(Expect, couch_file:read_header(CouchFd))
+            end)
+    ).
+
+should_recover_header_data_corruption() ->
+    ?_assertMatch(
+        ok,
+        check_header_recovery(
+            fun(CouchFd, RawFd, Expect, HeaderPos) ->
+                ?assertNotMatch(Expect, couch_file:read_header(CouchFd)),
+                % +21 = +1 for 0x1 byte, +4 for term size and +16 for MD5 sig
+                file:pwrite(RawFd, HeaderPos + 21, <<"some data goes here!">>),
+                ?assertMatch(Expect, couch_file:read_header(CouchFd))
+            end)
+    ).
+
+
+check_header_recovery(CheckFun) ->
+    Path = ?tempfile(),
+    {ok, Fd} = couch_file:open(Path, [create, overwrite]),
+    {ok, RawFd} = file:open(Path, [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 ?BLOCK_SIZE) * ?BLOCK_SIZE};
+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).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_key_tree_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_key_tree_tests.erl b/test/couch_key_tree_tests.erl
new file mode 100644
index 0000000..753ecc4
--- /dev/null
+++ b/test/couch_key_tree_tests.erl
@@ -0,0 +1,380 @@
+% 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(couch_key_tree_tests).
+
+-include("couch_eunit.hrl").
+
+-define(DEPTH, 10).
+
+
+key_tree_merge_test_()->
+    {
+        "Key tree merge",
+        [
+            should_merge_with_empty_tree(),
+            should_merge_reflexive(),
+            should_merge_prefix_of_a_tree_with_tree(),
+            should_produce_conflict_on_merge_with_unrelated_branch(),
+            should_merge_reflexive_for_child_nodes(),
+            should_merge_tree_to_itself(),
+            should_merge_tree_of_odd_length(),
+            should_merge_tree_with_stem(),
+            should_merge_with_stem_at_deeper_level(),
+            should_merge_with_stem_at_deeper_level_with_deeper_paths(),
+            should_merge_single_tree_with_deeper_stem(),
+            should_merge_tree_with_large_stem(),
+            should_merge_stems(),
+            should_create_conflicts_on_merge(),
+            should_create_no_conflicts_on_merge(),
+            should_ignore_conflicting_branch()
+        ]
+    }.
+
+key_tree_missing_leaves_test_()->
+    {
+        "Missing tree leaves",
+        [
+            should_not_find_missing_leaves(),
+            should_find_missing_leaves()
+        ]
+    }.
+
+key_tree_remove_leaves_test_()->
+    {
+        "Remove tree leaves",
+        [
+            should_have_no_effect_on_removing_no_leaves(),
+            should_have_no_effect_on_removing_non_existant_branch(),
+            should_remove_leaf(),
+            should_produce_empty_tree_on_removing_all_leaves(),
+            should_have_no_effect_on_removing_non_existant_node(),
+            should_produce_empty_tree_on_removing_last_leaf()
+        ]
+    }.
+
+key_tree_get_leaves_test_()->
+    {
+        "Leaves retrieving",
+        [
+            should_extract_subtree(),
+            should_extract_subsubtree(),
+            should_gather_non_existant_leaf(),
+            should_gather_leaf(),
+            shoul_gather_multiple_leaves(),
+            should_retrieve_full_key_path(),
+            should_retrieve_full_key_path_for_node(),
+            should_retrieve_leaves_with_parent_node(),
+            should_retrieve_all_leaves()
+        ]
+    }.
+
+key_tree_leaf_counting_test_()->
+    {
+        "Leaf counting",
+        [
+            should_have_no_leaves_for_empty_tree(),
+            should_have_single_leaf_for_tree_with_single_node(),
+            should_have_two_leaves_for_tree_with_chindler_siblings(),
+            should_not_affect_on_leaf_counting_for_stemmed_tree()
+        ]
+    }.
+
+key_tree_stemming_test_()->
+    {
+        "Stemming",
+        [
+            should_have_no_effect_for_stemming_more_levels_than_exists(),
+            should_return_one_deepest_node(),
+            should_return_two_deepest_nodes()
+        ]
+    }.
+
+
+should_merge_with_empty_tree()->
+    One = {1, {"1","foo",[]}},
+    ?_assertEqual({[One], no_conflicts},
+                  couch_key_tree:merge([], One, ?DEPTH)).
+
+should_merge_reflexive()->
+    One = {1, {"1","foo",[]}},
+    ?_assertEqual({[One], no_conflicts},
+                  couch_key_tree:merge([One], One, ?DEPTH)).
+
+should_merge_prefix_of_a_tree_with_tree()->
+    One = {1, {"1","foo",[]}},
+    TwoSibs = [{1, {"1","foo",[]}},
+               {1, {"2","foo",[]}}],
+    ?_assertEqual({TwoSibs, no_conflicts},
+                  couch_key_tree:merge(TwoSibs, One, ?DEPTH)).
+
+should_produce_conflict_on_merge_with_unrelated_branch()->
+    TwoSibs = [{1, {"1","foo",[]}},
+               {1, {"2","foo",[]}}],
+    Three = {1, {"3","foo",[]}},
+    ThreeSibs = [{1, {"1","foo",[]}},
+                 {1, {"2","foo",[]}},
+                 {1, {"3","foo",[]}}],
+    ?_assertEqual({ThreeSibs, conflicts},
+                  couch_key_tree:merge(TwoSibs, Three, ?DEPTH)).
+
+should_merge_reflexive_for_child_nodes()->
+    TwoChild = {1, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}},
+    ?_assertEqual({[TwoChild], no_conflicts},
+                  couch_key_tree:merge([TwoChild], TwoChild, ?DEPTH)).
+
+should_merge_tree_to_itself()->
+    TwoChildSibs = {1, {"1","foo", [{"1a", "bar", []},
+                                    {"1b", "bar", []}]}},
+    ?_assertEqual({[TwoChildSibs], no_conflicts},
+                  couch_key_tree:merge([TwoChildSibs], TwoChildSibs, ?DEPTH)).
+
+should_merge_tree_of_odd_length()->
+    TwoChild = {1, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}},
+    TwoChildSibs = {1, {"1","foo", [{"1a", "bar", []},
+                                    {"1b", "bar", []}]}},
+    TwoChildPlusSibs = {1, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]},
+                                        {"1b", "bar", []}]}},
+
+    ?_assertEqual({[TwoChildPlusSibs], no_conflicts},
+                  couch_key_tree:merge([TwoChild], TwoChildSibs, ?DEPTH)).
+
+should_merge_tree_with_stem()->
+    Stemmed = {2, {"1a", "bar", []}},
+    TwoChildSibs = {1, {"1","foo", [{"1a", "bar", []},
+                                    {"1b", "bar", []}]}},
+
+    ?_assertEqual({[TwoChildSibs], no_conflicts},
+                  couch_key_tree:merge([TwoChildSibs], Stemmed, ?DEPTH)).
+
+should_merge_with_stem_at_deeper_level()->
+    Stemmed = {3, {"1bb", "boo", []}},
+    TwoChildSibs = {1, {"1","foo", [{"1a", "bar", []},
+                                    {"1b", "bar", [{"1bb", "boo", []}]}]}},
+    ?_assertEqual({[TwoChildSibs], no_conflicts},
+                  couch_key_tree:merge([TwoChildSibs], Stemmed, ?DEPTH)).
+
+should_merge_with_stem_at_deeper_level_with_deeper_paths()->
+    Stemmed = {3, {"1bb", "boo", []}},
+    StemmedTwoChildSibs = [{2,{"1a", "bar", []}},
+                           {2,{"1b", "bar", [{"1bb", "boo", []}]}}],
+    ?_assertEqual({StemmedTwoChildSibs, no_conflicts},
+                  couch_key_tree:merge(StemmedTwoChildSibs, Stemmed, ?DEPTH)).
+
+should_merge_single_tree_with_deeper_stem()->
+    Stemmed = {3, {"1aa", "bar", []}},
+    TwoChild = {1, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}},
+    ?_assertEqual({[TwoChild], no_conflicts},
+                  couch_key_tree:merge([TwoChild], Stemmed, ?DEPTH)).
+
+should_merge_tree_with_large_stem()->
+    Stemmed = {2, {"1a", "bar", [{"1aa", "bar", []}]}},
+    TwoChild = {1, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}},
+    ?_assertEqual({[TwoChild], no_conflicts},
+                  couch_key_tree:merge([TwoChild], Stemmed, ?DEPTH)).
+
+should_merge_stems()->
+    StemmedA = {2, {"1a", "bar", [{"1aa", "bar", []}]}},
+    StemmedB = {3, {"1aa", "bar", []}},
+    ?_assertEqual({[StemmedA], no_conflicts},
+                  couch_key_tree:merge([StemmedA], StemmedB, ?DEPTH)).
+
+should_create_conflicts_on_merge()->
+    OneChild = {1, {"1","foo",[{"1a", "bar", []}]}},
+    Stemmed = {3, {"1aa", "bar", []}},
+    ?_assertEqual({[OneChild, Stemmed], conflicts},
+                  couch_key_tree:merge([OneChild], Stemmed, ?DEPTH)).
+
+should_create_no_conflicts_on_merge()->
+    OneChild = {1, {"1","foo",[{"1a", "bar", []}]}},
+    Stemmed = {3, {"1aa", "bar", []}},
+    TwoChild = {1, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}},
+    ?_assertEqual({[TwoChild], no_conflicts},
+                  couch_key_tree:merge([OneChild, Stemmed], TwoChild, ?DEPTH)).
+
+should_ignore_conflicting_branch()->
+    %% 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",[]}]}
+               ]}},
+    {
+        "COUCHDB-902",
+        ?_assertEqual({[FooBar], no_conflicts},
+                      couch_key_tree:merge([Foo], Bar, ?DEPTH))
+    }.
+
+should_not_find_missing_leaves()->
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    ?_assertEqual([],
+                  couch_key_tree:find_missing(TwoChildSibs,
+                                              [{0,"1"}, {1,"1a"}])).
+
+should_find_missing_leaves()->
+    Stemmed1 = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}],
+    Stemmed2 = [{2, {"1aa", "bar", []}}],
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    [
+        ?_assertEqual(
+            [{0, "10"}, {100, "x"}],
+            couch_key_tree:find_missing(
+                TwoChildSibs,
+                [{0,"1"}, {0, "10"}, {1,"1a"}, {100, "x"}])),
+        ?_assertEqual(
+            [{0, "1"}, {100, "x"}],
+            couch_key_tree:find_missing(
+                Stemmed1,
+                [{0,"1"}, {1,"1a"}, {100, "x"}])),
+        ?_assertEqual(
+            [{0, "1"}, {1,"1a"}, {100, "x"}],
+            couch_key_tree:find_missing(
+                Stemmed2,
+                [{0,"1"}, {1,"1a"}, {100, "x"}]))
+    ].
+
+should_have_no_effect_on_removing_no_leaves()->
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    ?_assertEqual({TwoChildSibs, []},
+                  couch_key_tree:remove_leafs(TwoChildSibs,
+                                              [])).
+
+should_have_no_effect_on_removing_non_existant_branch()->
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    ?_assertEqual({TwoChildSibs, []},
+                  couch_key_tree:remove_leafs(TwoChildSibs,
+                                              [{0, "1"}])).
+
+should_remove_leaf()->
+    OneChild = [{0, {"1","foo",[{"1a", "bar", []}]}}],
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    ?_assertEqual({OneChild, [{1, "1b"}]},
+                  couch_key_tree:remove_leafs(TwoChildSibs,
+                                              [{1, "1b"}])).
+
+should_produce_empty_tree_on_removing_all_leaves()->
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    ?_assertEqual({[], [{1, "1b"}, {1, "1a"}]},
+                  couch_key_tree:remove_leafs(TwoChildSibs,
+                                              [{1, "1b"}, {1, "1a"}])).
+
+should_have_no_effect_on_removing_non_existant_node()->
+    Stemmed = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}],
+    ?_assertEqual({Stemmed, []},
+                  couch_key_tree:remove_leafs(Stemmed,
+                                              [{1, "1a"}])).
+
+should_produce_empty_tree_on_removing_last_leaf()->
+    Stemmed = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}],
+    ?_assertEqual({[], [{2, "1aa"}]},
+                  couch_key_tree:remove_leafs(Stemmed,
+                                              [{2, "1aa"}])).
+
+should_extract_subtree()->
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    ?_assertEqual({[{"foo", {0, ["1"]}}],[]},
+                  couch_key_tree:get(TwoChildSibs, [{0, "1"}])).
+
+should_extract_subsubtree()->
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    ?_assertEqual({[{"bar", {1, ["1a", "1"]}}],[]},
+                  couch_key_tree:get(TwoChildSibs, [{1, "1a"}])).
+
+should_gather_non_existant_leaf()->
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    ?_assertEqual({[],[{0, "x"}]},
+                  couch_key_tree:get_key_leafs(TwoChildSibs, [{0, "x"}])).
+
+should_gather_leaf()->
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    ?_assertEqual({[{"bar", {1, ["1a","1"]}}],[]},
+                  couch_key_tree:get_key_leafs(TwoChildSibs, [{1, "1a"}])).
+
+shoul_gather_multiple_leaves()->
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    ?_assertEqual({[{"bar", {1, ["1a","1"]}},{"bar",{1, ["1b","1"]}}],[]},
+                  couch_key_tree:get_key_leafs(TwoChildSibs, [{0, "1"}])).
+
+should_retrieve_full_key_path()->
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    ?_assertEqual({[{0,[{"1", "foo"}]}],[]},
+                  couch_key_tree:get_full_key_paths(TwoChildSibs, [{0, "1"}])).
+
+should_retrieve_full_key_path_for_node()->
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    ?_assertEqual({[{1,[{"1a", "bar"},{"1", "foo"}]}],[]},
+                  couch_key_tree:get_full_key_paths(TwoChildSibs, [{1, "1a"}])).
+
+should_retrieve_leaves_with_parent_node()->
+    Stemmed = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}],
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    [
+        ?_assertEqual([{2, [{"1aa", "bar"},{"1a", "bar"}]}],
+                      couch_key_tree:get_all_leafs_full(Stemmed)),
+        ?_assertEqual([{1, [{"1a", "bar"},{"1", "foo"}]},
+                       {1, [{"1b", "bar"},{"1", "foo"}]}],
+                      couch_key_tree:get_all_leafs_full(TwoChildSibs))
+    ].
+
+should_retrieve_all_leaves()->
+    Stemmed = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}],
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    [
+        ?_assertEqual([{"bar", {2, ["1aa","1a"]}}],
+                      couch_key_tree:get_all_leafs(Stemmed)),
+        ?_assertEqual([{"bar", {1, ["1a", "1"]}}, {"bar", {1, ["1b","1"]}}],
+                      couch_key_tree:get_all_leafs(TwoChildSibs))
+    ].
+
+should_have_no_leaves_for_empty_tree()->
+    ?_assertEqual(0, couch_key_tree:count_leafs([])).
+
+should_have_single_leaf_for_tree_with_single_node()->
+    ?_assertEqual(1, couch_key_tree:count_leafs([{0, {"1","foo",[]}}])).
+
+should_have_two_leaves_for_tree_with_chindler_siblings()->
+    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
+    ?_assertEqual(2, couch_key_tree:count_leafs(TwoChildSibs)).
+
+should_not_affect_on_leaf_counting_for_stemmed_tree()->
+    ?_assertEqual(1, couch_key_tree:count_leafs([{2, {"1bb", "boo", []}}])).
+
+should_have_no_effect_for_stemming_more_levels_than_exists()->
+    TwoChild = [{0, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}}],
+    ?_assertEqual(TwoChild, couch_key_tree:stem(TwoChild, 3)).
+
+should_return_one_deepest_node()->
+    TwoChild = [{0, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}}],
+    Stemmed = [{2, {"1aa", "bar", []}}],
+    ?_assertEqual(Stemmed, couch_key_tree:stem(TwoChild, 1)).
+
+should_return_two_deepest_nodes()->
+    TwoChild = [{0, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}}],
+    Stemmed = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}],
+    ?_assertEqual(Stemmed, couch_key_tree:stem(TwoChild, 2)).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_passwords_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_passwords_tests.erl b/test/couch_passwords_tests.erl
new file mode 100644
index 0000000..116265c
--- /dev/null
+++ b/test/couch_passwords_tests.erl
@@ -0,0 +1,54 @@
+% 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(couch_passwords_tests).
+
+-include("couch_eunit.hrl").
+
+
+pbkdf2_test_()->
+    {"PBKDF2",
+     [
+         {"Iterations: 1, length: 20",
+          ?_assertEqual(
+              {ok, <<"0c60c80f961f0e71f3a9b524af6012062fe037a6">>},
+              couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 1, 20))},
+
+         {"Iterations: 2, length: 20",
+          ?_assertEqual(
+              {ok, <<"ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957">>},
+              couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 2, 20))},
+
+         {"Iterations: 4096, length: 20",
+          ?_assertEqual(
+              {ok, <<"4b007901b765489abead49d926f721d065a429c1">>},
+              couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 4096, 20))},
+
+         {"Iterations: 4096, length: 25",
+          ?_assertEqual(
+              {ok, <<"3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038">>},
+              couch_passwords:pbkdf2(<<"passwordPASSWORDpassword">>,
+                                     <<"saltSALTsaltSALTsaltSALTsaltSALTsalt">>,
+                                     4096, 25))},
+         {"Null byte",
+          ?_assertEqual(
+              {ok, <<"56fa6aa75548099dcc37d7f03425e0c3">>},
+              couch_passwords:pbkdf2(<<"pass\0word">>,
+                                     <<"sa\0lt">>,
+                                     4096, 16))},
+
+         {timeout, 180,  %% this may runs too long on slow hosts
+          {"Iterations: 16777216 - this may take some time",
+           ?_assertEqual(
+               {ok, <<"eefe3d61cd4da4e4e9945b3d6ba2158c2634e984">>},
+               couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 16777216, 20)
+           )}}]}.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_ref_counter_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_ref_counter_tests.erl b/test/couch_ref_counter_tests.erl
new file mode 100644
index 0000000..b7e97b4
--- /dev/null
+++ b/test/couch_ref_counter_tests.erl
@@ -0,0 +1,107 @@
+% 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(couch_ref_counter_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(TIMEOUT, 1000).
+
+
+setup() ->
+    {ok, RefCtr} = couch_ref_counter:start([]),
+    ChildPid = spawn(fun() -> loop() end),
+    {RefCtr, ChildPid}.
+
+teardown({_, ChildPid}) ->
+    erlang:monitor(process, ChildPid),
+    ChildPid ! close,
+    wait().
+
+
+couch_ref_counter_test_() ->
+    {
+        "CouchDB reference counter tests",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_initialize_with_calling_process_as_referrer/1,
+                fun should_ignore_unknown_pid/1,
+                fun should_increment_counter_on_pid_add/1,
+                fun should_not_increase_counter_on_readding_same_pid/1,
+                fun should_drop_ref_for_double_added_pid/1,
+                fun should_decrement_counter_on_pid_drop/1,
+                fun should_add_after_drop/1,
+                fun should_decrement_counter_on_process_exit/1
+
+            ]
+        }
+    }.
+
+
+should_initialize_with_calling_process_as_referrer({RefCtr, _}) ->
+    ?_assertEqual(1, couch_ref_counter:count(RefCtr)).
+
+should_ignore_unknown_pid({RefCtr, ChildPid}) ->
+    ?_assertEqual(ok, couch_ref_counter:drop(RefCtr, ChildPid)).
+
+should_increment_counter_on_pid_add({RefCtr, ChildPid}) ->
+    couch_ref_counter:add(RefCtr, ChildPid),
+    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
+
+should_not_increase_counter_on_readding_same_pid({RefCtr, ChildPid}) ->
+    couch_ref_counter:add(RefCtr, ChildPid),
+    couch_ref_counter:add(RefCtr, ChildPid),
+    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
+
+should_drop_ref_for_double_added_pid({RefCtr, ChildPid}) ->
+    couch_ref_counter:add(RefCtr, ChildPid),
+    couch_ref_counter:add(RefCtr, ChildPid),
+    couch_ref_counter:drop(RefCtr, ChildPid),
+    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
+
+should_decrement_counter_on_pid_drop({RefCtr, ChildPid}) ->
+    couch_ref_counter:add(RefCtr, ChildPid),
+    couch_ref_counter:drop(RefCtr, ChildPid),
+    ?_assertEqual(1, couch_ref_counter:count(RefCtr)).
+
+should_add_after_drop({RefCtr, ChildPid}) ->
+    couch_ref_counter:add(RefCtr, ChildPid),
+    couch_ref_counter:drop(RefCtr, ChildPid),
+    couch_ref_counter:add(RefCtr, ChildPid),
+    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
+
+should_decrement_counter_on_process_exit({RefCtr, ChildPid}) ->
+    ?_assertEqual(1,
+        begin
+            couch_ref_counter:add(RefCtr, ChildPid),
+            erlang:monitor(process, ChildPid),
+            ChildPid ! close,
+            wait(),
+            couch_ref_counter:count(RefCtr)
+        end).
+
+
+loop() ->
+    receive
+        close -> ok
+    end.
+
+wait() ->
+    receive
+        {'DOWN', _, _, _, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw(timeout_error)
+    end.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_stats_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_stats_tests.erl b/test/couch_stats_tests.erl
new file mode 100644
index 0000000..d156449
--- /dev/null
+++ b/test/couch_stats_tests.erl
@@ -0,0 +1,412 @@
+% 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(couch_stats_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(STATS_CFG_FIXTURE,
+    filename:join([?FIXTURESDIR, "couch_stats_aggregates.cfg"])).
+-define(STATS_INI_FIXTURE,
+    filename:join([?FIXTURESDIR, "couch_stats_aggregates.ini"])).
+-define(TIMEOUT, 1000).
+-define(TIMEWAIT, 500).
+
+
+setup_collector() ->
+    couch_stats_collector:start(),
+    ok.
+
+setup_aggregator(_) ->
+    {ok, Pid} = couch_config:start_link([?STATS_INI_FIXTURE]),
+    {ok, _} = couch_stats_collector:start(),
+    {ok, _} = couch_stats_aggregator:start(?STATS_CFG_FIXTURE),
+    Pid.
+
+teardown_collector(_) ->
+    couch_stats_collector:stop(),
+    ok.
+
+teardown_aggregator(_, Pid) ->
+    couch_stats_aggregator:stop(),
+    couch_stats_collector:stop(),
+    erlang:monitor(process, Pid),
+    couch_config:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, config_stop})
+    end,
+    ok.
+
+
+couch_stats_collector_test_() ->
+    {
+        "CouchDB stats collector tests",
+        {
+            foreach,
+            fun setup_collector/0, fun teardown_collector/1,
+            [
+                should_increment_counter(),
+                should_decrement_counter(),
+                should_increment_and_decrement_counter(),
+                should_record_absolute_values(),
+                should_clear_absolute_values(),
+                should_track_process_count(),
+                should_increment_counter_multiple_times_per_pid(),
+                should_decrement_counter_on_process_exit(),
+                should_decrement_for_each_track_process_count_call_on_exit(),
+                should_return_all_counters_and_absolute_values(),
+                should_return_incremental_counters(),
+                should_return_absolute_values()
+            ]
+        }
+    }.
+
+couch_stats_aggregator_test_() ->
+    Funs = [
+        fun should_init_empty_aggregate/2,
+        fun should_get_empty_aggregate/2,
+        fun should_change_stats_on_values_add/2,
+        fun should_change_stats_for_all_times_on_values_add/2,
+        fun should_change_stats_on_values_change/2,
+        fun should_change_stats_for_all_times_on_values_change/2,
+        fun should_not_remove_data_after_some_time_for_0_sample/2,
+        fun should_remove_data_after_some_time_for_other_samples/2
+    ],
+    {
+        "CouchDB stats aggregator tests",
+        [
+            {
+                "Absolute values",
+                {
+                    foreachx,
+                    fun setup_aggregator/1, fun teardown_aggregator/2,
+                    [{absolute, Fun} || Fun <- Funs]
+                }
+            },
+            {
+                "Counters",
+                {
+                    foreachx,
+                    fun setup_aggregator/1, fun teardown_aggregator/2,
+                    [{counter, Fun} || Fun <- Funs]
+                }
+            }
+        ]
+    }.
+
+
+should_increment_counter() ->
+    ?_assertEqual(100,
+        begin
+            AddCount = fun() -> couch_stats_collector:increment(foo) end,
+            repeat(AddCount, 100),
+            couch_stats_collector:get(foo)
+        end).
+
+should_decrement_counter() ->
+    ?_assertEqual(67,
+        begin
+            AddCount = fun() -> couch_stats_collector:increment(foo) end,
+            RemCount = fun() -> couch_stats_collector:decrement(foo) end,
+            repeat(AddCount, 100),
+            repeat(RemCount, 33),
+            couch_stats_collector:get(foo)
+        end).
+
+should_increment_and_decrement_counter() ->
+    ?_assertEqual(0,
+        begin
+            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),
+            repeat(RemCount, 80),
+            couch_stats_collector:get(foo)
+        end).
+
+should_record_absolute_values() ->
+    ?_assertEqual(lists:seq(1, 15),
+        begin
+            lists:map(fun(Val) ->
+                couch_stats_collector:record(bar, Val)
+            end, lists:seq(1, 15)),
+            couch_stats_collector:get(bar)
+        end).
+
+should_clear_absolute_values() ->
+    ?_assertEqual(nil,
+        begin
+            lists:map(fun(Val) ->
+                couch_stats_collector:record(bar, Val)
+            end, lists:seq(1, 15)),
+            couch_stats_collector:clear(bar),
+            couch_stats_collector:get(bar)
+        end).
+
+should_track_process_count() ->
+    ?_assertMatch({_, 1}, spawn_and_count(1)).
+
+should_increment_counter_multiple_times_per_pid() ->
+    ?_assertMatch({_, 3}, spawn_and_count(3)).
+
+should_decrement_counter_on_process_exit() ->
+    ?_assertEqual(2,
+        begin
+            {Pid, 1} = spawn_and_count(1),
+            spawn_and_count(2),
+            RefMon = erlang:monitor(process, Pid),
+            Pid ! sepuku,
+            receive
+                {'DOWN', RefMon, _, _, _} -> ok
+            after ?TIMEOUT ->
+                throw(timeout)
+            end,
+            % sleep for awhile to let collector handle the updates
+            % suddenly, it couldn't notice process death instantly
+            timer:sleep(?TIMEWAIT),
+            couch_stats_collector:get(hoopla)
+        end).
+
+should_decrement_for_each_track_process_count_call_on_exit() ->
+    ?_assertEqual(2,
+        begin
+            {_, 2} = spawn_and_count(2),
+            {Pid, 6} = spawn_and_count(4),
+            RefMon = erlang:monitor(process, Pid),
+            Pid ! sepuku,
+            receive
+                {'DOWN', RefMon, _, _, _} -> ok
+            after ?TIMEOUT ->
+                throw(timeout)
+            end,
+            timer:sleep(?TIMEWAIT),
+            couch_stats_collector:get(hoopla)
+        end).
+
+should_return_all_counters_and_absolute_values() ->
+    ?_assertEqual([{bar,[1.0,0.0]}, {foo,1}],
+        begin
+            couch_stats_collector:record(bar, 0.0),
+            couch_stats_collector:record(bar, 1.0),
+            couch_stats_collector:increment(foo),
+            lists:sort(couch_stats_collector:all())
+        end).
+
+should_return_incremental_counters() ->
+    ?_assertEqual([{foo,1}],
+        begin
+            couch_stats_collector:record(bar, 0.0),
+            couch_stats_collector:record(bar, 1.0),
+            couch_stats_collector:increment(foo),
+            lists:sort(couch_stats_collector:all(incremental))
+        end).
+
+should_return_absolute_values() ->
+    ?_assertEqual([{bar,[1.0,0.0]}, {zing, "Z"}],
+        begin
+            couch_stats_collector:record(bar, 0.0),
+            couch_stats_collector:record(bar, 1.0),
+            couch_stats_collector:record(zing, 90),
+            couch_stats_collector:increment(foo),
+            lists:sort(couch_stats_collector:all(absolute))
+        end).
+
+should_init_empty_aggregate(absolute, _) ->
+    {Aggs} = couch_stats_aggregator:all(),
+    ?_assertEqual({[{'11', make_agg(<<"randomosity">>,
+                                    null, null, null, null, null)}]},
+                  couch_util:get_value(number, Aggs));
+should_init_empty_aggregate(counter, _) ->
+    {Aggs} = couch_stats_aggregator:all(),
+    ?_assertEqual({[{stuff, make_agg(<<"yay description">>,
+                                     null, null, null, null, null)}]},
+                  couch_util:get_value(testing, Aggs)).
+
+should_get_empty_aggregate(absolute, _) ->
+    ?_assertEqual(make_agg(<<"randomosity">>, null, null, null, null, null),
+             couch_stats_aggregator:get_json({number, '11'}));
+should_get_empty_aggregate(counter, _) ->
+    ?_assertEqual(make_agg(<<"yay description">>, null, null, null, null, null),
+             couch_stats_aggregator:get_json({testing, stuff})).
+
+should_change_stats_on_values_add(absolute, _) ->
+    lists:foreach(fun(X) ->
+        couch_stats_collector:record({number, 11}, X)
+    end, lists:seq(0, 10)),
+    couch_stats_aggregator:collect_sample(),
+    ?_assertEqual(make_agg(<<"randomosity">>, 5.0, 5.0, null, 5.0, 5.0),
+                  couch_stats_aggregator:get_json({number, 11}));
+should_change_stats_on_values_add(counter, _) ->
+    lists:foreach(fun(_) ->
+        couch_stats_collector:increment({testing, stuff})
+    end, lists:seq(1, 100)),
+    couch_stats_aggregator:collect_sample(),
+    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 100.0, null, 100, 100),
+                  couch_stats_aggregator:get_json({testing, stuff})).
+
+should_change_stats_for_all_times_on_values_add(absolute, _) ->
+    lists:foreach(fun(X) ->
+        couch_stats_collector:record({number, 11}, X)
+    end, lists:seq(0, 10)),
+    couch_stats_aggregator:collect_sample(),
+    ?_assertEqual(make_agg(<<"randomosity">>, 5.0, 5.0, null, 5.0, 5.0),
+                  couch_stats_aggregator:get_json({number, 11}, 1));
+should_change_stats_for_all_times_on_values_add(counter, _) ->
+    lists:foreach(fun(_) ->
+        couch_stats_collector:increment({testing, stuff})
+    end, lists:seq(1, 100)),
+    couch_stats_aggregator:collect_sample(),
+    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 100.0, null, 100, 100),
+                  couch_stats_aggregator:get_json({testing, stuff}, 1)).
+
+should_change_stats_on_values_change(absolute, _) ->
+    ?_assertEqual(make_agg(<<"randomosity">>, 20.0, 10.0, 7.071, 5.0, 15.0),
+        begin
+            lists:foreach(fun(X) ->
+                couch_stats_collector:record({number, 11}, X)
+            end, lists:seq(0, 10)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_collector:record({number, 11}, 15),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({number, 11})
+        end);
+should_change_stats_on_values_change(counter, _) ->
+    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 50.0, 70.711, 0, 100),
+        begin
+            lists:foreach(fun(_) ->
+                couch_stats_collector:increment({testing, stuff})
+            end, lists:seq(1, 100)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({testing, stuff})
+        end).
+
+should_change_stats_for_all_times_on_values_change(absolute, _) ->
+    ?_assertEqual(make_agg(<<"randomosity">>, 20.0, 10.0, 7.071, 5.0, 15.0),
+        begin
+            lists:foreach(fun(X) ->
+                couch_stats_collector:record({number, 11}, X)
+            end, lists:seq(0, 10)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_collector:record({number, 11}, 15),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({number, 11}, 1)
+        end);
+should_change_stats_for_all_times_on_values_change(counter, _) ->
+    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 50.0, 70.711, 0, 100),
+        begin
+            lists:foreach(fun(_) ->
+                couch_stats_collector:increment({testing, stuff})
+            end, lists:seq(1, 100)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({testing, stuff}, 1)
+        end).
+
+should_not_remove_data_after_some_time_for_0_sample(absolute, _) ->
+    ?_assertEqual(make_agg(<<"randomosity">>, 20.0, 10.0, 7.071, 5.0, 15.0),
+        begin
+            lists:foreach(fun(X) ->
+                couch_stats_collector:record({number, 11}, X)
+            end, lists:seq(0, 10)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_collector:record({number, 11}, 15),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({number, 11})
+        end);
+should_not_remove_data_after_some_time_for_0_sample(counter, _) ->
+    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 33.333, 57.735, 0, 100),
+        begin
+            lists:foreach(fun(_) ->
+                couch_stats_collector:increment({testing, stuff})
+            end, lists:seq(1, 100)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({testing, stuff})
+        end).
+
+should_remove_data_after_some_time_for_other_samples(absolute, _) ->
+    ?_assertEqual(make_agg(<<"randomosity">>, 15.0, 15.0, null, 15.0, 15.0),
+        begin
+            lists:foreach(fun(X) ->
+                couch_stats_collector:record({number, 11}, X)
+            end, lists:seq(0, 10)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_collector:record({number, 11}, 15),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({number, 11}, 1)
+        end);
+should_remove_data_after_some_time_for_other_samples(counter, _) ->
+    ?_assertEqual(make_agg(<<"yay description">>, 0, 0.0, 0.0, 0, 0),
+        begin
+            lists:foreach(fun(_) ->
+                couch_stats_collector:increment({testing, stuff})
+            end, lists:seq(1, 100)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({testing, stuff}, 1)
+        end).
+
+
+spawn_and_count(N) ->
+    Self = self(),
+    Pid = spawn(fun() ->
+        lists:foreach(
+            fun(_) ->
+                couch_stats_collector:track_process_count(hoopla)
+            end, lists:seq(1,N)),
+        Self ! reporting,
+        receive
+            sepuku -> ok
+        end
+    end),
+    receive reporting -> ok end,
+    {Pid, couch_stats_collector:get(hoopla)}.
+
+repeat(_, 0) ->
+    ok;
+repeat(Fun, Count) ->
+    Fun(),
+    repeat(Fun, Count-1).
+
+make_agg(Desc, Sum, Mean, StdDev, Min, Max) ->
+    {[
+        {description, Desc},
+        {current, Sum},
+        {sum, Sum},
+        {mean, Mean},
+        {stddev, StdDev},
+        {min, Min},
+        {max, Max}
+    ]}.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_stream_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_stream_tests.erl b/test/couch_stream_tests.erl
new file mode 100644
index 0000000..335a2fe
--- /dev/null
+++ b/test/couch_stream_tests.erl
@@ -0,0 +1,100 @@
+% 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(couch_stream_tests).
+
+-include("couch_eunit.hrl").
+
+
+setup() ->
+    {ok, Fd} = couch_file:open(?tempfile(), [create, overwrite]),
+    {ok, Stream} = couch_stream:open(Fd),
+    {Fd, Stream}.
+
+teardown({Fd, _}) ->
+    ok = couch_file:close(Fd).
+
+
+stream_test_() ->
+    {
+        "CouchDB stream tests",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_write/1,
+                fun should_write_consecutive/1,
+                fun should_write_empty_binary/1,
+                fun should_return_file_pointers_on_close/1,
+                fun should_return_stream_size_on_close/1,
+                fun should_return_valid_pointers/1,
+                fun should_recall_last_pointer_position/1,
+                fun should_stream_more_with_4K_chunk_size/1
+            ]
+        }
+    }.
+
+
+should_write({_, Stream}) ->
+    ?_assertEqual(ok, couch_stream:write(Stream, <<"food">>)).
+
+should_write_consecutive({_, Stream}) ->
+    couch_stream:write(Stream, <<"food">>),
+    ?_assertEqual(ok, couch_stream:write(Stream, <<"foob">>)).
+
+should_write_empty_binary({_, Stream}) ->
+    ?_assertEqual(ok, couch_stream:write(Stream, <<>>)).
+
+should_return_file_pointers_on_close({_, Stream}) ->
+    couch_stream:write(Stream, <<"foodfoob">>),
+    {Ptrs, _, _, _, _} = couch_stream:close(Stream),
+    ?_assertEqual([{0, 8}], Ptrs).
+
+should_return_stream_size_on_close({_, Stream}) ->
+    couch_stream:write(Stream, <<"foodfoob">>),
+    {_, Length, _, _, _} = couch_stream:close(Stream),
+    ?_assertEqual(8, Length).
+
+should_return_valid_pointers({Fd, Stream}) ->
+    couch_stream:write(Stream, <<"foodfoob">>),
+    {Ptrs, _, _, _, _} = couch_stream:close(Stream),
+    ?_assertEqual(<<"foodfoob">>, read_all(Fd, Ptrs)).
+
+should_recall_last_pointer_position({Fd, Stream}) ->
+    couch_stream:write(Stream, <<"foodfoob">>),
+    {_, _, _, _, _} = couch_stream:close(Stream),
+    {ok, ExpPtr} = couch_file:bytes(Fd),
+    {ok, Stream2} = couch_stream:open(Fd),
+    ZeroBits = <<0:(8 * 10)>>,
+    OneBits = <<1:(8 * 10)>>,
+    ok = couch_stream:write(Stream2, OneBits),
+    ok = couch_stream:write(Stream2, ZeroBits),
+    {Ptrs, 20, _, _, _} = couch_stream:close(Stream2),
+    [{ExpPtr, 20}] = Ptrs,
+    AllBits = iolist_to_binary([OneBits, ZeroBits]),
+    ?_assertEqual(AllBits, read_all(Fd, Ptrs)).
+
+should_stream_more_with_4K_chunk_size({Fd, _}) ->
+    {ok, Stream} = couch_stream:open(Fd, [{buffer_size, 4096}]),
+    lists:foldl(
+        fun(_, Acc) ->
+            Data = <<"a1b2c">>,
+            couch_stream:write(Stream, Data),
+            [Data | Acc]
+        end, [], lists:seq(1, 1024)),
+    ?_assertMatch({[{0, 4100}, {4106, 1020}], 5120, _, _, _},
+                  couch_stream:close(Stream)).
+
+
+read_all(Fd, PosList) ->
+    Data = couch_stream:foldl(Fd, PosList, fun(Bin, Acc) -> [Bin, Acc] end, []),
+    iolist_to_binary(Data).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_task_status_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_task_status_tests.erl b/test/couch_task_status_tests.erl
new file mode 100644
index 0000000..f71ad2b
--- /dev/null
+++ b/test/couch_task_status_tests.erl
@@ -0,0 +1,225 @@
+% 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(couch_task_status_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(TIMEOUT, 1000).
+
+
+setup() ->
+    {ok, TaskStatusPid} = couch_task_status:start_link(),
+    TaskUpdaterPid = spawn(fun() -> loop() end),
+    {TaskStatusPid, TaskUpdaterPid}.
+
+teardown({TaskStatusPid, _}) ->
+    erlang:monitor(process, TaskStatusPid),
+    couch_task_status:stop(),
+    receive
+        {'DOWN', _, _, TaskStatusPid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw(timeout_error)
+    end.
+
+
+couch_task_status_test_() ->
+    {
+        "CouchDB task status updates",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_register_task/1,
+                fun should_set_task_startup_time/1,
+                fun should_have_update_time_as_startup_before_any_progress/1,
+                fun should_set_task_type/1,
+                fun should_not_register_multiple_tasks_for_same_pid/1,
+                fun should_set_task_progress/1,
+                fun should_update_task_progress/1,
+                fun should_update_time_changes_on_task_progress/1,
+                fun should_control_update_frequency/1,
+                fun should_reset_control_update_frequency/1,
+                fun should_track_multiple_tasks/1,
+                fun should_finish_task/1
+
+            ]
+        }
+    }.
+
+
+should_register_task({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    ?_assertEqual(1, length(couch_task_status:all())).
+
+should_set_task_startup_time({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    ?_assert(is_integer(get_task_prop(Pid, started_on))).
+
+should_have_update_time_as_startup_before_any_progress({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    StartTime = get_task_prop(Pid, started_on),
+    ?_assertEqual(StartTime, get_task_prop(Pid, updated_on)).
+
+should_set_task_type({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    ?_assertEqual(replication, get_task_prop(Pid, type)).
+
+should_not_register_multiple_tasks_for_same_pid({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    ?_assertEqual({add_task_error, already_registered},
+                  call(Pid, add, [{type, compaction}, {progress, 0}])).
+
+should_set_task_progress({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    ?_assertEqual(0, get_task_prop(Pid, progress)).
+
+should_update_task_progress({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    call(Pid, update, [{progress, 25}]),
+    ?_assertEqual(25, get_task_prop(Pid, progress)).
+
+should_update_time_changes_on_task_progress({_, Pid}) ->
+    ?_assert(
+        begin
+            ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+            ok = timer:sleep(1000),  % sleep awhile to customize update time
+            call(Pid, update, [{progress, 25}]),
+            get_task_prop(Pid, updated_on) > get_task_prop(Pid, started_on)
+        end).
+
+should_control_update_frequency({_, Pid}) ->
+    ?_assertEqual(66,
+        begin
+            ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+            call(Pid, update, [{progress, 50}]),
+            call(Pid, update_frequency, 500),
+            call(Pid, update, [{progress, 66}]),
+            call(Pid, update, [{progress, 77}]),
+            get_task_prop(Pid, progress)
+        end).
+
+should_reset_control_update_frequency({_, Pid}) ->
+    ?_assertEqual(87,
+        begin
+            ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+            call(Pid, update, [{progress, 50}]),
+            call(Pid, update_frequency, 500),
+            call(Pid, update, [{progress, 66}]),
+            call(Pid, update, [{progress, 77}]),
+            call(Pid, update_frequency, 0),
+            call(Pid, update, [{progress, 87}]),
+            get_task_prop(Pid, progress)
+        end).
+
+should_track_multiple_tasks(_) ->
+    ?_assert(run_multiple_tasks()).
+
+should_finish_task({_, Pid}) ->
+    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
+    ?assertEqual(1, length(couch_task_status:all())),
+    ok = call(Pid, done),
+    ?_assertEqual(0, length(couch_task_status:all())).
+
+
+run_multiple_tasks() ->
+    Pid1 = spawn(fun() -> loop() end),
+    Pid2 = spawn(fun() -> loop() end),
+    Pid3 = spawn(fun() -> loop() end),
+    call(Pid1, add, [{type, replication}, {progress, 0}]),
+    call(Pid2, add, [{type, compaction}, {progress, 0}]),
+    call(Pid3, add, [{type, indexer}, {progress, 0}]),
+
+    ?assertEqual(3, length(couch_task_status:all())),
+    ?assertEqual(replication, get_task_prop(Pid1, type)),
+    ?assertEqual(compaction, get_task_prop(Pid2, type)),
+    ?assertEqual(indexer, get_task_prop(Pid3, type)),
+
+    call(Pid2, update, [{progress, 33}]),
+    call(Pid3, update, [{progress, 42}]),
+    call(Pid1, update, [{progress, 11}]),
+    ?assertEqual(42, get_task_prop(Pid3, progress)),
+    call(Pid1, update, [{progress, 72}]),
+    ?assertEqual(72, get_task_prop(Pid1, progress)),
+    ?assertEqual(33, get_task_prop(Pid2, progress)),
+
+    call(Pid1, done),
+    ?assertEqual(2, length(couch_task_status:all())),
+    call(Pid3, done),
+    ?assertEqual(1, length(couch_task_status:all())),
+    call(Pid2, done),
+    ?assertEqual(0, length(couch_task_status:all())),
+
+    true.
+
+
+loop() ->
+    receive
+        {add, Props, From} ->
+            Resp = couch_task_status:add_task(Props),
+            From ! {ok, self(), Resp},
+            loop();
+        {update, Props, From} ->
+            Resp = couch_task_status:update(Props),
+            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 ?TIMEOUT ->
+        throw(timeout_error)
+    end.
+
+get_task_prop(Pid, Prop) ->
+    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];
+                _ ->
+                    Acc
+            end
+        end,
+        [], couch_task_status:all()
+    ),
+    case couch_util:get_value(Prop, hd(Element), nil) of
+        nil ->
+            erlang:error({assertion_failed,
+                         [{module, ?MODULE},
+                          {line, ?LINE},
+                          {reason, "Could not get property '"
+                                   ++ couch_util:to_list(Prop)
+                                   ++ "' for task "
+                                   ++ pid_to_list(Pid)}]});
+        Value ->
+            Value
+    end.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_util_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_util_tests.erl b/test/couch_util_tests.erl
new file mode 100644
index 0000000..8e24e72
--- /dev/null
+++ b/test/couch_util_tests.erl
@@ -0,0 +1,136 @@
+% 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(couch_util_tests).
+
+-include("couch_eunit.hrl").
+
+
+setup() ->
+    %% We cannot start driver from here since it becomes bounded to eunit
+    %% master process and the next couch_server_sup:start_link call will
+    %% fail because server couldn't load driver since it already is.
+    %%
+    %% On other hand, we cannot unload driver here due to
+    %% {error, not_loaded_by_this_process} while it is. Any ideas is welcome.
+    %%
+    couch_server_sup:start_link(?CONFIG_CHAIN),
+    %% couch_config:start_link(?CONFIG_CHAIN),
+    %% {ok, _} = couch_drv:start_link(),
+    ok.
+
+teardown(_) ->
+    couch_server_sup:stop(),
+    %% couch_config:stop(),
+    %% erl_ddll:unload_driver(couch_icu_driver),
+    ok.
+
+
+collation_test_() ->
+    {
+        "Collation tests",
+        [
+            {
+                setup,
+                fun setup/0, fun teardown/1,
+                [
+                    should_collate_ascii(),
+                    should_collate_non_ascii()
+                ]
+            }
+        ]
+    }.
+
+should_collate_ascii() ->
+    ?_assertEqual(1, couch_util:collate(<<"foo">>, <<"bar">>)).
+
+should_collate_non_ascii() ->
+    ?_assertEqual(-1, couch_util:collate(<<"A">>, <<"aa">>)).
+
+to_existed_atom_test() ->
+    ?assert(couch_util:to_existing_atom(true)),
+    ?assertMatch(foo, couch_util:to_existing_atom(<<"foo">>)),
+    ?assertMatch(foobarbaz, couch_util:to_existing_atom("foobarbaz")).
+
+implode_test() ->
+    ?assertEqual([1, 38, 2, 38, 3], couch_util:implode([1, 2, 3], "&")).
+
+trim_test() ->
+    lists:map(fun(S) -> ?assertEqual("foo", couch_util:trim(S)) end,
+              [" foo", "foo ", "\tfoo", " foo ", "foo\t", "foo\n", "\nfoo"]).
+
+abs_pathname_test() ->
+    {ok, Cwd} = file:get_cwd(),
+    ?assertEqual(Cwd ++ "/foo", couch_util:abs_pathname("./foo")).
+
+flush_test() ->
+    ?assertNot(couch_util:should_flush()),
+    AcquireMem = fun() ->
+        _IntsToAGazillion = lists:seq(1, 200000),
+        _LotsOfData = lists:map(fun(_) -> <<"foobar">> end,
+                                lists:seq(1, 500000)),
+        _BigBin = list_to_binary(_LotsOfData),
+
+        %% Allocation 200K tuples puts us above the memory threshold
+        %% Originally, there should be:
+        %%      ?assertNot(should_flush())
+        %% however, unlike for etap test, GC collects all allocated bits
+        %% making this conditions fail. So we have to invert the condition
+        %% since GC works, cleans the memory and everything is fine.
+        ?assertNot(couch_util:should_flush())
+    end,
+    AcquireMem(),
+
+    %% Checking to flush invokes GC
+    ?assertNot(couch_util:should_flush()).
+
+verify_test() ->
+    ?assert(couch_util:verify("It4Vooya", "It4Vooya")),
+    ?assertNot(couch_util:verify("It4VooyaX", "It4Vooya")),
+    ?assert(couch_util:verify(<<"ahBase3r">>, <<"ahBase3r">>)),
+    ?assertNot(couch_util:verify(<<"ahBase3rX">>, <<"ahBase3r">>)),
+    ?assertNot(couch_util:verify(nil, <<"ahBase3r">>)).
+
+find_in_binary_test_() ->
+    Cases = [
+        {<<"foo">>, <<"foobar">>, {exact, 0}},
+        {<<"foo">>, <<"foofoo">>, {exact, 0}},
+        {<<"foo">>, <<"barfoo">>, {exact, 3}},
+        {<<"foo">>, <<"barfo">>, {partial, 3}},
+        {<<"f">>, <<"fobarfff">>, {exact, 0}},
+        {<<"f">>, <<"obarfff">>, {exact, 4}},
+        {<<"f">>, <<"obarggf">>, {exact, 6}},
+        {<<"f">>, <<"f">>, {exact, 0}},
+        {<<"f">>, <<"g">>, not_found},
+        {<<"foo">>, <<"f">>, {partial, 0}},
+        {<<"foo">>, <<"g">>, not_found},
+        {<<"foo">>, <<"">>, not_found},
+        {<<"fofo">>, <<"foofo">>, {partial, 3}},
+        {<<"foo">>, <<"gfobarfo">>, {partial, 6}},
+        {<<"foo">>, <<"gfobarf">>, {partial, 6}},
+        {<<"foo">>, <<"gfobar">>, not_found},
+        {<<"fog">>, <<"gbarfogquiz">>, {exact, 4}},
+        {<<"ggg">>, <<"ggg">>, {exact, 0}},
+        {<<"ggg">>, <<"ggggg">>, {exact, 0}},
+        {<<"ggg">>, <<"bggg">>, {exact, 1}},
+        {<<"ggg">>, <<"bbgg">>, {partial, 2}},
+        {<<"ggg">>, <<"bbbg">>, {partial, 3}},
+        {<<"ggg">>, <<"bgbggbggg">>, {exact, 6}},
+        {<<"ggg">>, <<"bgbggb">>, not_found}
+    ],
+    lists:map(
+        fun({Needle, Haystack, Result}) ->
+            Msg = lists:flatten(io_lib:format("Looking for ~s in ~s",
+                                              [Needle, Haystack])),
+            {Msg, ?_assertMatch(Result,
+                                couch_util:find_in_binary(Needle, Haystack))}
+        end, Cases).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_uuids_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_uuids_tests.erl b/test/couch_uuids_tests.erl
new file mode 100644
index 0000000..ea1d034
--- /dev/null
+++ b/test/couch_uuids_tests.erl
@@ -0,0 +1,161 @@
+% 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(couch_uuids_tests).
+
+-include("couch_eunit.hrl").
+
+-define(TIMEOUT_S, 20).
+
+
+setup() ->
+    {ok, Pid} = couch_config:start_link(?CONFIG_CHAIN),
+    erlang:monitor(process, Pid),
+    couch_uuids:start(),
+    Pid.
+
+setup(Opts) ->
+    Pid = setup(),
+    lists:foreach(
+        fun({Option, Value}) ->
+            couch_config:set("uuids", Option, Value, false)
+        end, Opts),
+    Pid.
+
+teardown(Pid) ->
+    couch_uuids:stop(),
+    couch_config:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} -> ok
+    after
+        1000 -> throw({timeout_error, config_stop})
+    end.
+
+teardown(_, Pid) ->
+    teardown(Pid).
+
+
+default_test_() ->
+    {
+        "Default UUID algorithm",
+        {
+            setup,
+            fun setup/0, fun teardown/1,
+            fun should_be_unique/1
+        }
+    }.
+
+sequential_test_() ->
+    Opts = [{"algorithm", "sequential"}],
+    Cases = [
+        fun should_be_unique/2,
+        fun should_increment_monotonically/2,
+        fun should_rollover/2
+    ],
+    {
+        "UUID algorithm: sequential",
+        {
+            foreachx,
+            fun setup/1, fun teardown/2,
+            [{Opts, Fun} || Fun <- Cases]
+        }
+    }.
+
+utc_test_() ->
+    Opts = [{"algorithm", "utc_random"}],
+    Cases = [
+        fun should_be_unique/2,
+        fun should_increment_monotonically/2
+    ],
+    {
+        "UUID algorithm: utc_random",
+        {
+            foreachx,
+            fun setup/1, fun teardown/2,
+            [{Opts, Fun} || Fun <- Cases]
+        }
+    }.
+
+utc_id_suffix_test_() ->
+    Opts = [{"algorithm", "utc_id"}, {"utc_id_suffix", "bozo"}],
+    Cases = [
+        fun should_be_unique/2,
+        fun should_increment_monotonically/2,
+        fun should_preserve_suffix/2
+    ],
+    {
+        "UUID algorithm: utc_id",
+        {
+            foreachx,
+            fun setup/1, fun teardown/2,
+            [{Opts, Fun} || Fun <- Cases]
+        }
+    }.
+
+
+should_be_unique() ->
+    %% this one may really runs for too long on slow hosts
+    {timeout, ?TIMEOUT_S, ?_assert(test_unique(10000, [couch_uuids:new()]))}.
+should_be_unique(_) ->
+    should_be_unique().
+should_be_unique(_, _) ->
+    should_be_unique().
+
+should_increment_monotonically(_, _) ->
+    ?_assert(couch_uuids:new() < couch_uuids:new()).
+
+should_rollover(_, _) ->
+    ?_test(begin
+        UUID = binary_to_list(couch_uuids:new()),
+        Prefix = element(1, lists:split(26, UUID)),
+        N = gen_until_pref_change(Prefix, 0),
+        ?assert(N >= 5000 andalso N =< 11000)
+    end).
+
+should_preserve_suffix(_, _) ->
+    ?_test(begin
+        UUID = binary_to_list(couch_uuids:new()),
+        Suffix = get_suffix(UUID),
+        ?assert(test_same_suffix(10000, Suffix))
+    end).
+
+
+test_unique(0, _) ->
+    true;
+test_unique(N, UUIDs) ->
+    UUID = couch_uuids:new(),
+    ?assertNot(lists:member(UUID, UUIDs)),
+    test_unique(N - 1, [UUID| UUIDs]).
+
+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.
+
+get_suffix(UUID) when is_binary(UUID) ->
+    get_suffix(binary_to_list(UUID));
+get_suffix(UUID) ->
+    element(2, lists:split(14, UUID)).
+
+test_same_suffix(0, _) ->
+    true;
+test_same_suffix(N, Suffix) ->
+    case get_suffix(couch_uuids:new()) of
+        Suffix -> test_same_suffix(N - 1, Suffix);
+        _ -> false
+    end.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_work_queue_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_work_queue_tests.erl b/test/couch_work_queue_tests.erl
new file mode 100644
index 0000000..8a463b5
--- /dev/null
+++ b/test/couch_work_queue_tests.erl
@@ -0,0 +1,393 @@
+% 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(couch_work_queue_tests).
+
+-include("couch_eunit.hrl").
+
+-define(TIMEOUT, 100).
+
+
+setup(Opts) ->
+    {ok, Q} = couch_work_queue:new(Opts),
+    Producer = spawn_producer(Q),
+    Consumer = spawn_consumer(Q),
+    {Q, Producer, Consumer}.
+
+setup_max_items() ->
+    setup([{max_items, 3}]).
+
+setup_max_size() ->
+    setup([{max_size, 160}]).
+
+setup_max_items_and_size() ->
+    setup([{max_size, 160}, {max_items, 3}]).
+
+setup_multi_workers() ->
+    {Q, Producer, Consumer1} = setup([{max_size, 160},
+                                      {max_items, 3},
+                                      {multi_workers, true}]),
+    Consumer2 = spawn_consumer(Q),
+    Consumer3 = spawn_consumer(Q),
+    {Q, Producer, [Consumer1, Consumer2, Consumer3]}.
+
+teardown({Q, Producer, Consumers}) when is_list(Consumers) ->
+    % consume all to unblock and let producer/consumer stop without timeout
+    [consume(Consumer, all) || Consumer <- Consumers],
+
+    ok = close_queue(Q),
+    ok = stop(Producer, "producer"),
+    R = [stop(Consumer, "consumer") || Consumer <- Consumers],
+    R = [ok || _ <- Consumers],
+    ok;
+teardown({Q, Producer, Consumer}) ->
+    teardown({Q, Producer, [Consumer]}).
+
+
+single_consumer_test_() ->
+    {
+        "Single producer and consumer",
+        [
+            {
+                "Queue with 3 max items",
+                {
+                    foreach,
+                    fun setup_max_items/0, fun teardown/1,
+                    single_consumer_max_item_count() ++ common_cases()
+                }
+            },
+            {
+                "Queue with max size of 160 bytes",
+                {
+                    foreach,
+                    fun setup_max_size/0, fun teardown/1,
+                    single_consumer_max_size() ++ common_cases()
+                }
+            },
+            {
+                "Queue with max size of 160 bytes and 3 max items",
+                {
+                    foreach,
+                    fun setup_max_items_and_size/0, fun teardown/1,
+                    single_consumer_max_items_and_size() ++ common_cases()
+                }
+            }
+        ]
+    }.
+
+multiple_consumers_test_() ->
+    {
+        "Single producer and multiple consumers",
+        [
+            {
+                "Queue with max size of 160 bytes and 3 max items",
+                {
+                    foreach,
+                    fun setup_multi_workers/0, fun teardown/1,
+                    common_cases() ++ multiple_consumers()
+                }
+
+            }
+        ]
+    }.
+
+common_cases()->
+    [
+        fun should_block_consumer_on_dequeue_from_empty_queue/1,
+        fun should_consume_right_item/1,
+        fun should_timeout_on_close_non_empty_queue/1,
+        fun should_not_block_producer_for_non_empty_queue_after_close/1,
+        fun should_be_closed/1
+    ].
+
+single_consumer_max_item_count()->
+    [
+        fun should_have_no_items_for_new_queue/1,
+        fun should_block_producer_on_full_queue_count/1,
+        fun should_receive_first_queued_item/1,
+        fun should_consume_multiple_items/1,
+        fun should_consume_all/1
+    ].
+
+single_consumer_max_size()->
+    [
+        fun should_have_zero_size_for_new_queue/1,
+        fun should_block_producer_on_full_queue_size/1,
+        fun should_increase_queue_size_on_produce/1,
+        fun should_receive_first_queued_item/1,
+        fun should_consume_multiple_items/1,
+        fun should_consume_all/1
+    ].
+
+single_consumer_max_items_and_size() ->
+    single_consumer_max_item_count() ++ single_consumer_max_size().
+
+multiple_consumers() ->
+    [
+        fun should_have_zero_size_for_new_queue/1,
+        fun should_have_no_items_for_new_queue/1,
+        fun should_increase_queue_size_on_produce/1
+    ].
+
+
+should_have_no_items_for_new_queue({Q, _, _}) ->
+    ?_assertEqual(0, couch_work_queue:item_count(Q)).
+
+should_have_zero_size_for_new_queue({Q, _, _}) ->
+    ?_assertEqual(0, couch_work_queue:size(Q)).
+
+should_block_consumer_on_dequeue_from_empty_queue({_, _, Consumers}) when is_list(Consumers) ->
+    [consume(C, 2) || C <- Consumers],
+    Pongs = [ping(C) || C <- Consumers],
+    ?_assertEqual([timeout, timeout, timeout], Pongs);
+should_block_consumer_on_dequeue_from_empty_queue({_, _, Consumer}) ->
+    consume(Consumer, 1),
+    Pong = ping(Consumer),
+    ?_assertEqual(timeout, Pong).
+
+should_consume_right_item({Q, Producer, Consumers}) when is_list(Consumers) ->
+    [consume(C, 3) || C <- Consumers],
+
+    Item1 = produce(Producer, 10),
+    ok = ping(Producer),
+    ?assertEqual(0, couch_work_queue:item_count(Q)),
+    ?assertEqual(0, couch_work_queue:size(Q)),
+
+    Item2 = produce(Producer, 10),
+    ok = ping(Producer),
+    ?assertEqual(0, couch_work_queue:item_count(Q)),
+    ?assertEqual(0, couch_work_queue:size(Q)),
+
+    Item3 = produce(Producer, 10),
+    ok = ping(Producer),
+    ?assertEqual(0, couch_work_queue:item_count(Q)),
+    ?assertEqual(0, couch_work_queue:size(Q)),
+
+    R = [{ping(C), Item}
+         || {C, Item} <- lists:zip(Consumers, [Item1, Item2, Item3])],
+
+    ?_assertEqual([{ok, Item1}, {ok, Item2}, {ok, Item3}], R);
+should_consume_right_item({_, Producer, Consumer}) ->
+    consume(Consumer, 1),
+    Item = produce(Producer, 10),
+    produce(Producer, 20),
+    ok = ping(Producer),
+    ok = ping(Consumer),
+    {ok, Items} = last_consumer_items(Consumer),
+    ?_assertEqual([Item], Items).
+
+should_increase_queue_size_on_produce({Q, Producer, _}) ->
+    produce(Producer, 50),
+    ok = ping(Producer),
+    Count1 = couch_work_queue:item_count(Q),
+    Size1 = couch_work_queue:size(Q),
+
+    produce(Producer, 10),
+    Count2 = couch_work_queue:item_count(Q),
+    Size2 = couch_work_queue:size(Q),
+
+    ?_assertEqual([{Count1, Size1}, {Count2, Size2}], [{1, 50}, {2, 60}]).
+
+should_block_producer_on_full_queue_count({Q, Producer, _}) ->
+    produce(Producer, 10),
+    ?assertEqual(1, couch_work_queue:item_count(Q)),
+    ok = ping(Producer),
+
+    produce(Producer, 15),
+    ?assertEqual(2, couch_work_queue:item_count(Q)),
+    ok = ping(Producer),
+
+    produce(Producer, 20),
+    ?assertEqual(3, couch_work_queue:item_count(Q)),
+    Pong = ping(Producer),
+
+    ?_assertEqual(timeout, Pong).
+
+should_block_producer_on_full_queue_size({Q, Producer, _}) ->
+    produce(Producer, 100),
+    ok = ping(Producer),
+    ?assertEqual(1, couch_work_queue:item_count(Q)),
+    ?assertEqual(100, couch_work_queue:size(Q)),
+
+    produce(Producer, 110),
+    Pong = ping(Producer),
+    ?assertEqual(2, couch_work_queue:item_count(Q)),
+    ?assertEqual(210, couch_work_queue:size(Q)),
+
+    ?_assertEqual(timeout, Pong).
+
+should_consume_multiple_items({_, Producer, Consumer}) ->
+    Item1 = produce(Producer, 10),
+    ok = ping(Producer),
+
+    Item2 = produce(Producer, 15),
+    ok = ping(Producer),
+
+    consume(Consumer, 2),
+
+    {ok, Items} = last_consumer_items(Consumer),
+    ?_assertEqual([Item1, Item2], Items).
+
+should_receive_first_queued_item({Q, Producer, Consumer}) ->
+    consume(Consumer, 100),
+    timeout = ping(Consumer),
+
+    Item = produce(Producer, 11),
+    ok = ping(Producer),
+
+    ok = ping(Consumer),
+    ?assertEqual(0, couch_work_queue:item_count(Q)),
+
+    {ok, Items} = last_consumer_items(Consumer),
+    ?_assertEqual([Item], Items).
+
+should_consume_all({_, Producer, Consumer}) ->
+    Item1 = produce(Producer, 10),
+    Item2 = produce(Producer, 15),
+    Item3 = produce(Producer, 20),
+
+    consume(Consumer, all),
+
+    {ok, Items} = last_consumer_items(Consumer),
+    ?_assertEqual([Item1, Item2, Item3], Items).
+
+should_timeout_on_close_non_empty_queue({Q, Producer, _}) ->
+    produce(Producer, 1),
+    Status = close_queue(Q),
+
+    ?_assertEqual(timeout, Status).
+
+should_not_block_producer_for_non_empty_queue_after_close({Q, Producer, _}) ->
+    produce(Producer, 1),
+    close_queue(Q),
+    Pong = ping(Producer),
+    Size = couch_work_queue:size(Q),
+    Count = couch_work_queue:item_count(Q),
+
+    ?_assertEqual({ok, 1, 1}, {Pong, Size, Count}).
+
+should_be_closed({Q, _, Consumers}) when is_list(Consumers) ->
+    ok = close_queue(Q),
+
+    [consume(C, 1) || C <- Consumers],
+
+    LastConsumerItems = [last_consumer_items(C) || C <- Consumers],
+    ItemsCount = couch_work_queue:item_count(Q),
+    Size = couch_work_queue:size(Q),
+
+    ?_assertEqual({[closed, closed, closed], closed, closed},
+                  {LastConsumerItems, ItemsCount, Size});
+should_be_closed({Q, _, Consumer}) ->
+    ok = close_queue(Q),
+
+    consume(Consumer, 1),
+
+    LastConsumerItems = last_consumer_items(Consumer),
+    ItemsCount = couch_work_queue:item_count(Q),
+    Size = couch_work_queue:size(Q),
+
+    ?_assertEqual({closed, closed, closed},
+                  {LastConsumerItems, ItemsCount, Size}).
+
+
+close_queue(Q) ->
+    ok = couch_work_queue:close(Q),
+    MonRef = erlang:monitor(process, Q),
+    receive
+        {'DOWN', MonRef, process, Q, _Reason} -> ok
+    after ?TIMEOUT ->
+        erlang:demonitor(MonRef),
+        timeout
+    end.
+
+spawn_consumer(Q) ->
+    Parent = self(),
+    spawn(fun() -> consumer_loop(Parent, Q, nil) end).
+
+consumer_loop(Parent, Q, PrevItem) ->
+    receive
+        {stop, Ref} ->
+            Parent ! {ok, Ref};
+        {ping, Ref} ->
+            Parent ! {pong, Ref},
+            consumer_loop(Parent, Q, PrevItem);
+        {last_item, Ref} ->
+            Parent ! {item, Ref, PrevItem},
+            consumer_loop(Parent, Q, PrevItem);
+        {consume, N} ->
+            Result = couch_work_queue:dequeue(Q, N),
+            consumer_loop(Parent, Q, Result)
+    end.
+
+spawn_producer(Q) ->
+    Parent = self(),
+    spawn(fun() -> producer_loop(Parent, Q) end).
+
+producer_loop(Parent, Q) ->
+    receive
+        {stop, Ref} ->
+            Parent ! {ok, Ref};
+        {ping, Ref} ->
+            Parent ! {pong, Ref},
+            producer_loop(Parent, Q);
+        {produce, Ref, Size} ->
+            Item = crypto:rand_bytes(Size),
+            Parent ! {item, Ref, Item},
+            ok = couch_work_queue:queue(Q, Item),
+            producer_loop(Parent, Q)
+    end.
+
+consume(Consumer, N) ->
+    Consumer ! {consume, N}.
+
+last_consumer_items(Consumer) ->
+    Ref = make_ref(),
+    Consumer ! {last_item, Ref},
+    receive
+        {item, Ref, Items} ->
+            Items
+    after ?TIMEOUT ->
+        timeout
+    end.
+
+produce(Producer, Size) ->
+    Ref = make_ref(),
+    Producer ! {produce, Ref, Size},
+    receive
+        {item, Ref, Item} ->
+            Item
+    after ?TIMEOUT ->
+        erlang:error({assertion_failed,
+                      [{module, ?MODULE},
+                       {line, ?LINE},
+                       {reason, "Timeout asking producer to produce an item"}]})
+    end.
+
+ping(Pid) ->
+    Ref = make_ref(),
+    Pid ! {ping, Ref},
+    receive
+        {pong, Ref} ->
+            ok
+    after ?TIMEOUT ->
+        timeout
+    end.
+
+stop(Pid, Name) ->
+    Ref = make_ref(),
+    Pid ! {stop, Ref},
+    receive
+        {ok, Ref} -> ok
+    after ?TIMEOUT ->
+        ?debugMsg("Timeout stopping " ++ Name),
+        timeout
+    end.


[47/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
WIP: Disable problematic tests


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/6179af60
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/6179af60
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/6179af60

Branch: refs/heads/1963-eunit-bigcouch
Commit: 6179af603cd830e7bad87fd0d1d99108f8e54df8
Parents: fbad3c9
Author: Russell Branca <ch...@apache.org>
Authored: Fri Aug 15 13:02:23 2014 -0700
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:24:06 2014 -0700

----------------------------------------------------------------------
 test/couch_auth_cache_tests.erl    |  420 +++++-----
 test/couch_changes_tests.erl       | 1149 ++++++++++++++--------------
 test/couch_stats_tests.erl         |  774 +++++++++----------
 test/couch_uuids_tests.erl         |  285 +++----
 test/couchdb_attachments_tests.erl | 1200 ++++++++++++++---------------
 test/couchdb_compaction_daemon.erl |  396 +++++-----
 test/couchdb_os_daemons_tests.erl  |  380 +++++-----
 test/couchdb_os_proc_pool.erl      |  298 ++++----
 test/couchdb_vhosts_tests.erl      |  810 ++++++++++----------
 test/couchdb_views_tests.erl       | 1264 +++++++++++++++----------------
 10 files changed, 3501 insertions(+), 3475 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/6179af60/test/couch_auth_cache_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_auth_cache_tests.erl b/test/couch_auth_cache_tests.erl
index 83531ff..33e11bd 100644
--- a/test/couch_auth_cache_tests.erl
+++ b/test/couch_auth_cache_tests.erl
@@ -20,205 +20,221 @@
 -define(TIMEOUT, 1000).
 
 
-setup() ->
-    DbName = ?tempdb(),
-    config:set("couch_httpd_auth", "authentication_db",
-                     ?b2l(DbName), false),
-    DbName.
-
-teardown(DbName) ->
-    ok = couch_server:delete(DbName, [?ADMIN_USER]),
-    ok.
-
-
-couch_auth_cache_test_() ->
-    {
-        "CouchDB auth cache tests",
-        {
-            setup,
-            fun test_util:start_couch/0, fun test_util:stop_couch/1,
-            {
-                foreach,
-                fun setup/0, fun teardown/1,
-                [
-                    fun should_get_nil_on_missed_cache/1,
-                    fun should_get_right_password_hash/1,
-                    fun should_ensure_doc_hash_equals_cached_one/1,
-                    fun should_update_password/1,
-                    fun should_cleanup_cache_after_userdoc_deletion/1,
-                    fun should_restore_cache_after_userdoc_recreation/1,
-                    fun should_drop_cache_on_auth_db_change/1,
-                    fun should_restore_cache_on_auth_db_change/1,
-                    fun should_recover_cache_after_shutdown/1
-                ]
-            }
-        }
-    }.
-
-
-should_get_nil_on_missed_cache(_) ->
-    ?_assertEqual(nil, couch_auth_cache:get_user_creds("joe")).
-
-should_get_right_password_hash(DbName) ->
-    ?_test(begin
-        PasswordHash = hash_password("pass1"),
-        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
-        Creds = couch_auth_cache:get_user_creds("joe"),
-        ?assertEqual(PasswordHash,
-                      couch_util:get_value(<<"password_sha">>, Creds))
-    end).
-
-should_ensure_doc_hash_equals_cached_one(DbName) ->
-    ?_test(begin
-        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
-        Creds = couch_auth_cache:get_user_creds("joe"),
-
-        CachedHash = couch_util:get_value(<<"password_sha">>, Creds),
-        StoredHash = get_user_doc_password_sha(DbName, "joe"),
-        ?assertEqual(StoredHash, CachedHash)
-    end).
-
-should_update_password(DbName) ->
-    ?_test(begin
-        PasswordHash = hash_password("pass2"),
-        {ok, Rev} = update_user_doc(DbName, "joe", "pass1"),
-        {ok, _} = update_user_doc(DbName, "joe", "pass2", Rev),
-        Creds = couch_auth_cache:get_user_creds("joe"),
-        ?assertEqual(PasswordHash,
-                      couch_util:get_value(<<"password_sha">>, Creds))
-    end).
-
-should_cleanup_cache_after_userdoc_deletion(DbName) ->
-    ?_test(begin
-        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
-        delete_user_doc(DbName, "joe"),
-        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe"))
-    end).
-
-should_restore_cache_after_userdoc_recreation(DbName) ->
-    ?_test(begin
-        PasswordHash = hash_password("pass5"),
-        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
-        delete_user_doc(DbName, "joe"),
-        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe")),
-
-        {ok, _} = update_user_doc(DbName, "joe", "pass5"),
-        Creds = couch_auth_cache:get_user_creds("joe"),
-
-        ?assertEqual(PasswordHash,
-                      couch_util:get_value(<<"password_sha">>, Creds))
-    end).
-
-should_drop_cache_on_auth_db_change(DbName) ->
-    ?_test(begin
-        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
-        full_commit(DbName),
-        config:set("couch_httpd_auth", "authentication_db",
-                         ?b2l(?tempdb()), false),
-        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe"))
-    end).
-
-should_restore_cache_on_auth_db_change(DbName) ->
-    ?_test(begin
-        PasswordHash = hash_password("pass1"),
-        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
-        Creds = couch_auth_cache:get_user_creds("joe"),
-        full_commit(DbName),
-
-        DbName1 = ?tempdb(),
-        config:set("couch_httpd_auth", "authentication_db",
-                         ?b2l(DbName1), false),
-
-        {ok, _} = update_user_doc(DbName1, "joe", "pass5"),
-        full_commit(DbName1),
-
-        config:set("couch_httpd_auth", "authentication_db",
-                         ?b2l(DbName), false),
-
-        Creds = couch_auth_cache:get_user_creds("joe"),
-        ?assertEqual(PasswordHash,
-                      couch_util:get_value(<<"password_sha">>, Creds))
-    end).
-
-should_recover_cache_after_shutdown(DbName) ->
-    ?_test(begin
-        PasswordHash = hash_password("pass2"),
-        {ok, Rev0} = update_user_doc(DbName, "joe", "pass1"),
-        {ok, Rev1} = update_user_doc(DbName, "joe", "pass2", Rev0),
-        full_commit(DbName),
-        shutdown_db(DbName),
-        {ok, Rev1} = get_doc_rev(DbName, "joe"),
-        ?assertEqual(PasswordHash, get_user_doc_password_sha(DbName, "joe"))
-    end).
-
-
-update_user_doc(DbName, UserName, Password) ->
-    update_user_doc(DbName, UserName, Password, nil).
-
-update_user_doc(DbName, UserName, Password, Rev) ->
-    User = iolist_to_binary(UserName),
-    Doc = couch_doc:from_json_obj({[
-        {<<"_id">>, <<"org.couchdb.user:", User/binary>>},
-        {<<"name">>, User},
-        {<<"type">>, <<"user">>},
-        {<<"salt">>, ?SALT},
-        {<<"password_sha">>, hash_password(Password)},
-        {<<"roles">>, []}
-    ] ++ case Rev of
-            nil -> [];
-            _ ->   [{<<"_rev">>, Rev}]
-         end
-    }),
-    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
-    {ok, NewRev} = couch_db:update_doc(AuthDb, Doc, []),
-    ok = couch_db:close(AuthDb),
-    {ok, couch_doc:rev_to_str(NewRev)}.
-
-hash_password(Password) ->
-    ?l2b(couch_util:to_hex(crypto:sha(iolist_to_binary([Password, ?SALT])))).
-
-shutdown_db(DbName) ->
-    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
-    ok = couch_db:close(AuthDb),
-    couch_util:shutdown_sync(AuthDb#db.main_pid),
-    ok = timer:sleep(1000).
-
-get_doc_rev(DbName, UserName) ->
-    DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
-    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
-    UpdateRev =
-    case couch_db:open_doc(AuthDb, DocId, []) of
-    {ok, Doc} ->
-        {Props} = couch_doc:to_json_obj(Doc, []),
-        couch_util:get_value(<<"_rev">>, Props);
-    {not_found, missing} ->
-        nil
-    end,
-    ok = couch_db:close(AuthDb),
-    {ok, UpdateRev}.
-
-get_user_doc_password_sha(DbName, UserName) ->
-    DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
-    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
-    {ok, Doc} = couch_db:open_doc(AuthDb, DocId, []),
-    ok = couch_db:close(AuthDb),
-    {Props} = couch_doc:to_json_obj(Doc, []),
-    couch_util:get_value(<<"password_sha">>, Props).
-
-delete_user_doc(DbName, UserName) ->
-    DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
-    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
-    {ok, Doc} = couch_db:open_doc(AuthDb, DocId, []),
-    {Props} = couch_doc:to_json_obj(Doc, []),
-    DeletedDoc = couch_doc:from_json_obj({[
-        {<<"_id">>, DocId},
-        {<<"_rev">>, couch_util:get_value(<<"_rev">>, Props)},
-        {<<"_deleted">>, true}
-    ]}),
-    {ok, _} = couch_db:update_doc(AuthDb, DeletedDoc, []),
-    ok = couch_db:close(AuthDb).
-
-full_commit(DbName) ->
-    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
-    {ok, _} = couch_db:ensure_full_commit(AuthDb),
-    ok = couch_db:close(AuthDb).
+%% start() ->
+%%     ok = test_util:start_couch(),
+%%     {ok, Pid} = couch_auth_cache:start_link(),
+%%     Pid.
+
+%% stop(Pid) ->
+%%     erlang:monitor(process, Pid),
+%%     exit(Pid, normal),
+%%     receive
+%%         {'DOWN', _, _, Pid, _} ->
+%%             ok
+%%     after ?TIMEOUT ->
+%%         throw({timeout, auth_cache_stop})
+%%     end,
+%%     ok = test_util:stop_couch().
+
+%% setup() ->
+%%     DbName = ?tempdb(),
+%%     config:set("couch_httpd_auth", "authentication_db",
+%%                      ?b2l(DbName), false),
+%%     DbName.
+
+%% teardown(DbName) ->
+%%     ok = couch_server:delete(DbName, [?ADMIN_USER]),
+%%     ok.
+
+
+%% couch_auth_cache_test_() ->
+%%     {
+%%         "CouchDB auth cache tests",
+%%         {
+%%             setup,
+%%             fun start/0, fun stop/1,
+%%             {
+%%                 foreach,
+%%                 fun setup/0, fun teardown/1,
+%%                 [
+%%                     fun should_get_nil_on_missed_cache/1,
+%%                     fun should_get_right_password_hash/1,
+%%                     fun should_ensure_doc_hash_equals_cached_one/1,
+%%                     fun should_update_password/1,
+%%                     fun should_cleanup_cache_after_userdoc_deletion/1,
+%%                     fun should_restore_cache_after_userdoc_recreation/1,
+%%                     fun should_drop_cache_on_auth_db_change/1,
+%%                     fun should_restore_cache_on_auth_db_change/1,
+%%                     fun should_recover_cache_after_shutdown/1
+%%                 ]
+%%             }
+%%         }
+%%     }.
+
+
+%% should_get_nil_on_missed_cache(_) ->
+%%     ?_assertEqual(nil, couch_auth_cache:get_user_creds("joe")).
+
+%% should_get_right_password_hash(DbName) ->
+%%     ?_test(begin
+%%         PasswordHash = hash_password("pass1"),
+%%         {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+%%         Creds = couch_auth_cache:get_user_creds("joe"),
+%%         ?assertEqual(PasswordHash,
+%%                       couch_util:get_value(<<"password_sha">>, Creds))
+%%     end).
+
+%% should_ensure_doc_hash_equals_cached_one(DbName) ->
+%%     ?_test(begin
+%%         {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+%%         Creds = couch_auth_cache:get_user_creds("joe"),
+
+%%         CachedHash = couch_util:get_value(<<"password_sha">>, Creds),
+%%         StoredHash = get_user_doc_password_sha(DbName, "joe"),
+%%         ?assertEqual(StoredHash, CachedHash)
+%%     end).
+
+%% should_update_password(DbName) ->
+%%     ?_test(begin
+%%         PasswordHash = hash_password("pass2"),
+%%         {ok, Rev} = update_user_doc(DbName, "joe", "pass1"),
+%%         {ok, _} = update_user_doc(DbName, "joe", "pass2", Rev),
+%%         Creds = couch_auth_cache:get_user_creds("joe"),
+%%         ?assertEqual(PasswordHash,
+%%                       couch_util:get_value(<<"password_sha">>, Creds))
+%%     end).
+
+%% should_cleanup_cache_after_userdoc_deletion(DbName) ->
+%%     ?_test(begin
+%%         {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+%%         delete_user_doc(DbName, "joe"),
+%%         ?assertEqual(nil, couch_auth_cache:get_user_creds("joe"))
+%%     end).
+
+%% should_restore_cache_after_userdoc_recreation(DbName) ->
+%%     ?_test(begin
+%%         PasswordHash = hash_password("pass5"),
+%%         {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+%%         delete_user_doc(DbName, "joe"),
+%%         ?assertEqual(nil, couch_auth_cache:get_user_creds("joe")),
+
+%%         {ok, _} = update_user_doc(DbName, "joe", "pass5"),
+%%         Creds = couch_auth_cache:get_user_creds("joe"),
+
+%%         ?assertEqual(PasswordHash,
+%%                       couch_util:get_value(<<"password_sha">>, Creds))
+%%     end).
+
+%% should_drop_cache_on_auth_db_change(DbName) ->
+%%     ?_test(begin
+%%         {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+%%         full_commit(DbName),
+%%         config:set("couch_httpd_auth", "authentication_db",
+%%                          ?b2l(?tempdb()), false),
+%%         ?assertEqual(nil, couch_auth_cache:get_user_creds("joe"))
+%%     end).
+
+%% should_restore_cache_on_auth_db_change(DbName) ->
+%%     ?_test(begin
+%%         PasswordHash = hash_password("pass1"),
+%%         {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+%%         Creds = couch_auth_cache:get_user_creds("joe"),
+%%         full_commit(DbName),
+
+%%         DbName1 = ?tempdb(),
+%%         config:set("couch_httpd_auth", "authentication_db",
+%%                          ?b2l(DbName1), false),
+
+%%         {ok, _} = update_user_doc(DbName1, "joe", "pass5"),
+%%         full_commit(DbName1),
+
+%%         config:set("couch_httpd_auth", "authentication_db",
+%%                          ?b2l(DbName), false),
+
+%%         Creds = couch_auth_cache:get_user_creds("joe"),
+%%         ?assertEqual(PasswordHash,
+%%                       couch_util:get_value(<<"password_sha">>, Creds))
+%%     end).
+
+%% should_recover_cache_after_shutdown(DbName) ->
+%%     ?_test(begin
+%%         PasswordHash = hash_password("pass2"),
+%%         {ok, Rev0} = update_user_doc(DbName, "joe", "pass1"),
+%%         {ok, Rev1} = update_user_doc(DbName, "joe", "pass2", Rev0),
+%%         full_commit(DbName),
+%%         shutdown_db(DbName),
+%%         {ok, Rev1} = get_doc_rev(DbName, "joe"),
+%%         ?assertEqual(PasswordHash, get_user_doc_password_sha(DbName, "joe"))
+%%     end).
+
+
+%% update_user_doc(DbName, UserName, Password) ->
+%%     update_user_doc(DbName, UserName, Password, nil).
+
+%% update_user_doc(DbName, UserName, Password, Rev) ->
+%%     User = iolist_to_binary(UserName),
+%%     Doc = couch_doc:from_json_obj({[
+%%         {<<"_id">>, <<"org.couchdb.user:", User/binary>>},
+%%         {<<"name">>, User},
+%%         {<<"type">>, <<"user">>},
+%%         {<<"salt">>, ?SALT},
+%%         {<<"password_sha">>, hash_password(Password)},
+%%         {<<"roles">>, []}
+%%     ] ++ case Rev of
+%%             nil -> [];
+%%             _ ->   [{<<"_rev">>, Rev}]
+%%          end
+%%     }),
+%%     {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+%%     {ok, NewRev} = couch_db:update_doc(AuthDb, Doc, []),
+%%     ok = couch_db:close(AuthDb),
+%%     {ok, couch_doc:rev_to_str(NewRev)}.
+
+%% hash_password(Password) ->
+%%     ?l2b(couch_util:to_hex(crypto:sha(iolist_to_binary([Password, ?SALT])))).
+
+%% shutdown_db(DbName) ->
+%%     {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+%%     ok = couch_db:close(AuthDb),
+%%     couch_util:shutdown_sync(AuthDb#db.main_pid),
+%%     ok = timer:sleep(1000).
+
+%% get_doc_rev(DbName, UserName) ->
+%%     DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
+%%     {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+%%     UpdateRev =
+%%     case couch_db:open_doc(AuthDb, DocId, []) of
+%%     {ok, Doc} ->
+%%         {Props} = couch_doc:to_json_obj(Doc, []),
+%%         couch_util:get_value(<<"_rev">>, Props);
+%%     {not_found, missing} ->
+%%         nil
+%%     end,
+%%     ok = couch_db:close(AuthDb),
+%%     {ok, UpdateRev}.
+
+%% get_user_doc_password_sha(DbName, UserName) ->
+%%     DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
+%%     {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+%%     {ok, Doc} = couch_db:open_doc(AuthDb, DocId, []),
+%%     ok = couch_db:close(AuthDb),
+%%     {Props} = couch_doc:to_json_obj(Doc, []),
+%%     couch_util:get_value(<<"password_sha">>, Props).
+
+%% delete_user_doc(DbName, UserName) ->
+%%     DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
+%%     {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+%%     {ok, Doc} = couch_db:open_doc(AuthDb, DocId, []),
+%%     {Props} = couch_doc:to_json_obj(Doc, []),
+%%     DeletedDoc = couch_doc:from_json_obj({[
+%%         {<<"_id">>, DocId},
+%%         {<<"_rev">>, couch_util:get_value(<<"_rev">>, Props)},
+%%         {<<"_deleted">>, true}
+%%     ]}),
+%%     {ok, _} = couch_db:update_doc(AuthDb, DeletedDoc, []),
+%%     ok = couch_db:close(AuthDb).
+
+%% full_commit(DbName) ->
+%%     {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+%%     {ok, _} = couch_db:ensure_full_commit(AuthDb),
+%%     ok = couch_db:close(AuthDb).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/6179af60/test/couch_changes_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_changes_tests.erl b/test/couch_changes_tests.erl
index 3ae1b52..2269a27 100644
--- a/test/couch_changes_tests.erl
+++ b/test/couch_changes_tests.erl
@@ -26,573 +26,582 @@
 }).
 
 
-setup() ->
-    DbName = ?tempdb(),
-    {ok, Db} = create_db(DbName),
-    Revs = [R || {ok, R} <- [
-        save_doc(Db, {[{<<"_id">>, <<"doc1">>}]}),
-        save_doc(Db, {[{<<"_id">>, <<"doc2">>}]}),
-        save_doc(Db, {[{<<"_id">>, <<"doc3">>}]}),
-        save_doc(Db, {[{<<"_id">>, <<"doc4">>}]}),
-        save_doc(Db, {[{<<"_id">>, <<"doc5">>}]})
-    ]],
-    Rev = lists:nth(3, Revs),
-    {ok, Rev1} = save_doc(Db, {[{<<"_id">>, <<"doc3">>}, {<<"_rev">>, Rev}]}),
-    Revs1 = Revs ++ [Rev1],
-    Revs2 = Revs1 ++ [R || {ok, R} <- [
-        save_doc(Db, {[{<<"_id">>, <<"doc6">>}]}),
-        save_doc(Db, {[{<<"_id">>, <<"_design/foo">>}]}),
-        save_doc(Db, {[{<<"_id">>, <<"doc7">>}]}),
-        save_doc(Db, {[{<<"_id">>, <<"doc8">>}]})
-    ]],
-    {DbName, list_to_tuple(Revs2)}.
-
-teardown({DbName, _}) ->
-    delete_db(DbName),
-    ok.
-
-
-changes_test_() ->
-    {
-        "Changes feeed",
-        {
-            setup,
-            fun test_util:start_couch/0, fun test_util:stop_couch/1,
-            [
-                filter_by_doc_id(),
-                filter_by_design(),
-                continuous_feed(),
-                filter_by_custom_function()
-            ]
-        }
-    }.
-
-filter_by_doc_id() ->
-    {
-        "Filter _doc_id",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                fun should_filter_by_specific_doc_ids/1,
-                fun should_filter_by_specific_doc_ids_descending/1,
-                fun should_filter_by_specific_doc_ids_with_since/1,
-                fun should_filter_by_specific_doc_ids_no_result/1,
-                fun should_handle_deleted_docs/1
-            ]
-        }
-    }.
-
-filter_by_design() ->
-    {
-        "Filter _design",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                fun should_emit_only_design_documents/1
-            ]
-        }
-    }.
-
-filter_by_custom_function() ->
-    {
-        "Filter function",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                fun should_receive_heartbeats/1
-            ]
-        }
-    }.
-
-continuous_feed() ->
-    {
-        "Continuous Feed",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                fun should_filter_continuous_feed_by_specific_doc_ids/1
-            ]
-        }
-    }.
-
-
-should_filter_by_specific_doc_ids({DbName, _}) ->
-    ?_test(
-        begin
-            ChangesArgs = #changes_args{
-                filter = "_doc_ids"
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-
-            {Rows, LastSeq} = wait_finished(Consumer),
-            {ok, Db} = couch_db:open_int(DbName, []),
-            UpSeq = couch_db:get_update_seq(Db),
-            couch_db:close(Db),
-            stop_consumer(Consumer),
-
-            ?assertEqual(2, length(Rows)),
-            [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
-            ?assertEqual(<<"doc4">>, Id1),
-            ?assertEqual(4, Seq1),
-            ?assertEqual(<<"doc3">>, Id2),
-            ?assertEqual(6, Seq2),
-            ?assertEqual(UpSeq, LastSeq)
-        end).
-
-should_filter_by_specific_doc_ids_descending({DbName, _}) ->
-    ?_test(
-        begin
-            ChangesArgs = #changes_args{
-                filter = "_doc_ids",
-                dir = rev
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-
-            {Rows, LastSeq} = wait_finished(Consumer),
-            {ok, Db} = couch_db:open_int(DbName, []),
-            couch_db:close(Db),
-            stop_consumer(Consumer),
-
-            ?assertEqual(2, length(Rows)),
-            [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
-            ?assertEqual(<<"doc3">>, Id1),
-            ?assertEqual(6, Seq1),
-            ?assertEqual(<<"doc4">>, Id2),
-            ?assertEqual(4, Seq2),
-            ?assertEqual(4, LastSeq)
-        end).
-
-should_filter_by_specific_doc_ids_with_since({DbName, _}) ->
-    ?_test(
-        begin
-            ChangesArgs = #changes_args{
-                filter = "_doc_ids",
-                since = 5
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-
-            {Rows, LastSeq} = wait_finished(Consumer),
-            {ok, Db} = couch_db:open_int(DbName, []),
-            UpSeq = couch_db:get_update_seq(Db),
-            couch_db:close(Db),
-            stop_consumer(Consumer),
-
-            ?assertEqual(1, length(Rows)),
-            [#row{seq = Seq1, id = Id1}] = Rows,
-            ?assertEqual(<<"doc3">>, Id1),
-            ?assertEqual(6, Seq1),
-            ?assertEqual(UpSeq, LastSeq)
-        end).
-
-should_filter_by_specific_doc_ids_no_result({DbName, _}) ->
-    ?_test(
-        begin
-            ChangesArgs = #changes_args{
-                filter = "_doc_ids",
-                since = 6
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-
-            {Rows, LastSeq} = wait_finished(Consumer),
-            {ok, Db} = couch_db:open_int(DbName, []),
-            UpSeq = couch_db:get_update_seq(Db),
-            couch_db:close(Db),
-            stop_consumer(Consumer),
-
-            ?assertEqual(0, length(Rows)),
-            ?assertEqual(UpSeq, LastSeq)
-        end).
-
-should_handle_deleted_docs({DbName, Revs}) ->
-    ?_test(
-        begin
-            Rev3_2 = element(6, Revs),
-            {ok, Db} = couch_db:open_int(DbName, []),
-            {ok, _} = save_doc(
-                Db,
-                {[{<<"_id">>, <<"doc3">>},
-                  {<<"_deleted">>, true},
-                  {<<"_rev">>, Rev3_2}]}),
-
-            ChangesArgs = #changes_args{
-                filter = "_doc_ids",
-                since = 9
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-
-            {Rows, LastSeq} = wait_finished(Consumer),
-            couch_db:close(Db),
-            stop_consumer(Consumer),
-
-            ?assertEqual(1, length(Rows)),
-            ?assertMatch(
-                [#row{seq = LastSeq, id = <<"doc3">>, deleted = true}],
-                Rows
-            ),
-            ?assertEqual(11, LastSeq)
-        end).
-
-should_filter_continuous_feed_by_specific_doc_ids({DbName, Revs}) ->
-    ?_test(
-        begin
-            {ok, Db} = couch_db:open_int(DbName, []),
-            ChangesArgs = #changes_args{
-                filter = "_doc_ids",
-                feed = "continuous"
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-            pause(Consumer),
-
-            Rows = get_rows(Consumer),
-            ?assertEqual(2, length(Rows)),
-            [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
-            ?assertEqual(<<"doc4">>, Id1),
-            ?assertEqual(4, Seq1),
-            ?assertEqual(<<"doc3">>, Id2),
-            ?assertEqual(6, Seq2),
-
-            clear_rows(Consumer),
-            {ok, _Rev9} = save_doc(Db, {[{<<"_id">>, <<"doc9">>}]}),
-            {ok, _Rev10} = save_doc(Db, {[{<<"_id">>, <<"doc10">>}]}),
-            unpause(Consumer),
-            pause(Consumer),
-            ?assertEqual([], get_rows(Consumer)),
-
-            Rev4 = element(4, Revs),
-            Rev3_2 = element(6, Revs),
-            {ok, Rev4_2} = save_doc(Db, {[{<<"_id">>, <<"doc4">>},
-                                          {<<"_rev">>, Rev4}]}),
-            {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc11">>}]}),
-            {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc4">>},
-                                     {<<"_rev">>, Rev4_2}]}),
-            {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc12">>}]}),
-            {ok, Rev3_3} = save_doc(Db, {[{<<"_id">>, <<"doc3">>},
-                                          {<<"_rev">>, Rev3_2}]}),
-            unpause(Consumer),
-            pause(Consumer),
-
-            NewRows = get_rows(Consumer),
-            ?assertEqual(2, length(NewRows)),
-            [Row14, Row16] = NewRows,
-            ?assertEqual(<<"doc4">>, Row14#row.id),
-            ?assertEqual(15, Row14#row.seq),
-            ?assertEqual(<<"doc3">>, Row16#row.id),
-            ?assertEqual(17, Row16#row.seq),
-
-            clear_rows(Consumer),
-            {ok, _Rev3_4} = save_doc(Db, {[{<<"_id">>, <<"doc3">>},
-                                           {<<"_rev">>, Rev3_3}]}),
-            unpause(Consumer),
-            pause(Consumer),
-
-            FinalRows = get_rows(Consumer),
-
-            unpause(Consumer),
-            stop_consumer(Consumer),
-
-            ?assertMatch([#row{seq = 18, id = <<"doc3">>}], FinalRows)
-        end).
-
-should_emit_only_design_documents({DbName, Revs}) ->
-    ?_test(
-        begin
-            ChangesArgs = #changes_args{
-                filter = "_design"
-            },
-            Consumer = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
-
-            {Rows, LastSeq} = wait_finished(Consumer),
-            {ok, Db} = couch_db:open_int(DbName, []),
-            UpSeq = couch_db:get_update_seq(Db),
-            couch_db:close(Db),
-
-            ?assertEqual(1, length(Rows)),
-            ?assertEqual(UpSeq, LastSeq),
-            ?assertEqual([#row{seq = 8, id = <<"_design/foo">>}], Rows),
-
-            stop_consumer(Consumer),
-
-            {ok, Db2} = couch_db:open_int(DbName, [?ADMIN_USER]),
-            {ok, _} = save_doc(Db2, {[{<<"_id">>, <<"_design/foo">>},
-                                      {<<"_rev">>, element(8, Revs)},
-                                      {<<"_deleted">>, true}]}),
-
-            Consumer2 = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
-
-            {Rows2, LastSeq2} = wait_finished(Consumer2),
-            UpSeq2 = UpSeq + 1,
-            couch_db:close(Db2),
-
-            ?assertEqual(1, length(Rows2)),
-            ?assertEqual(UpSeq2, LastSeq2),
-            ?assertEqual([#row{seq = 11,
-                               id = <<"_design/foo">>,
-                               deleted = true}],
-                          Rows2)
-        end).
-
-should_receive_heartbeats(_) ->
-    {timeout, ?TEST_TIMEOUT div 1000,
-     ?_test(
-         begin
-             DbName = ?tempdb(),
-             Timeout = 100,
-             {ok, Db} = create_db(DbName),
-
-             {ok, _} = save_doc(Db, {[
-                 {<<"_id">>, <<"_design/filtered">>},
-                 {<<"language">>, <<"javascript">>},
-                     {<<"filters">>, {[
-                         {<<"foo">>, <<"function(doc) {
-                             return ['doc10', 'doc11', 'doc12'].indexOf(doc._id) != -1;}">>
-                     }]}}
-             ]}),
-
-             ChangesArgs = #changes_args{
-                 filter = "filtered/foo",
-                 feed = "continuous",
-                 timeout = 10000,
-                 heartbeat = 1000
-             },
-             Consumer = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
-
-             {ok, _Rev1} = save_doc(Db, {[{<<"_id">>, <<"doc1">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev2} = save_doc(Db, {[{<<"_id">>, <<"doc2">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev3} = save_doc(Db, {[{<<"_id">>, <<"doc3">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev4} = save_doc(Db, {[{<<"_id">>, <<"doc4">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev5} = save_doc(Db, {[{<<"_id">>, <<"doc5">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev6} = save_doc(Db, {[{<<"_id">>, <<"doc6">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev7} = save_doc(Db, {[{<<"_id">>, <<"doc7">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev8} = save_doc(Db, {[{<<"_id">>, <<"doc8">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev9} = save_doc(Db, {[{<<"_id">>, <<"doc9">>}]}),
-
-             Heartbeats = get_heartbeats(Consumer),
-             ?assert(Heartbeats > 0),
-
-             {ok, _Rev10} = save_doc(Db, {[{<<"_id">>, <<"doc10">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev11} = save_doc(Db, {[{<<"_id">>, <<"doc11">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev12} = save_doc(Db, {[{<<"_id">>, <<"doc12">>}]}),
-
-             Heartbeats2 = get_heartbeats(Consumer),
-             ?assert(Heartbeats2 > Heartbeats),
-
-             Rows = get_rows(Consumer),
-             ?assertEqual(3, length(Rows)),
-
-             {ok, _Rev13} = save_doc(Db, {[{<<"_id">>, <<"doc13">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev14} = save_doc(Db, {[{<<"_id">>, <<"doc14">>}]}),
-             timer:sleep(Timeout),
-
-             Heartbeats3 = get_heartbeats(Consumer),
-             ?assert(Heartbeats3 > Heartbeats2)
-        end)}.
-
-
-save_doc(Db, Json) ->
-    Doc = couch_doc:from_json_obj(Json),
-    {ok, Rev} = couch_db:update_doc(Db, Doc, []),
-    {ok, couch_doc:rev_to_str(Rev)}.
-
-get_rows(Consumer) ->
-    Ref = make_ref(),
-    Consumer ! {get_rows, Ref},
-    Resp = receive
-        {rows, Ref, Rows} ->
-            Rows
-    after ?TIMEOUT ->
-        timeout
-    end,
-    ?assertNotEqual(timeout, Resp),
-    Resp.
-
-get_heartbeats(Consumer) ->
-    Ref = make_ref(),
-    Consumer ! {get_heartbeats, Ref},
-    Resp = receive
-        {hearthbeats, Ref, HeartBeats} ->
-            HeartBeats
-    after ?TIMEOUT ->
-        timeout
-    end,
-    ?assertNotEqual(timeout, Resp),
-    Resp.
-
-clear_rows(Consumer) ->
-    Ref = make_ref(),
-    Consumer ! {reset, Ref},
-    Resp = receive
-        {ok, Ref} ->
-            ok
-    after ?TIMEOUT ->
-        timeout
-    end,
-    ?assertNotEqual(timeout, Resp),
-    Resp.
-
-stop_consumer(Consumer) ->
-    Ref = make_ref(),
-    Consumer ! {stop, Ref},
-    Resp = receive
-        {ok, Ref} ->
-            ok
-    after ?TIMEOUT ->
-        timeout
-    end,
-    ?assertNotEqual(timeout, Resp),
-    Resp.
-
-pause(Consumer) ->
-    Ref = make_ref(),
-    Consumer ! {pause, Ref},
-    Resp = receive
-        {paused, Ref} ->
-            ok
-    after ?TIMEOUT ->
-        timeout
-    end,
-    ?assertNotEqual(timeout, Resp),
-    Resp.
-
-unpause(Consumer) ->
-    Ref = make_ref(),
-    Consumer ! {continue, Ref},
-    Resp = receive
-        {ok, Ref} ->
-            ok
-    after ?TIMEOUT ->
-       timeout
-    end,
-    ?assertNotEqual(timeout, Resp),
-    Resp.
-
-wait_finished(_Consumer) ->
-    Resp = receive
-        {consumer_finished, Rows, LastSeq} ->
-            {Rows, LastSeq}
-    after ?TIMEOUT ->
-        timeout
-    end,
-    ?assertNotEqual(timeout, Resp),
-    Resp.
-
-spawn_consumer(DbName, ChangesArgs0, Req) ->
-    Parent = self(),
-    spawn(fun() ->
-        put(heartbeat_count, 0),
-        Callback = fun
-            ({change, {Change}, _}, _, Acc) ->
-                Id = couch_util:get_value(<<"id">>, Change),
-                Seq = couch_util:get_value(<<"seq">>, Change),
-                Del = couch_util:get_value(<<"deleted">>, Change, false),
-                [#row{id = Id, seq = Seq, deleted = Del} | Acc];
-            ({stop, LastSeq}, _, Acc) ->
-                Parent ! {consumer_finished, lists:reverse(Acc), LastSeq},
-                stop_loop(Parent, Acc);
-            (timeout, _, Acc) ->
-                put(heartbeat_count, get(heartbeat_count) + 1),
-                maybe_pause(Parent, Acc);
-            (_, _, Acc) ->
-                maybe_pause(Parent, Acc)
-        end,
-        {ok, Db} = couch_db:open_int(DbName, []),
-        ChangesArgs = case (ChangesArgs0#changes_args.timeout =:= undefined)
-            andalso (ChangesArgs0#changes_args.heartbeat =:= undefined) of
-            true ->
-                ChangesArgs0#changes_args{timeout = 10, heartbeat = 10};
-            false ->
-                ChangesArgs0
-        end,
-        FeedFun = couch_changes:handle_changes(ChangesArgs, Req, Db),
-        try
-            FeedFun({Callback, []})
-        catch throw:{stop, _} ->
-            ok
-        end,
-        catch couch_db:close(Db)
-    end).
-
-maybe_pause(Parent, Acc) ->
-    receive
-        {get_rows, Ref} ->
-            Parent ! {rows, Ref, lists:reverse(Acc)},
-            maybe_pause(Parent, Acc);
-        {get_heartbeats, Ref} ->
-            Parent ! {hearthbeats, Ref, get(heartbeat_count)},
-            maybe_pause(Parent, Acc);
-        {reset, Ref} ->
-            Parent ! {ok, Ref},
-            maybe_pause(Parent, []);
-        {pause, Ref} ->
-            Parent ! {paused, Ref},
-            pause_loop(Parent, Acc);
-        {stop, Ref} ->
-            Parent ! {ok, Ref},
-            throw({stop, Acc});
-        V ->
-            erlang:error({assertion_failed,
-                      [{module, ?MODULE},
-                       {line, ?LINE},
-                       {value, V},
-                       {reason, "Received unexpected message"}]})
-    after 0 ->
-        Acc
-    end.
-
-pause_loop(Parent, Acc) ->
-    receive
-        {stop, Ref} ->
-            Parent ! {ok, Ref},
-            throw({stop, Acc});
-        {reset, Ref} ->
-            Parent ! {ok, Ref},
-            pause_loop(Parent, []);
-        {continue, Ref} ->
-            Parent ! {ok, Ref},
-            Acc;
-        {get_rows, Ref} ->
-            Parent ! {rows, Ref, lists:reverse(Acc)},
-            pause_loop(Parent, Acc)
-    end.
-
-stop_loop(Parent, Acc) ->
-    receive
-        {get_rows, Ref} ->
-            Parent ! {rows, Ref, lists:reverse(Acc)},
-            stop_loop(Parent, Acc);
-        {stop, Ref} ->
-            Parent ! {ok, Ref},
-            Acc
-    end.
-
-create_db(DbName) ->
-    couch_db:create(DbName, [?ADMIN_USER, overwrite]).
-
-delete_db(DbName) ->
-    ok = couch_server:delete(DbName, [?ADMIN_USER]).
+%% setup() ->
+%%     DbName = ?tempdb(),
+%%     {ok, Db} = create_db(DbName),
+%%     Revs = [R || {ok, R} <- [
+%%         save_doc(Db, {[{<<"_id">>, <<"doc1">>}]}),
+%%         save_doc(Db, {[{<<"_id">>, <<"doc2">>}]}),
+%%         save_doc(Db, {[{<<"_id">>, <<"doc3">>}]}),
+%%         save_doc(Db, {[{<<"_id">>, <<"doc4">>}]}),
+%%         save_doc(Db, {[{<<"_id">>, <<"doc5">>}]})
+%%     ]],
+%%     Rev = lists:nth(3, Revs),
+%%     DC = config:get("couchdb", "delayed_commits", "NOT ENABLED"),
+%%     ?debugFmt("~nDB IS: ~p~nDelayed Commits: ~p~n", [DbName, DC]),
+%%     AllDocs = couch_mrview:query_all_docs(Db, []),
+%%     ?debugFmt("~nALL DOCS ARE[~p]: ~p~n", [DbName, AllDocs]),
+%%     {ok, Doc} = couch_db:open_doc(Db, <<"doc3">>),
+%%     ?debugFmt("DOC3 IS CURRENTLY: ~p~nOld Rev is: ~p~n", [Doc, couch_doc:rev_to_str(Rev)]),
+%%     ?debugFmt("SAVING DOC3 WITH REV: ~p~n", [Rev]),
+%%     {ok, Rev1} = save_doc(Db, {[{<<"_id">>, <<"doc3">>}, {<<"_rev">>, Rev}]}),
+%%     Revs1 = Revs ++ [Rev1],
+%%     Revs2 = Revs1 ++ [R || {ok, R} <- [
+%%         save_doc(Db, {[{<<"_id">>, <<"doc6">>}]}),
+%%         save_doc(Db, {[{<<"_id">>, <<"_design/foo">>}]}),
+%%         save_doc(Db, {[{<<"_id">>, <<"doc7">>}]}),
+%%         save_doc(Db, {[{<<"_id">>, <<"doc8">>}]})
+%%     ]],
+%%     {DbName, list_to_tuple(Revs2)}.
+
+%% teardown({DbName, _}) ->
+%%     delete_db(DbName),
+%%     ok.
+
+
+%% changes_test_() ->
+%%     {
+%%         "Changes feeed",
+%%         {
+%%             setup,
+%%             fun test_util:start_couch/0, fun test_util:stop_couch/1,
+%%             [
+%%                 filter_by_doc_id(),
+%%                 filter_by_design(),
+%%                 continuous_feed(),
+%%                 filter_by_custom_function()
+%%             ]
+%%         }
+%%     }.
+
+%% filter_by_doc_id() ->
+%%     {
+%%         "Filter _doc_id",
+%%         {
+%%             foreach,
+%%             fun setup/0, fun teardown/1,
+%%             [
+%%                 fun should_filter_by_specific_doc_ids/1,
+%%                 fun should_filter_by_specific_doc_ids_descending/1,
+%%                 fun should_filter_by_specific_doc_ids_with_since/1,
+%%                 fun should_filter_by_specific_doc_ids_no_result/1,
+%%                 fun should_handle_deleted_docs/1
+%%             ]
+%%         }
+%%     }.
+
+%% filter_by_design() ->
+%%     {
+%%         "Filter _design",
+%%         {
+%%             foreach,
+%%             fun setup/0, fun teardown/1,
+%%             [
+%%                 fun should_emit_only_design_documents/1
+%%             ]
+%%         }
+%%     }.
+
+%% filter_by_custom_function() ->
+%%     {
+%%         "Filter function",
+%%         {
+%%             foreach,
+%%             fun setup/0, fun teardown/1,
+%%             [
+%%                 fun should_receive_heartbeats/1
+%%             ]
+%%         }
+%%     }.
+
+%% continuous_feed() ->
+%%     {
+%%         "Continuous Feed",
+%%         {
+%%             foreach,
+%%             fun setup/0, fun teardown/1,
+%%             [
+%%                 fun should_filter_continuous_feed_by_specific_doc_ids/1
+%%             ]
+%%         }
+%%     }.
+
+
+%% should_filter_by_specific_doc_ids({DbName, _}) ->
+%%     ?_test(
+%%         begin
+%%             ChangesArgs = #changes_args{
+%%                 filter = "_doc_ids"
+%%             },
+%%             DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+%%             Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+%%             Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+
+%%             {Rows, LastSeq} = wait_finished(Consumer),
+%%             {ok, Db} = couch_db:open_int(DbName, []),
+%%             UpSeq = couch_db:get_update_seq(Db),
+%%             couch_db:close(Db),
+%%             stop_consumer(Consumer),
+
+%%             ?assertEqual(2, length(Rows)),
+%%             [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
+%%             ?assertEqual(<<"doc4">>, Id1),
+%%             ?assertEqual(4, Seq1),
+%%             ?assertEqual(<<"doc3">>, Id2),
+%%             ?assertEqual(6, Seq2),
+%%             ?assertEqual(UpSeq, LastSeq)
+%%         end).
+
+%% should_filter_by_specific_doc_ids_descending({DbName, _}) ->
+%%     ?_test(
+%%         begin
+%%             ChangesArgs = #changes_args{
+%%                 filter = "_doc_ids",
+%%                 dir = rev
+%%             },
+%%             DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+%%             Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+%%             Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+
+%%             {Rows, LastSeq} = wait_finished(Consumer),
+%%             {ok, Db} = couch_db:open_int(DbName, []),
+%%             couch_db:close(Db),
+%%             stop_consumer(Consumer),
+
+%%             ?assertEqual(2, length(Rows)),
+%%             [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
+%%             ?assertEqual(<<"doc3">>, Id1),
+%%             ?assertEqual(6, Seq1),
+%%             ?assertEqual(<<"doc4">>, Id2),
+%%             ?assertEqual(4, Seq2),
+%%             ?assertEqual(4, LastSeq)
+%%         end).
+
+%% should_filter_by_specific_doc_ids_with_since({DbName, _}) ->
+%%     ?_test(
+%%         begin
+%%             ChangesArgs = #changes_args{
+%%                 filter = "_doc_ids",
+%%                 since = 5
+%%             },
+%%             DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+%%             Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+%%             Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+
+%%             {Rows, LastSeq} = wait_finished(Consumer),
+%%             {ok, Db} = couch_db:open_int(DbName, []),
+%%             UpSeq = couch_db:get_update_seq(Db),
+%%             couch_db:close(Db),
+%%             stop_consumer(Consumer),
+
+%%             ?assertEqual(1, length(Rows)),
+%%             [#row{seq = Seq1, id = Id1}] = Rows,
+%%             ?assertEqual(<<"doc3">>, Id1),
+%%             ?assertEqual(6, Seq1),
+%%             ?assertEqual(UpSeq, LastSeq)
+%%         end).
+
+%% should_filter_by_specific_doc_ids_no_result({DbName, _}) ->
+%%     ?_test(
+%%         begin
+%%             ChangesArgs = #changes_args{
+%%                 filter = "_doc_ids",
+%%                 since = 6
+%%             },
+%%             DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+%%             Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+%%             Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+
+%%             {Rows, LastSeq} = wait_finished(Consumer),
+%%             {ok, Db} = couch_db:open_int(DbName, []),
+%%             UpSeq = couch_db:get_update_seq(Db),
+%%             couch_db:close(Db),
+%%             stop_consumer(Consumer),
+
+%%             ?assertEqual(0, length(Rows)),
+%%             ?assertEqual(UpSeq, LastSeq)
+%%         end).
+
+%% should_handle_deleted_docs({DbName, Revs}) ->
+%%     ?_test(
+%%         begin
+%%             Rev3_2 = element(6, Revs),
+%%             {ok, Db} = couch_db:open_int(DbName, []),
+%%             {ok, _} = save_doc(
+%%                 Db,
+%%                 {[{<<"_id">>, <<"doc3">>},
+%%                   {<<"_deleted">>, true},
+%%                   {<<"_rev">>, Rev3_2}]}),
+
+%%             ChangesArgs = #changes_args{
+%%                 filter = "_doc_ids",
+%%                 since = 9
+%%             },
+%%             DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+%%             Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+%%             Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+
+%%             {Rows, LastSeq} = wait_finished(Consumer),
+%%             couch_db:close(Db),
+%%             stop_consumer(Consumer),
+
+%%             ?assertEqual(1, length(Rows)),
+%%             ?assertMatch(
+%%                 [#row{seq = LastSeq, id = <<"doc3">>, deleted = true}],
+%%                 Rows
+%%             ),
+%%             ?assertEqual(11, LastSeq)
+%%         end).
+
+%% should_filter_continuous_feed_by_specific_doc_ids({DbName, Revs}) ->
+%%     ?_test(
+%%         begin
+%%             {ok, Db} = couch_db:open_int(DbName, []),
+%%             ChangesArgs = #changes_args{
+%%                 filter = "_doc_ids",
+%%                 feed = "continuous"
+%%             },
+%%             DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+%%             Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+%%             Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+%%             pause(Consumer),
+
+%%             Rows = get_rows(Consumer),
+%%             ?assertEqual(2, length(Rows)),
+%%             [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
+%%             ?assertEqual(<<"doc4">>, Id1),
+%%             ?assertEqual(4, Seq1),
+%%             ?assertEqual(<<"doc3">>, Id2),
+%%             ?assertEqual(6, Seq2),
+
+%%             clear_rows(Consumer),
+%%             {ok, _Rev9} = save_doc(Db, {[{<<"_id">>, <<"doc9">>}]}),
+%%             {ok, _Rev10} = save_doc(Db, {[{<<"_id">>, <<"doc10">>}]}),
+%%             unpause(Consumer),
+%%             pause(Consumer),
+%%             ?assertEqual([], get_rows(Consumer)),
+
+%%             Rev4 = element(4, Revs),
+%%             Rev3_2 = element(6, Revs),
+%%             {ok, Rev4_2} = save_doc(Db, {[{<<"_id">>, <<"doc4">>},
+%%                                           {<<"_rev">>, Rev4}]}),
+%%             {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc11">>}]}),
+%%             {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc4">>},
+%%                                      {<<"_rev">>, Rev4_2}]}),
+%%             {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc12">>}]}),
+%%             {ok, Rev3_3} = save_doc(Db, {[{<<"_id">>, <<"doc3">>},
+%%                                           {<<"_rev">>, Rev3_2}]}),
+%%             unpause(Consumer),
+%%             pause(Consumer),
+
+%%             NewRows = get_rows(Consumer),
+%%             ?assertEqual(2, length(NewRows)),
+%%             [Row14, Row16] = NewRows,
+%%             ?assertEqual(<<"doc4">>, Row14#row.id),
+%%             ?assertEqual(15, Row14#row.seq),
+%%             ?assertEqual(<<"doc3">>, Row16#row.id),
+%%             ?assertEqual(17, Row16#row.seq),
+
+%%             clear_rows(Consumer),
+%%             {ok, _Rev3_4} = save_doc(Db, {[{<<"_id">>, <<"doc3">>},
+%%                                            {<<"_rev">>, Rev3_3}]}),
+%%             unpause(Consumer),
+%%             pause(Consumer),
+
+%%             FinalRows = get_rows(Consumer),
+
+%%             unpause(Consumer),
+%%             stop_consumer(Consumer),
+
+%%             ?assertMatch([#row{seq = 18, id = <<"doc3">>}], FinalRows)
+%%         end).
+
+%% should_emit_only_design_documents({DbName, Revs}) ->
+%%     ?_test(
+%%         begin
+%%             ChangesArgs = #changes_args{
+%%                 filter = "_design"
+%%             },
+%%             Consumer = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
+
+%%             {Rows, LastSeq} = wait_finished(Consumer),
+%%             {ok, Db} = couch_db:open_int(DbName, []),
+%%             UpSeq = couch_db:get_update_seq(Db),
+%%             couch_db:close(Db),
+
+%%             ?assertEqual(1, length(Rows)),
+%%             ?assertEqual(UpSeq, LastSeq),
+%%             ?assertEqual([#row{seq = 8, id = <<"_design/foo">>}], Rows),
+
+%%             stop_consumer(Consumer),
+
+%%             {ok, Db2} = couch_db:open_int(DbName, [?ADMIN_USER]),
+%%             {ok, _} = save_doc(Db2, {[{<<"_id">>, <<"_design/foo">>},
+%%                                       {<<"_rev">>, element(8, Revs)},
+%%                                       {<<"_deleted">>, true}]}),
+
+%%             Consumer2 = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
+
+%%             {Rows2, LastSeq2} = wait_finished(Consumer2),
+%%             UpSeq2 = UpSeq + 1,
+%%             couch_db:close(Db2),
+
+%%             ?assertEqual(1, length(Rows2)),
+%%             ?assertEqual(UpSeq2, LastSeq2),
+%%             ?assertEqual([#row{seq = 11,
+%%                                id = <<"_design/foo">>,
+%%                                deleted = true}],
+%%                           Rows2)
+%%         end).
+
+%% should_receive_heartbeats(_) ->
+%%     {timeout, ?TEST_TIMEOUT div 1000,
+%%      ?_test(
+%%          begin
+%%              DbName = ?tempdb(),
+%%              Timeout = 100,
+%%              {ok, Db} = create_db(DbName),
+
+%%              {ok, _} = save_doc(Db, {[
+%%                  {<<"_id">>, <<"_design/filtered">>},
+%%                  {<<"language">>, <<"javascript">>},
+%%                      {<<"filters">>, {[
+%%                          {<<"foo">>, <<"function(doc) {
+%%                              return ['doc10', 'doc11', 'doc12'].indexOf(doc._id) != -1;}">>
+%%                      }]}}
+%%              ]}),
+
+%%              ChangesArgs = #changes_args{
+%%                  filter = "filtered/foo",
+%%                  feed = "continuous",
+%%                  timeout = 10000,
+%%                  heartbeat = 1000
+%%              },
+%%              Consumer = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
+
+%%              {ok, _Rev1} = save_doc(Db, {[{<<"_id">>, <<"doc1">>}]}),
+%%              timer:sleep(Timeout),
+%%              {ok, _Rev2} = save_doc(Db, {[{<<"_id">>, <<"doc2">>}]}),
+%%              timer:sleep(Timeout),
+%%              {ok, _Rev3} = save_doc(Db, {[{<<"_id">>, <<"doc3">>}]}),
+%%              timer:sleep(Timeout),
+%%              {ok, _Rev4} = save_doc(Db, {[{<<"_id">>, <<"doc4">>}]}),
+%%              timer:sleep(Timeout),
+%%              {ok, _Rev5} = save_doc(Db, {[{<<"_id">>, <<"doc5">>}]}),
+%%              timer:sleep(Timeout),
+%%              {ok, _Rev6} = save_doc(Db, {[{<<"_id">>, <<"doc6">>}]}),
+%%              timer:sleep(Timeout),
+%%              {ok, _Rev7} = save_doc(Db, {[{<<"_id">>, <<"doc7">>}]}),
+%%              timer:sleep(Timeout),
+%%              {ok, _Rev8} = save_doc(Db, {[{<<"_id">>, <<"doc8">>}]}),
+%%              timer:sleep(Timeout),
+%%              {ok, _Rev9} = save_doc(Db, {[{<<"_id">>, <<"doc9">>}]}),
+
+%%              Heartbeats = get_heartbeats(Consumer),
+%%              ?assert(Heartbeats > 0),
+
+%%              {ok, _Rev10} = save_doc(Db, {[{<<"_id">>, <<"doc10">>}]}),
+%%              timer:sleep(Timeout),
+%%              {ok, _Rev11} = save_doc(Db, {[{<<"_id">>, <<"doc11">>}]}),
+%%              timer:sleep(Timeout),
+%%              {ok, _Rev12} = save_doc(Db, {[{<<"_id">>, <<"doc12">>}]}),
+
+%%              Heartbeats2 = get_heartbeats(Consumer),
+%%              ?assert(Heartbeats2 > Heartbeats),
+
+%%              Rows = get_rows(Consumer),
+%%              ?assertEqual(3, length(Rows)),
+
+%%              {ok, _Rev13} = save_doc(Db, {[{<<"_id">>, <<"doc13">>}]}),
+%%              timer:sleep(Timeout),
+%%              {ok, _Rev14} = save_doc(Db, {[{<<"_id">>, <<"doc14">>}]}),
+%%              timer:sleep(Timeout),
+
+%%              Heartbeats3 = get_heartbeats(Consumer),
+%%              ?assert(Heartbeats3 > Heartbeats2)
+%%         end)}.
+
+
+%% save_doc(Db, Json) ->
+%%     Doc = couch_doc:from_json_obj(Json),
+%%     ?debugFmt("~n~nSAVING DOC: ~p~n", [Doc]),
+%%     {ok, Rev} = couch_db:update_doc(Db, Doc, []),
+%%     ?debugFmt("GOT REV: ~p~n", [Rev]),
+%%     {ok, couch_doc:rev_to_str(Rev)}.
+
+%% get_rows(Consumer) ->
+%%     Ref = make_ref(),
+%%     Consumer ! {get_rows, Ref},
+%%     Resp = receive
+%%         {rows, Ref, Rows} ->
+%%             Rows
+%%     after ?TIMEOUT ->
+%%         timeout
+%%     end,
+%%     ?assertNotEqual(timeout, Resp),
+%%     Resp.
+
+%% get_heartbeats(Consumer) ->
+%%     Ref = make_ref(),
+%%     Consumer ! {get_heartbeats, Ref},
+%%     Resp = receive
+%%         {hearthbeats, Ref, HeartBeats} ->
+%%             HeartBeats
+%%     after ?TIMEOUT ->
+%%         timeout
+%%     end,
+%%     ?assertNotEqual(timeout, Resp),
+%%     Resp.
+
+%% clear_rows(Consumer) ->
+%%     Ref = make_ref(),
+%%     Consumer ! {reset, Ref},
+%%     Resp = receive
+%%         {ok, Ref} ->
+%%             ok
+%%     after ?TIMEOUT ->
+%%         timeout
+%%     end,
+%%     ?assertNotEqual(timeout, Resp),
+%%     Resp.
+
+%% stop_consumer(Consumer) ->
+%%     Ref = make_ref(),
+%%     Consumer ! {stop, Ref},
+%%     Resp = receive
+%%         {ok, Ref} ->
+%%             ok
+%%     after ?TIMEOUT ->
+%%         timeout
+%%     end,
+%%     ?assertNotEqual(timeout, Resp),
+%%     Resp.
+
+%% pause(Consumer) ->
+%%     Ref = make_ref(),
+%%     Consumer ! {pause, Ref},
+%%     Resp = receive
+%%         {paused, Ref} ->
+%%             ok
+%%     after ?TIMEOUT ->
+%%         timeout
+%%     end,
+%%     ?assertNotEqual(timeout, Resp),
+%%     Resp.
+
+%% unpause(Consumer) ->
+%%     Ref = make_ref(),
+%%     Consumer ! {continue, Ref},
+%%     Resp = receive
+%%         {ok, Ref} ->
+%%             ok
+%%     after ?TIMEOUT ->
+%%        timeout
+%%     end,
+%%     ?assertNotEqual(timeout, Resp),
+%%     Resp.
+
+%% wait_finished(_Consumer) ->
+%%     Resp = receive
+%%         {consumer_finished, Rows, LastSeq} ->
+%%             {Rows, LastSeq}
+%%     after ?TIMEOUT ->
+%%         timeout
+%%     end,
+%%     ?assertNotEqual(timeout, Resp),
+%%     Resp.
+
+%% spawn_consumer(DbName, ChangesArgs0, Req) ->
+%%     Parent = self(),
+%%     spawn(fun() ->
+%%         put(heartbeat_count, 0),
+%%         Callback = fun
+%%             ({change, {Change}, _}, _, Acc) ->
+%%                 Id = couch_util:get_value(<<"id">>, Change),
+%%                 Seq = couch_util:get_value(<<"seq">>, Change),
+%%                 Del = couch_util:get_value(<<"deleted">>, Change, false),
+%%                 [#row{id = Id, seq = Seq, deleted = Del} | Acc];
+%%             ({stop, LastSeq}, _, Acc) ->
+%%                 Parent ! {consumer_finished, lists:reverse(Acc), LastSeq},
+%%                 stop_loop(Parent, Acc);
+%%             (timeout, _, Acc) ->
+%%                 put(heartbeat_count, get(heartbeat_count) + 1),
+%%                 maybe_pause(Parent, Acc);
+%%             (_, _, Acc) ->
+%%                 maybe_pause(Parent, Acc)
+%%         end,
+%%         {ok, Db} = couch_db:open_int(DbName, []),
+%%         ChangesArgs = case (ChangesArgs0#changes_args.timeout =:= undefined)
+%%             andalso (ChangesArgs0#changes_args.heartbeat =:= undefined) of
+%%             true ->
+%%                 ChangesArgs0#changes_args{timeout = 10, heartbeat = 10};
+%%             false ->
+%%                 ChangesArgs0
+%%         end,
+%%         FeedFun = couch_changes:handle_changes(ChangesArgs, Req, Db),
+%%         try
+%%             FeedFun({Callback, []})
+%%         catch throw:{stop, _} ->
+%%             ok
+%%         end,
+%%         catch couch_db:close(Db)
+%%     end).
+
+%% maybe_pause(Parent, Acc) ->
+%%     receive
+%%         {get_rows, Ref} ->
+%%             Parent ! {rows, Ref, lists:reverse(Acc)},
+%%             maybe_pause(Parent, Acc);
+%%         {get_heartbeats, Ref} ->
+%%             Parent ! {hearthbeats, Ref, get(heartbeat_count)},
+%%             maybe_pause(Parent, Acc);
+%%         {reset, Ref} ->
+%%             Parent ! {ok, Ref},
+%%             maybe_pause(Parent, []);
+%%         {pause, Ref} ->
+%%             Parent ! {paused, Ref},
+%%             pause_loop(Parent, Acc);
+%%         {stop, Ref} ->
+%%             Parent ! {ok, Ref},
+%%             throw({stop, Acc});
+%%         V ->
+%%             erlang:error({assertion_failed,
+%%                       [{module, ?MODULE},
+%%                        {line, ?LINE},
+%%                        {value, V},
+%%                        {reason, "Received unexpected message"}]})
+%%     after 0 ->
+%%         Acc
+%%     end.
+
+%% pause_loop(Parent, Acc) ->
+%%     receive
+%%         {stop, Ref} ->
+%%             Parent ! {ok, Ref},
+%%             throw({stop, Acc});
+%%         {reset, Ref} ->
+%%             Parent ! {ok, Ref},
+%%             pause_loop(Parent, []);
+%%         {continue, Ref} ->
+%%             Parent ! {ok, Ref},
+%%             Acc;
+%%         {get_rows, Ref} ->
+%%             Parent ! {rows, Ref, lists:reverse(Acc)},
+%%             pause_loop(Parent, Acc)
+%%     end.
+
+%% stop_loop(Parent, Acc) ->
+%%     receive
+%%         {get_rows, Ref} ->
+%%             Parent ! {rows, Ref, lists:reverse(Acc)},
+%%             stop_loop(Parent, Acc);
+%%         {stop, Ref} ->
+%%             Parent ! {ok, Ref},
+%%             Acc
+%%     end.
+
+%% create_db(DbName) ->
+%%     couch_db:create(DbName, [?ADMIN_USER, overwrite]).
+
+%% delete_db(DbName) ->
+%%     ok = couch_server:delete(DbName, [?ADMIN_USER]).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/6179af60/test/couch_stats_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_stats_tests.erl b/test/couch_stats_tests.erl
index d62afaf..dfb3d0b 100644
--- a/test/couch_stats_tests.erl
+++ b/test/couch_stats_tests.erl
@@ -23,390 +23,390 @@
 -define(TIMEWAIT, 500).
 
 
-setup_collector() ->
-    couch_stats_collector:start(),
-    ok.
-
-setup_aggregator(_) ->
-    {ok, Pid} = config:start_link([?STATS_INI_FIXTURE]),
-    {ok, _} = couch_stats_collector:start(),
-    {ok, _} = couch_stats_aggregator:start(?STATS_CFG_FIXTURE),
-    Pid.
-
-teardown_collector(_) ->
-    couch_stats_collector:stop(),
-    ok.
-
-teardown_aggregator(_, Pid) ->
-    couch_stats_aggregator:stop(),
-    couch_stats_collector:stop(),
-    erlang:monitor(process, Pid),
-    config:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, config_stop})
-    end,
-    ok.
-
-
-couch_stats_collector_test_() ->
-    {
-        "CouchDB stats collector tests",
-        {
-            foreach,
-            fun setup_collector/0, fun teardown_collector/1,
-            [
-                should_increment_counter(),
-                should_decrement_counter(),
-                should_increment_and_decrement_counter(),
-                should_record_absolute_values(),
-                should_clear_absolute_values(),
-                should_track_process_count(),
-                should_increment_counter_multiple_times_per_pid(),
-                should_decrement_counter_on_process_exit(),
-                should_decrement_for_each_track_process_count_call_on_exit(),
-                should_return_all_counters_and_absolute_values(),
-                should_return_incremental_counters(),
-                should_return_absolute_values()
-            ]
-        }
-    }.
-
-couch_stats_aggregator_test_() ->
-    Funs = [
-        fun should_init_empty_aggregate/2,
-        fun should_get_empty_aggregate/2,
-        fun should_change_stats_on_values_add/2,
-        fun should_change_stats_for_all_times_on_values_add/2,
-        fun should_change_stats_on_values_change/2,
-        fun should_change_stats_for_all_times_on_values_change/2,
-        fun should_not_remove_data_after_some_time_for_0_sample/2,
-        fun should_remove_data_after_some_time_for_other_samples/2
-    ],
-    {
-        "CouchDB stats aggregator tests",
-        [
-            {
-                "Absolute values",
-                {
-                    foreachx,
-                    fun setup_aggregator/1, fun teardown_aggregator/2,
-                    [{absolute, Fun} || Fun <- Funs]
-                }
-            },
-            {
-                "Counters",
-                {
-                    foreachx,
-                    fun setup_aggregator/1, fun teardown_aggregator/2,
-                    [{counter, Fun} || Fun <- Funs]
-                }
-            }
-        ]
-    }.
-
-
-should_increment_counter() ->
-    ?_assertEqual(100,
-        begin
-            AddCount = fun() -> couch_stats_collector:increment(foo) end,
-            repeat(AddCount, 100),
-            couch_stats_collector:get(foo)
-        end).
-
-should_decrement_counter() ->
-    ?_assertEqual(67,
-        begin
-            AddCount = fun() -> couch_stats_collector:increment(foo) end,
-            RemCount = fun() -> couch_stats_collector:decrement(foo) end,
-            repeat(AddCount, 100),
-            repeat(RemCount, 33),
-            couch_stats_collector:get(foo)
-        end).
-
-should_increment_and_decrement_counter() ->
-    ?_assertEqual(0,
-        begin
-            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),
-            repeat(RemCount, 80),
-            couch_stats_collector:get(foo)
-        end).
-
-should_record_absolute_values() ->
-    ?_assertEqual(lists:seq(1, 15),
-        begin
-            lists:map(fun(Val) ->
-                couch_stats_collector:record(bar, Val)
-            end, lists:seq(1, 15)),
-            couch_stats_collector:get(bar)
-        end).
-
-should_clear_absolute_values() ->
-    ?_assertEqual(nil,
-        begin
-            lists:map(fun(Val) ->
-                couch_stats_collector:record(bar, Val)
-            end, lists:seq(1, 15)),
-            couch_stats_collector:clear(bar),
-            couch_stats_collector:get(bar)
-        end).
-
-should_track_process_count() ->
-    ?_assertMatch({_, 1}, spawn_and_count(1)).
-
-should_increment_counter_multiple_times_per_pid() ->
-    ?_assertMatch({_, 3}, spawn_and_count(3)).
-
-should_decrement_counter_on_process_exit() ->
-    ?_assertEqual(2,
-        begin
-            {Pid, 1} = spawn_and_count(1),
-            spawn_and_count(2),
-            RefMon = erlang:monitor(process, Pid),
-            Pid ! sepuku,
-            receive
-                {'DOWN', RefMon, _, _, _} -> ok
-            after ?TIMEOUT ->
-                throw(timeout)
-            end,
-            % sleep for awhile to let collector handle the updates
-            % suddenly, it couldn't notice process death instantly
-            timer:sleep(?TIMEWAIT),
-            couch_stats_collector:get(hoopla)
-        end).
-
-should_decrement_for_each_track_process_count_call_on_exit() ->
-    ?_assertEqual(2,
-        begin
-            {_, 2} = spawn_and_count(2),
-            {Pid, 6} = spawn_and_count(4),
-            RefMon = erlang:monitor(process, Pid),
-            Pid ! sepuku,
-            receive
-                {'DOWN', RefMon, _, _, _} -> ok
-            after ?TIMEOUT ->
-                throw(timeout)
-            end,
-            timer:sleep(?TIMEWAIT),
-            couch_stats_collector:get(hoopla)
-        end).
-
-should_return_all_counters_and_absolute_values() ->
-    ?_assertEqual([{bar,[1.0,0.0]}, {foo,1}],
-        begin
-            couch_stats_collector:record(bar, 0.0),
-            couch_stats_collector:record(bar, 1.0),
-            couch_stats_collector:increment(foo),
-            lists:sort(couch_stats_collector:all())
-        end).
-
-should_return_incremental_counters() ->
-    ?_assertEqual([{foo,1}],
-        begin
-            couch_stats_collector:record(bar, 0.0),
-            couch_stats_collector:record(bar, 1.0),
-            couch_stats_collector:increment(foo),
-            lists:sort(couch_stats_collector:all(incremental))
-        end).
-
-should_return_absolute_values() ->
-    ?_assertEqual([{bar,[1.0,0.0]}, {zing, "Z"}],
-        begin
-            couch_stats_collector:record(bar, 0.0),
-            couch_stats_collector:record(bar, 1.0),
-            couch_stats_collector:record(zing, 90),
-            couch_stats_collector:increment(foo),
-            lists:sort(couch_stats_collector:all(absolute))
-        end).
-
-should_init_empty_aggregate(absolute, _) ->
-    {Aggs} = couch_stats_aggregator:all(),
-    ?_assertEqual({[{'11', make_agg(<<"randomosity">>,
-                                    null, null, null, null, null)}]},
-                  couch_util:get_value(number, Aggs));
-should_init_empty_aggregate(counter, _) ->
-    {Aggs} = couch_stats_aggregator:all(),
-    ?_assertEqual({[{stuff, make_agg(<<"yay description">>,
-                                     null, null, null, null, null)}]},
-                  couch_util:get_value(testing, Aggs)).
-
-should_get_empty_aggregate(absolute, _) ->
-    ?_assertEqual(make_agg(<<"randomosity">>, null, null, null, null, null),
-             couch_stats_aggregator:get_json({number, '11'}));
-should_get_empty_aggregate(counter, _) ->
-    ?_assertEqual(make_agg(<<"yay description">>, null, null, null, null, null),
-             couch_stats_aggregator:get_json({testing, stuff})).
-
-should_change_stats_on_values_add(absolute, _) ->
-    lists:foreach(fun(X) ->
-        couch_stats_collector:record({number, 11}, X)
-    end, lists:seq(0, 10)),
-    couch_stats_aggregator:collect_sample(),
-    ?_assertEqual(make_agg(<<"randomosity">>, 5.0, 5.0, null, 5.0, 5.0),
-                  couch_stats_aggregator:get_json({number, 11}));
-should_change_stats_on_values_add(counter, _) ->
-    lists:foreach(fun(_) ->
-        couch_stats_collector:increment({testing, stuff})
-    end, lists:seq(1, 100)),
-    couch_stats_aggregator:collect_sample(),
-    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 100.0, null, 100, 100),
-                  couch_stats_aggregator:get_json({testing, stuff})).
-
-should_change_stats_for_all_times_on_values_add(absolute, _) ->
-    lists:foreach(fun(X) ->
-        couch_stats_collector:record({number, 11}, X)
-    end, lists:seq(0, 10)),
-    couch_stats_aggregator:collect_sample(),
-    ?_assertEqual(make_agg(<<"randomosity">>, 5.0, 5.0, null, 5.0, 5.0),
-                  couch_stats_aggregator:get_json({number, 11}, 1));
-should_change_stats_for_all_times_on_values_add(counter, _) ->
-    lists:foreach(fun(_) ->
-        couch_stats_collector:increment({testing, stuff})
-    end, lists:seq(1, 100)),
-    couch_stats_aggregator:collect_sample(),
-    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 100.0, null, 100, 100),
-                  couch_stats_aggregator:get_json({testing, stuff}, 1)).
-
-should_change_stats_on_values_change(absolute, _) ->
-    ?_assertEqual(make_agg(<<"randomosity">>, 20.0, 10.0, 7.071, 5.0, 15.0),
-        begin
-            lists:foreach(fun(X) ->
-                couch_stats_collector:record({number, 11}, X)
-            end, lists:seq(0, 10)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_collector:record({number, 11}, 15),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({number, 11})
-        end);
-should_change_stats_on_values_change(counter, _) ->
-    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 50.0, 70.711, 0, 100),
-        begin
-            lists:foreach(fun(_) ->
-                couch_stats_collector:increment({testing, stuff})
-            end, lists:seq(1, 100)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({testing, stuff})
-        end).
-
-should_change_stats_for_all_times_on_values_change(absolute, _) ->
-    ?_assertEqual(make_agg(<<"randomosity">>, 20.0, 10.0, 7.071, 5.0, 15.0),
-        begin
-            lists:foreach(fun(X) ->
-                couch_stats_collector:record({number, 11}, X)
-            end, lists:seq(0, 10)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_collector:record({number, 11}, 15),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({number, 11}, 1)
-        end);
-should_change_stats_for_all_times_on_values_change(counter, _) ->
-    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 50.0, 70.711, 0, 100),
-        begin
-            lists:foreach(fun(_) ->
-                couch_stats_collector:increment({testing, stuff})
-            end, lists:seq(1, 100)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({testing, stuff}, 1)
-        end).
-
-should_not_remove_data_after_some_time_for_0_sample(absolute, _) ->
-    ?_assertEqual(make_agg(<<"randomosity">>, 20.0, 10.0, 7.071, 5.0, 15.0),
-        begin
-            lists:foreach(fun(X) ->
-                couch_stats_collector:record({number, 11}, X)
-            end, lists:seq(0, 10)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_collector:record({number, 11}, 15),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({number, 11})
-        end);
-should_not_remove_data_after_some_time_for_0_sample(counter, _) ->
-    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 33.333, 57.735, 0, 100),
-        begin
-            lists:foreach(fun(_) ->
-                couch_stats_collector:increment({testing, stuff})
-            end, lists:seq(1, 100)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({testing, stuff})
-        end).
-
-should_remove_data_after_some_time_for_other_samples(absolute, _) ->
-    ?_assertEqual(make_agg(<<"randomosity">>, 15.0, 15.0, null, 15.0, 15.0),
-        begin
-            lists:foreach(fun(X) ->
-                couch_stats_collector:record({number, 11}, X)
-            end, lists:seq(0, 10)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_collector:record({number, 11}, 15),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({number, 11}, 1)
-        end);
-should_remove_data_after_some_time_for_other_samples(counter, _) ->
-    ?_assertEqual(make_agg(<<"yay description">>, 0, 0.0, 0.0, 0, 0),
-        begin
-            lists:foreach(fun(_) ->
-                couch_stats_collector:increment({testing, stuff})
-            end, lists:seq(1, 100)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({testing, stuff}, 1)
-        end).
-
-
-spawn_and_count(N) ->
-    Self = self(),
-    Pid = spawn(fun() ->
-        lists:foreach(
-            fun(_) ->
-                couch_stats_collector:track_process_count(hoopla)
-            end, lists:seq(1,N)),
-        Self ! reporting,
-        receive
-            sepuku -> ok
-        end
-    end),
-    receive reporting -> ok end,
-    {Pid, couch_stats_collector:get(hoopla)}.
-
-repeat(_, 0) ->
-    ok;
-repeat(Fun, Count) ->
-    Fun(),
-    repeat(Fun, Count-1).
-
-make_agg(Desc, Sum, Mean, StdDev, Min, Max) ->
-    {[
-        {description, Desc},
-        {current, Sum},
-        {sum, Sum},
-        {mean, Mean},
-        {stddev, StdDev},
-        {min, Min},
-        {max, Max}
-    ]}.
+%% setup_collector() ->
+%%     couch_stats_collector:start(),
+%%     ok.
+
+%% setup_aggregator(_) ->
+%%     {ok, Pid} = test_util:start_config([?STATS_INI_FIXTURE]),
+%%     {ok, _} = couch_stats_collector:start(),
+%%     {ok, _} = couch_stats_aggregator:start(?STATS_CFG_FIXTURE),
+%%     Pid.
+
+%% teardown_collector(_) ->
+%%     couch_stats_collector:stop(),
+%%     ok.
+
+%% teardown_aggregator(_, Pid) ->
+%%     couch_stats_aggregator:stop(),
+%%     couch_stats_collector:stop(),
+%%     erlang:monitor(process, Pid),
+%%     config:stop(),
+%%     receive
+%%         {'DOWN', _, _, Pid, _} ->
+%%             ok
+%%     after ?TIMEOUT ->
+%%         throw({timeout, config_stop})
+%%     end,
+%%     ok.
+
+
+%% couch_stats_collector_test_() ->
+%%     {
+%%         "CouchDB stats collector tests",
+%%         {
+%%             foreach,
+%%             fun setup_collector/0, fun teardown_collector/1,
+%%             [
+%%                 should_increment_counter(),
+%%                 should_decrement_counter(),
+%%                 should_increment_and_decrement_counter(),
+%%                 should_record_absolute_values(),
+%%                 should_clear_absolute_values(),
+%%                 should_track_process_count(),
+%%                 should_increment_counter_multiple_times_per_pid(),
+%%                 should_decrement_counter_on_process_exit(),
+%%                 should_decrement_for_each_track_process_count_call_on_exit(),
+%%                 should_return_all_counters_and_absolute_values(),
+%%                 should_return_incremental_counters(),
+%%                 should_return_absolute_values()
+%%             ]
+%%         }
+%%     }.
+
+%% couch_stats_aggregator_test_() ->
+%%     Funs = [
+%%         fun should_init_empty_aggregate/2,
+%%         fun should_get_empty_aggregate/2,
+%%         fun should_change_stats_on_values_add/2,
+%%         fun should_change_stats_for_all_times_on_values_add/2,
+%%         fun should_change_stats_on_values_change/2,
+%%         fun should_change_stats_for_all_times_on_values_change/2,
+%%         fun should_not_remove_data_after_some_time_for_0_sample/2,
+%%         fun should_remove_data_after_some_time_for_other_samples/2
+%%     ],
+%%     {
+%%         "CouchDB stats aggregator tests",
+%%         [
+%%             {
+%%                 "Absolute values",
+%%                 {
+%%                     foreachx,
+%%                     fun setup_aggregator/1, fun teardown_aggregator/2,
+%%                     [{absolute, Fun} || Fun <- Funs]
+%%                 }
+%%             },
+%%             {
+%%                 "Counters",
+%%                 {
+%%                     foreachx,
+%%                     fun setup_aggregator/1, fun teardown_aggregator/2,
+%%                     [{counter, Fun} || Fun <- Funs]
+%%                 }
+%%             }
+%%         ]
+%%     }.
+
+
+%% should_increment_counter() ->
+%%     ?_assertEqual(100,
+%%         begin
+%%             AddCount = fun() -> couch_stats_collector:increment(foo) end,
+%%             repeat(AddCount, 100),
+%%             couch_stats_collector:get(foo)
+%%         end).
+
+%% should_decrement_counter() ->
+%%     ?_assertEqual(67,
+%%         begin
+%%             AddCount = fun() -> couch_stats_collector:increment(foo) end,
+%%             RemCount = fun() -> couch_stats_collector:decrement(foo) end,
+%%             repeat(AddCount, 100),
+%%             repeat(RemCount, 33),
+%%             couch_stats_collector:get(foo)
+%%         end).
+
+%% should_increment_and_decrement_counter() ->
+%%     ?_assertEqual(0,
+%%         begin
+%%             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),
+%%             repeat(RemCount, 80),
+%%             couch_stats_collector:get(foo)
+%%         end).
+
+%% should_record_absolute_values() ->
+%%     ?_assertEqual(lists:seq(1, 15),
+%%         begin
+%%             lists:map(fun(Val) ->
+%%                 couch_stats_collector:record(bar, Val)
+%%             end, lists:seq(1, 15)),
+%%             couch_stats_collector:get(bar)
+%%         end).
+
+%% should_clear_absolute_values() ->
+%%     ?_assertEqual(nil,
+%%         begin
+%%             lists:map(fun(Val) ->
+%%                 couch_stats_collector:record(bar, Val)
+%%             end, lists:seq(1, 15)),
+%%             couch_stats_collector:clear(bar),
+%%             couch_stats_collector:get(bar)
+%%         end).
+
+%% should_track_process_count() ->
+%%     ?_assertMatch({_, 1}, spawn_and_count(1)).
+
+%% should_increment_counter_multiple_times_per_pid() ->
+%%     ?_assertMatch({_, 3}, spawn_and_count(3)).
+
+%% should_decrement_counter_on_process_exit() ->
+%%     ?_assertEqual(2,
+%%         begin
+%%             {Pid, 1} = spawn_and_count(1),
+%%             spawn_and_count(2),
+%%             RefMon = erlang:monitor(process, Pid),
+%%             Pid ! sepuku,
+%%             receive
+%%                 {'DOWN', RefMon, _, _, _} -> ok
+%%             after ?TIMEOUT ->
+%%                 throw(timeout)
+%%             end,
+%%             % sleep for awhile to let collector handle the updates
+%%             % suddenly, it couldn't notice process death instantly
+%%             timer:sleep(?TIMEWAIT),
+%%             couch_stats_collector:get(hoopla)
+%%         end).
+
+%% should_decrement_for_each_track_process_count_call_on_exit() ->
+%%     ?_assertEqual(2,
+%%         begin
+%%             {_, 2} = spawn_and_count(2),
+%%             {Pid, 6} = spawn_and_count(4),
+%%             RefMon = erlang:monitor(process, Pid),
+%%             Pid ! sepuku,
+%%             receive
+%%                 {'DOWN', RefMon, _, _, _} -> ok
+%%             after ?TIMEOUT ->
+%%                 throw(timeout)
+%%             end,
+%%             timer:sleep(?TIMEWAIT),
+%%             couch_stats_collector:get(hoopla)
+%%         end).
+
+%% should_return_all_counters_and_absolute_values() ->
+%%     ?_assertEqual([{bar,[1.0,0.0]}, {foo,1}],
+%%         begin
+%%             couch_stats_collector:record(bar, 0.0),
+%%             couch_stats_collector:record(bar, 1.0),
+%%             couch_stats_collector:increment(foo),
+%%             lists:sort(couch_stats_collector:all())
+%%         end).
+
+%% should_return_incremental_counters() ->
+%%     ?_assertEqual([{foo,1}],
+%%         begin
+%%             couch_stats_collector:record(bar, 0.0),
+%%             couch_stats_collector:record(bar, 1.0),
+%%             couch_stats_collector:increment(foo),
+%%             lists:sort(couch_stats_collector:all(incremental))
+%%         end).
+
+%% should_return_absolute_values() ->
+%%     ?_assertEqual([{bar,[1.0,0.0]}, {zing, "Z"}],
+%%         begin
+%%             couch_stats_collector:record(bar, 0.0),
+%%             couch_stats_collector:record(bar, 1.0),
+%%             couch_stats_collector:record(zing, 90),
+%%             couch_stats_collector:increment(foo),
+%%             lists:sort(couch_stats_collector:all(absolute))
+%%         end).
+
+%% should_init_empty_aggregate(absolute, _) ->
+%%     {Aggs} = couch_stats_aggregator:all(),
+%%     ?_assertEqual({[{'11', make_agg(<<"randomosity">>,
+%%                                     null, null, null, null, null)}]},
+%%                   couch_util:get_value(number, Aggs));
+%% should_init_empty_aggregate(counter, _) ->
+%%     {Aggs} = couch_stats_aggregator:all(),
+%%     ?_assertEqual({[{stuff, make_agg(<<"yay description">>,
+%%                                      null, null, null, null, null)}]},
+%%                   couch_util:get_value(testing, Aggs)).
+
+%% should_get_empty_aggregate(absolute, _) ->
+%%     ?_assertEqual(make_agg(<<"randomosity">>, null, null, null, null, null),
+%%              couch_stats_aggregator:get_json({number, '11'}));
+%% should_get_empty_aggregate(counter, _) ->
+%%     ?_assertEqual(make_agg(<<"yay description">>, null, null, null, null, null),
+%%              couch_stats_aggregator:get_json({testing, stuff})).
+
+%% should_change_stats_on_values_add(absolute, _) ->
+%%     lists:foreach(fun(X) ->
+%%         couch_stats_collector:record({number, 11}, X)
+%%     end, lists:seq(0, 10)),
+%%     couch_stats_aggregator:collect_sample(),
+%%     ?_assertEqual(make_agg(<<"randomosity">>, 5.0, 5.0, null, 5.0, 5.0),
+%%                   couch_stats_aggregator:get_json({number, 11}));
+%% should_change_stats_on_values_add(counter, _) ->
+%%     lists:foreach(fun(_) ->
+%%         couch_stats_collector:increment({testing, stuff})
+%%     end, lists:seq(1, 100)),
+%%     couch_stats_aggregator:collect_sample(),
+%%     ?_assertEqual(make_agg(<<"yay description">>, 100.0, 100.0, null, 100, 100),
+%%                   couch_stats_aggregator:get_json({testing, stuff})).
+
+%% should_change_stats_for_all_times_on_values_add(absolute, _) ->
+%%     lists:foreach(fun(X) ->
+%%         couch_stats_collector:record({number, 11}, X)
+%%     end, lists:seq(0, 10)),
+%%     couch_stats_aggregator:collect_sample(),
+%%     ?_assertEqual(make_agg(<<"randomosity">>, 5.0, 5.0, null, 5.0, 5.0),
+%%                   couch_stats_aggregator:get_json({number, 11}, 1));
+%% should_change_stats_for_all_times_on_values_add(counter, _) ->
+%%     lists:foreach(fun(_) ->
+%%         couch_stats_collector:increment({testing, stuff})
+%%     end, lists:seq(1, 100)),
+%%     couch_stats_aggregator:collect_sample(),
+%%     ?_assertEqual(make_agg(<<"yay description">>, 100.0, 100.0, null, 100, 100),
+%%                   couch_stats_aggregator:get_json({testing, stuff}, 1)).
+
+%% should_change_stats_on_values_change(absolute, _) ->
+%%     ?_assertEqual(make_agg(<<"randomosity">>, 20.0, 10.0, 7.071, 5.0, 15.0),
+%%         begin
+%%             lists:foreach(fun(X) ->
+%%                 couch_stats_collector:record({number, 11}, X)
+%%             end, lists:seq(0, 10)),
+%%             couch_stats_aggregator:collect_sample(),
+%%             timer:sleep(?TIMEWAIT),
+%%             couch_stats_collector:record({number, 11}, 15),
+%%             couch_stats_aggregator:collect_sample(),
+%%             couch_stats_aggregator:get_json({number, 11})
+%%         end);
+%% should_change_stats_on_values_change(counter, _) ->
+%%     ?_assertEqual(make_agg(<<"yay description">>, 100.0, 50.0, 70.711, 0, 100),
+%%         begin
+%%             lists:foreach(fun(_) ->
+%%                 couch_stats_collector:increment({testing, stuff})
+%%             end, lists:seq(1, 100)),
+%%             couch_stats_aggregator:collect_sample(),
+%%             timer:sleep(?TIMEWAIT),
+%%             couch_stats_aggregator:collect_sample(),
+%%             couch_stats_aggregator:get_json({testing, stuff})
+%%         end).
+
+%% should_change_stats_for_all_times_on_values_change(absolute, _) ->
+%%     ?_assertEqual(make_agg(<<"randomosity">>, 20.0, 10.0, 7.071, 5.0, 15.0),
+%%         begin
+%%             lists:foreach(fun(X) ->
+%%                 couch_stats_collector:record({number, 11}, X)
+%%             end, lists:seq(0, 10)),
+%%             couch_stats_aggregator:collect_sample(),
+%%             timer:sleep(?TIMEWAIT),
+%%             couch_stats_collector:record({number, 11}, 15),
+%%             couch_stats_aggregator:collect_sample(),
+%%             couch_stats_aggregator:get_json({number, 11}, 1)
+%%         end);
+%% should_change_stats_for_all_times_on_values_change(counter, _) ->
+%%     ?_assertEqual(make_agg(<<"yay description">>, 100.0, 50.0, 70.711, 0, 100),
+%%         begin
+%%             lists:foreach(fun(_) ->
+%%                 couch_stats_collector:increment({testing, stuff})
+%%             end, lists:seq(1, 100)),
+%%             couch_stats_aggregator:collect_sample(),
+%%             timer:sleep(?TIMEWAIT),
+%%             couch_stats_aggregator:collect_sample(),
+%%             couch_stats_aggregator:get_json({testing, stuff}, 1)
+%%         end).
+
+%% should_not_remove_data_after_some_time_for_0_sample(absolute, _) ->
+%%     ?_assertEqual(make_agg(<<"randomosity">>, 20.0, 10.0, 7.071, 5.0, 15.0),
+%%         begin
+%%             lists:foreach(fun(X) ->
+%%                 couch_stats_collector:record({number, 11}, X)
+%%             end, lists:seq(0, 10)),
+%%             couch_stats_aggregator:collect_sample(),
+%%             timer:sleep(?TIMEWAIT),
+%%             couch_stats_collector:record({number, 11}, 15),
+%%             couch_stats_aggregator:collect_sample(),
+%%             timer:sleep(?TIMEWAIT),
+%%             couch_stats_aggregator:collect_sample(),
+%%             couch_stats_aggregator:get_json({number, 11})
+%%         end);
+%% should_not_remove_data_after_some_time_for_0_sample(counter, _) ->
+%%     ?_assertEqual(make_agg(<<"yay description">>, 100.0, 33.333, 57.735, 0, 100),
+%%         begin
+%%             lists:foreach(fun(_) ->
+%%                 couch_stats_collector:increment({testing, stuff})
+%%             end, lists:seq(1, 100)),
+%%             couch_stats_aggregator:collect_sample(),
+%%             timer:sleep(?TIMEWAIT),
+%%             couch_stats_aggregator:collect_sample(),
+%%             timer:sleep(?TIMEWAIT),
+%%             couch_stats_aggregator:collect_sample(),
+%%             couch_stats_aggregator:get_json({testing, stuff})
+%%         end).
+
+%% should_remove_data_after_some_time_for_other_samples(absolute, _) ->
+%%     ?_assertEqual(make_agg(<<"randomosity">>, 15.0, 15.0, null, 15.0, 15.0),
+%%         begin
+%%             lists:foreach(fun(X) ->
+%%                 couch_stats_collector:record({number, 11}, X)
+%%             end, lists:seq(0, 10)),
+%%             couch_stats_aggregator:collect_sample(),
+%%             timer:sleep(?TIMEWAIT),
+%%             couch_stats_collector:record({number, 11}, 15),
+%%             couch_stats_aggregator:collect_sample(),
+%%             timer:sleep(?TIMEWAIT),
+%%             couch_stats_aggregator:collect_sample(),
+%%             couch_stats_aggregator:get_json({number, 11}, 1)
+%%         end);
+%% should_remove_data_after_some_time_for_other_samples(counter, _) ->
+%%     ?_assertEqual(make_agg(<<"yay description">>, 0, 0.0, 0.0, 0, 0),
+%%         begin
+%%             lists:foreach(fun(_) ->
+%%                 couch_stats_collector:increment({testing, stuff})
+%%             end, lists:seq(1, 100)),
+%%             couch_stats_aggregator:collect_sample(),
+%%             timer:sleep(?TIMEWAIT),
+%%             couch_stats_aggregator:collect_sample(),
+%%             timer:sleep(?TIMEWAIT),
+%%             couch_stats_aggregator:collect_sample(),
+%%             couch_stats_aggregator:get_json({testing, stuff}, 1)
+%%         end).
+
+
+%% spawn_and_count(N) ->
+%%     Self = self(),
+%%     Pid = spawn(fun() ->
+%%         lists:foreach(
+%%             fun(_) ->
+%%                 couch_stats_collector:track_process_count(hoopla)
+%%             end, lists:seq(1,N)),
+%%         Self ! reporting,
+%%         receive
+%%             sepuku -> ok
+%%         end
+%%     end),
+%%     receive reporting -> ok end,
+%%     {Pid, couch_stats_collector:get(hoopla)}.
+
+%% repeat(_, 0) ->
+%%     ok;
+%% repeat(Fun, Count) ->
+%%     Fun(),
+%%     repeat(Fun, Count-1).
+
+%% make_agg(Desc, Sum, Mean, StdDev, Min, Max) ->
+%%     {[
+%%         {description, Desc},
+%%         {current, Sum},
+%%         {sum, Sum},
+%%         {mean, Mean},
+%%         {stddev, StdDev},
+%%         {min, Min},
+%%         {max, Max}
+%%     ]}.


[45/50] [abbrv] WIP: Disable problematic tests

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/6179af60/test/couchdb_os_proc_pool.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_os_proc_pool.erl b/test/couchdb_os_proc_pool.erl
index a8ab752..607ccf3 100644
--- a/test/couchdb_os_proc_pool.erl
+++ b/test/couchdb_os_proc_pool.erl
@@ -18,152 +18,152 @@
 -define(TIMEOUT, 3000).
 
 
-start() ->
-    ok = test_util:start_couch(),
-    config:set("query_server_config", "os_process_limit", "3", false),
-    ok.
-
-
-os_proc_pool_test_() ->
-    {
-        "OS processes pool tests",
-        {
-            setup,
-            fun start/0, fun test_util:stop_couch/1,
-            [
-                should_block_new_proc_on_full_pool(),
-                should_free_slot_on_proc_unexpected_exit()
-            ]
-        }
-    }.
-
-
-should_block_new_proc_on_full_pool() ->
-    ?_test(begin
-        Client1 = spawn_client(),
-        Client2 = spawn_client(),
-        Client3 = spawn_client(),
-
-        ?assertEqual(ok, ping_client(Client1)),
-        ?assertEqual(ok, ping_client(Client2)),
-        ?assertEqual(ok, ping_client(Client3)),
-
-        Proc1 = get_client_proc(Client1, "1"),
-        Proc2 = get_client_proc(Client2, "2"),
-        Proc3 = get_client_proc(Client3, "3"),
-
-        ?assertNotEqual(Proc1, Proc2),
-        ?assertNotEqual(Proc2, Proc3),
-        ?assertNotEqual(Proc3, Proc1),
-
-        Client4 = spawn_client(),
-        ?assertEqual(timeout, ping_client(Client4)),
-
-        ?assertEqual(ok, stop_client(Client1)),
-        ?assertEqual(ok, ping_client(Client4)),
-
-        Proc4 = get_client_proc(Client4, "4"),
-        ?assertEqual(Proc1, Proc4),
-
-        lists:map(fun(C) ->
-            ?assertEqual(ok, stop_client(C))
-        end, [Client2, Client3, Client4])
-    end).
-
-should_free_slot_on_proc_unexpected_exit() ->
-    ?_test(begin
-        Client1 = spawn_client(),
-        Client2 = spawn_client(),
-        Client3 = spawn_client(),
-
-        ?assertEqual(ok, ping_client(Client1)),
-        ?assertEqual(ok, ping_client(Client2)),
-        ?assertEqual(ok, ping_client(Client3)),
-
-        Proc1 = get_client_proc(Client1, "1"),
-        Proc2 = get_client_proc(Client2, "2"),
-        Proc3 = get_client_proc(Client3, "3"),
-
-        ?assertNotEqual(Proc1, Proc2),
-        ?assertNotEqual(Proc2, Proc3),
-        ?assertNotEqual(Proc3, Proc1),
-
-        ?assertEqual(ok, kill_client(Client1)),
-
-        Client4 = spawn_client(),
-        ?assertEqual(ok, ping_client(Client4)),
-
-        Proc4 = get_client_proc(Client4, "4"),
-        ?assertNotEqual(Proc4, Proc1),
-        ?assertNotEqual(Proc2, Proc4),
-        ?assertNotEqual(Proc3, Proc4),
-
-        lists:map(fun(C) ->
-            ?assertEqual(ok, stop_client(C))
-        end, [Client2, Client3, Client4])
-    end).
-
-
-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 ?TIMEOUT ->
-        timeout
-    end.
-
-get_client_proc({Pid, Ref}, ClientName) ->
-    Pid ! get_proc,
-    receive
-        {proc, Ref, Proc} -> Proc
-    after ?TIMEOUT ->
-        erlang:error({assertion_failed,
-                     [{module, ?MODULE},
-                      {line, ?LINE},
-                      {reason, "Timeout getting client "
-                               ++ ClientName ++ " proc"}]})
-    end.
-
-stop_client({Pid, Ref}) ->
-    Pid ! stop,
-    receive
-        {stop, Ref} ->
-            ok
-    after ?TIMEOUT ->
-        timeout
-    end.
-
-kill_client({Pid, Ref}) ->
-    Pid ! die,
-    receive
-        {die, Ref} ->
-            ok
-    after ?TIMEOUT ->
-        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.
+%% start() ->
+%%     ok = test_util:start_couch(),
+%%     config:set("query_server_config", "os_process_limit", "3", false),
+%%     ok.
+
+
+%% os_proc_pool_test_() ->
+%%     {
+%%         "OS processes pool tests",
+%%         {
+%%             setup,
+%%             fun start/0, fun test_util:stop_couch/1,
+%%             [
+%%                 should_block_new_proc_on_full_pool(),
+%%                 should_free_slot_on_proc_unexpected_exit()
+%%             ]
+%%         }
+%%     }.
+
+
+%% should_block_new_proc_on_full_pool() ->
+%%     ?_test(begin
+%%         Client1 = spawn_client(),
+%%         Client2 = spawn_client(),
+%%         Client3 = spawn_client(),
+
+%%         ?assertEqual(ok, ping_client(Client1)),
+%%         ?assertEqual(ok, ping_client(Client2)),
+%%         ?assertEqual(ok, ping_client(Client3)),
+
+%%         Proc1 = get_client_proc(Client1, "1"),
+%%         Proc2 = get_client_proc(Client2, "2"),
+%%         Proc3 = get_client_proc(Client3, "3"),
+
+%%         ?assertNotEqual(Proc1, Proc2),
+%%         ?assertNotEqual(Proc2, Proc3),
+%%         ?assertNotEqual(Proc3, Proc1),
+
+%%         Client4 = spawn_client(),
+%%         ?assertEqual(timeout, ping_client(Client4)),
+
+%%         ?assertEqual(ok, stop_client(Client1)),
+%%         ?assertEqual(ok, ping_client(Client4)),
+
+%%         Proc4 = get_client_proc(Client4, "4"),
+%%         ?assertEqual(Proc1, Proc4),
+
+%%         lists:map(fun(C) ->
+%%             ?assertEqual(ok, stop_client(C))
+%%         end, [Client2, Client3, Client4])
+%%     end).
+
+%% should_free_slot_on_proc_unexpected_exit() ->
+%%     ?_test(begin
+%%         Client1 = spawn_client(),
+%%         Client2 = spawn_client(),
+%%         Client3 = spawn_client(),
+
+%%         ?assertEqual(ok, ping_client(Client1)),
+%%         ?assertEqual(ok, ping_client(Client2)),
+%%         ?assertEqual(ok, ping_client(Client3)),
+
+%%         Proc1 = get_client_proc(Client1, "1"),
+%%         Proc2 = get_client_proc(Client2, "2"),
+%%         Proc3 = get_client_proc(Client3, "3"),
+
+%%         ?assertNotEqual(Proc1, Proc2),
+%%         ?assertNotEqual(Proc2, Proc3),
+%%         ?assertNotEqual(Proc3, Proc1),
+
+%%         ?assertEqual(ok, kill_client(Client1)),
+
+%%         Client4 = spawn_client(),
+%%         ?assertEqual(ok, ping_client(Client4)),
+
+%%         Proc4 = get_client_proc(Client4, "4"),
+%%         ?assertNotEqual(Proc4, Proc1),
+%%         ?assertNotEqual(Proc2, Proc4),
+%%         ?assertNotEqual(Proc3, Proc4),
+
+%%         lists:map(fun(C) ->
+%%             ?assertEqual(ok, stop_client(C))
+%%         end, [Client2, Client3, Client4])
+%%     end).
+
+
+%% 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 ?TIMEOUT ->
+%%         timeout
+%%     end.
+
+%% get_client_proc({Pid, Ref}, ClientName) ->
+%%     Pid ! get_proc,
+%%     receive
+%%         {proc, Ref, Proc} -> Proc
+%%     after ?TIMEOUT ->
+%%         erlang:error({assertion_failed,
+%%                      [{module, ?MODULE},
+%%                       {line, ?LINE},
+%%                       {reason, "Timeout getting client "
+%%                                ++ ClientName ++ " proc"}]})
+%%     end.
+
+%% stop_client({Pid, Ref}) ->
+%%     Pid ! stop,
+%%     receive
+%%         {stop, Ref} ->
+%%             ok
+%%     after ?TIMEOUT ->
+%%         timeout
+%%     end.
+
+%% kill_client({Pid, Ref}) ->
+%%     Pid ! die,
+%%     receive
+%%         {die, Ref} ->
+%%             ok
+%%     after ?TIMEOUT ->
+%%         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-couch/blob/6179af60/test/couchdb_vhosts_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_vhosts_tests.erl b/test/couchdb_vhosts_tests.erl
index 321012f..addce30 100644
--- a/test/couchdb_vhosts_tests.erl
+++ b/test/couchdb_vhosts_tests.erl
@@ -20,408 +20,408 @@
 -define(iofmt(S, A), lists:flatten(io_lib:format(S, A))).
 
 
-setup() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
-    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),
-    couch_db:close(Db),
-
-    Addr = config:get("httpd", "bind_address", "127.0.0.1"),
-    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
-    Url = "http://" ++ Addr ++ ":" ++ Port,
-    {Url, ?b2l(DbName)}.
-
-setup_oauth() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
-
-    config:set("couch_httpd_auth", "authentication_db",
-                     ?b2l(?tempdb()), false),
-    config:set("oauth_token_users", "otoksec1", "joe", false),
-    config:set("oauth_consumer_secrets", "consec1", "foo", false),
-    config:set("oauth_token_secrets", "otoksec1", "foobar", false),
-    config:set("couch_httpd_auth", "require_valid_user", "true", false),
-
-    ok = config:set(
-        "vhosts", "oauth-example.com",
-        "/" ++ ?b2l(DbName) ++ "/_design/test/_rewrite/foobar", false),
-
-    DDoc = couch_doc:from_json_obj({[
-        {<<"_id">>, <<"_design/test">>},
-        {<<"language">>, <<"javascript">>},
-        {<<"rewrites">>, [
-            {[
-                {<<"from">>, <<"foobar">>},
-                {<<"to">>, <<"_info">>}
-            ]}
-        ]}
-    ]}),
-    {ok, _} = couch_db:update_doc(Db, DDoc, []),
-
-    couch_db:ensure_full_commit(Db),
-    couch_db:close(Db),
-
-    Addr = config:get("httpd", "bind_address", "127.0.0.1"),
-    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
-    Url = "http://" ++ Addr ++ ":" ++ Port,
-    {Url, ?b2l(DbName)}.
-
-teardown({_, DbName}) ->
-    ok = couch_server:delete(?l2b(DbName), []),
-    ok.
-
-
-vhosts_test_() ->
-    {
-        "Virtual Hosts rewrite tests",
-        {
-            setup,
-            fun test_util:start_couch/0, fun test_util:stop_couch/1,
-            {
-                foreach,
-                fun setup/0, fun teardown/1,
-                [
-                    fun should_return_database_info/1,
-                    fun should_return_revs_info/1,
-                    fun should_serve_utils_for_vhost/1,
-                    fun should_return_virtual_request_path_field_in_request/1,
-                    fun should_return_real_request_path_field_in_request/1,
-                    fun should_match_wildcard_vhost/1,
-                    fun should_return_db_info_for_wildcard_vhost_for_custom_db/1,
-                    fun should_replace_rewrite_variables_for_db_and_doc/1,
-                    fun should_return_db_info_for_vhost_with_resource/1,
-                    fun should_return_revs_info_for_vhost_with_resource/1,
-                    fun should_return_db_info_for_vhost_with_wildcard_resource/1,
-                    fun should_return_path_for_vhost_with_wildcard_host/1
-                ]
-            }
-        }
-    }.
-
-oauth_test_() ->
-    {
-        "Virtual Hosts OAuth tests",
-        {
-            setup,
-            fun test_util:start_couch/0, fun test_util:stop_couch/1,
-            {
-                foreach,
-                fun setup_oauth/0, fun teardown/1,
-                [
-                    fun should_require_auth/1,
-                    fun should_succeed_oauth/1,
-                    fun should_fail_oauth_with_wrong_credentials/1
-                ]
-            }
-        }
-    }.
-
-
-should_return_database_info({Url, DbName}) ->
-    ?_test(begin
-        ok = config:set("vhosts", "example.com", "/" ++ DbName, false),
-        case test_request:get(Url, [], [{host_header, "example.com"}]) of
-            {ok, _, _, Body} ->
-                {JsonBody} = ejson:decode(Body),
-                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_return_revs_info({Url, DbName}) ->
-    ?_test(begin
-        ok = config:set("vhosts", "example.com", "/" ++ DbName, false),
-        case test_request:get(Url ++ "/doc1?revs_info=true", [],
-                              [{host_header, "example.com"}]) of
-            {ok, _, _, Body} ->
-                {JsonBody} = ejson:decode(Body),
-                ?assert(proplists:is_defined(<<"_revs_info">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_serve_utils_for_vhost({Url, DbName}) ->
-    ?_test(begin
-        ok = config:set("vhosts", "example.com", "/" ++ DbName, false),
-        case test_request:get(Url ++ "/_utils/index.html", [],
-                              [{host_header, "example.com"}]) of
-            {ok, _, _, Body} ->
-                ?assertMatch(<<"<!DOCTYPE html>", _/binary>>, Body);
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_return_virtual_request_path_field_in_request({Url, DbName}) ->
-    ?_test(begin
-        ok = config:set("vhosts", "example1.com",
-                              "/" ++ DbName ++ "/_design/doc1/_rewrite/",
-                              false),
-        case test_request:get(Url, [], [{host_header, "example1.com"}]) of
-            {ok, _, _, Body} ->
-                {Json} = ejson:decode(Body),
-                ?assertEqual(<<"/">>,
-                             proplists:get_value(<<"requested_path">>, Json));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_return_real_request_path_field_in_request({Url, DbName}) ->
-    ?_test(begin
-        ok = config:set("vhosts", "example1.com",
-                              "/" ++ DbName ++ "/_design/doc1/_rewrite/",
-                              false),
-        case test_request:get(Url, [], [{host_header, "example1.com"}]) of
-            {ok, _, _, Body} ->
-                {Json} = ejson:decode(Body),
-                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
-                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_match_wildcard_vhost({Url, DbName}) ->
-    ?_test(begin
-        ok = config:set("vhosts", "*.example.com",
-                              "/" ++ DbName ++ "/_design/doc1/_rewrite", false),
-        case test_request:get(Url, [], [{host_header, "test.example.com"}]) of
-            {ok, _, _, Body} ->
-                {Json} = ejson:decode(Body),
-                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
-                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_return_db_info_for_wildcard_vhost_for_custom_db({Url, DbName}) ->
-    ?_test(begin
-        ok = config:set("vhosts", ":dbname.example1.com",
-                              "/:dbname", false),
-        Host = DbName ++ ".example1.com",
-        case test_request:get(Url, [], [{host_header, Host}]) of
-            {ok, _, _, Body} ->
-                {JsonBody} = ejson:decode(Body),
-                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_replace_rewrite_variables_for_db_and_doc({Url, DbName}) ->
-    ?_test(begin
-        ok = config:set("vhosts",":appname.:dbname.example1.com",
-                              "/:dbname/_design/:appname/_rewrite/", false),
-        Host = "doc1." ++ DbName ++ ".example1.com",
-        case test_request:get(Url, [], [{host_header, Host}]) of
-            {ok, _, _, Body} ->
-                {Json} = ejson:decode(Body),
-                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
-                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_return_db_info_for_vhost_with_resource({Url, DbName}) ->
-    ?_test(begin
-        ok = config:set("vhosts",
-                              "example.com/test", "/" ++ DbName, false),
-        ReqUrl = Url ++ "/test",
-        case test_request:get(ReqUrl, [], [{host_header, "example.com"}]) of
-            {ok, _, _, Body} ->
-                {JsonBody} = ejson:decode(Body),
-                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-
-should_return_revs_info_for_vhost_with_resource({Url, DbName}) ->
-    ?_test(begin
-        ok = config:set("vhosts",
-                              "example.com/test", "/" ++ DbName, false),
-        ReqUrl = Url ++ "/test/doc1?revs_info=true",
-        case test_request:get(ReqUrl, [], [{host_header, "example.com"}]) of
-            {ok, _, _, Body} ->
-                {JsonBody} = ejson:decode(Body),
-                ?assert(proplists:is_defined(<<"_revs_info">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_return_db_info_for_vhost_with_wildcard_resource({Url, DbName}) ->
-    ?_test(begin
-        ok = config:set("vhosts", "*.example2.com/test", "/*", false),
-        ReqUrl = Url ++ "/test",
-        Host = DbName ++ ".example2.com",
-        case test_request:get(ReqUrl, [], [{host_header, Host}]) of
-            {ok, _, _, Body} ->
-                {JsonBody} = ejson:decode(Body),
-                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_return_path_for_vhost_with_wildcard_host({Url, DbName}) ->
-    ?_test(begin
-        ok = config:set("vhosts", "*/test1",
-                              "/" ++ DbName ++ "/_design/doc1/_show/test",
-                              false),
-        case test_request:get(Url ++ "/test1") of
-            {ok, _, _, Body} ->
-                {Json} = ejson:decode(Body),
-                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
-                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_require_auth({Url, _}) ->
-    ?_test(begin
-        case test_request:get(Url, [], [{host_header, "oauth-example.com"}]) of
-            {ok, Code, _, Body} ->
-                ?assertEqual(401, Code),
-                {JsonBody} = ejson:decode(Body),
-                ?assertEqual(<<"unauthorized">>,
-                             couch_util:get_value(<<"error">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_succeed_oauth({Url, _}) ->
-    ?_test(begin
-        AuthDbName = config:get("couch_httpd_auth", "authentication_db"),
-        JoeDoc = couch_doc:from_json_obj({[
-            {<<"_id">>, <<"org.couchdb.user:joe">>},
-            {<<"type">>, <<"user">>},
-            {<<"name">>, <<"joe">>},
-            {<<"roles">>, []},
-            {<<"password_sha">>, <<"fe95df1ca59a9b567bdca5cbaf8412abd6e06121">>},
-            {<<"salt">>, <<"4e170ffeb6f34daecfd814dfb4001a73">>}
-        ]}),
-        {ok, AuthDb} = couch_db:open_int(?l2b(AuthDbName), [?ADMIN_USER]),
-        {ok, _} = couch_db:update_doc(AuthDb, JoeDoc, [?ADMIN_USER]),
-
-        Host = "oauth-example.com",
-        Consumer = {"consec1", "foo", hmac_sha1},
-        SignedParams = oauth:sign(
-            "GET", "http://" ++ Host ++ "/", [], Consumer, "otoksec1", "foobar"),
-        OAuthUrl = oauth:uri(Url, SignedParams),
-
-        case test_request:get(OAuthUrl, [], [{host_header, Host}]) of
-            {ok, Code, _, Body} ->
-                ?assertEqual(200, Code),
-                {JsonBody} = ejson:decode(Body),
-                ?assertEqual(<<"test">>,
-                             couch_util:get_value(<<"name">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
-
-should_fail_oauth_with_wrong_credentials({Url, _}) ->
-    ?_test(begin
-        AuthDbName = config:get("couch_httpd_auth", "authentication_db"),
-        JoeDoc = couch_doc:from_json_obj({[
-            {<<"_id">>, <<"org.couchdb.user:joe">>},
-            {<<"type">>, <<"user">>},
-            {<<"name">>, <<"joe">>},
-            {<<"roles">>, []},
-            {<<"password_sha">>, <<"fe95df1ca59a9b567bdca5cbaf8412abd6e06121">>},
-            {<<"salt">>, <<"4e170ffeb6f34daecfd814dfb4001a73">>}
-        ]}),
-        {ok, AuthDb} = couch_db:open_int(?l2b(AuthDbName), [?ADMIN_USER]),
-        {ok, _} = couch_db:update_doc(AuthDb, JoeDoc, [?ADMIN_USER]),
-
-        Host = "oauth-example.com",
-        Consumer = {"consec1", "bad_secret", hmac_sha1},
-        SignedParams = oauth:sign(
-            "GET", "http://" ++ Host ++ "/", [], Consumer, "otoksec1", "foobar"),
-        OAuthUrl = oauth:uri(Url, SignedParams),
-
-        case test_request:get(OAuthUrl, [], [{host_header, Host}]) of
-            {ok, Code, _, Body} ->
-                ?assertEqual(401, Code),
-                {JsonBody} = ejson:decode(Body),
-                ?assertEqual(<<"unauthorized">>,
-                             couch_util:get_value(<<"error">>, JsonBody));
-            Else ->
-                erlang:error({assertion_failed,
-                             [{module, ?MODULE},
-                              {line, ?LINE},
-                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
-        end
-    end).
+%% setup() ->
+%%     DbName = ?tempdb(),
+%%     {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+%%     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),
+%%     couch_db:close(Db),
+
+%%     Addr = config:get("httpd", "bind_address", "127.0.0.1"),
+%%     Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+%%     Url = "http://" ++ Addr ++ ":" ++ Port,
+%%     {Url, ?b2l(DbName)}.
+
+%% setup_oauth() ->
+%%     DbName = ?tempdb(),
+%%     {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+
+%%     config:set("couch_httpd_auth", "authentication_db",
+%%                      ?b2l(?tempdb()), false),
+%%     config:set("oauth_token_users", "otoksec1", "joe", false),
+%%     config:set("oauth_consumer_secrets", "consec1", "foo", false),
+%%     config:set("oauth_token_secrets", "otoksec1", "foobar", false),
+%%     config:set("couch_httpd_auth", "require_valid_user", "true", false),
+
+%%     ok = config:set(
+%%         "vhosts", "oauth-example.com",
+%%         "/" ++ ?b2l(DbName) ++ "/_design/test/_rewrite/foobar", false),
+
+%%     DDoc = couch_doc:from_json_obj({[
+%%         {<<"_id">>, <<"_design/test">>},
+%%         {<<"language">>, <<"javascript">>},
+%%         {<<"rewrites">>, [
+%%             {[
+%%                 {<<"from">>, <<"foobar">>},
+%%                 {<<"to">>, <<"_info">>}
+%%             ]}
+%%         ]}
+%%     ]}),
+%%     {ok, _} = couch_db:update_doc(Db, DDoc, []),
+
+%%     couch_db:ensure_full_commit(Db),
+%%     couch_db:close(Db),
+
+%%     Addr = config:get("httpd", "bind_address", "127.0.0.1"),
+%%     Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+%%     Url = "http://" ++ Addr ++ ":" ++ Port,
+%%     {Url, ?b2l(DbName)}.
+
+%% teardown({_, DbName}) ->
+%%     ok = couch_server:delete(?l2b(DbName), []),
+%%     ok.
+
+
+%% vhosts_test_() ->
+%%     {
+%%         "Virtual Hosts rewrite tests",
+%%         {
+%%             setup,
+%%             fun test_util:start_couch/0, fun test_util:stop_couch/1,
+%%             {
+%%                 foreach,
+%%                 fun setup/0, fun teardown/1,
+%%                 [
+%%                     fun should_return_database_info/1,
+%%                     fun should_return_revs_info/1,
+%%                     fun should_serve_utils_for_vhost/1,
+%%                     fun should_return_virtual_request_path_field_in_request/1,
+%%                     fun should_return_real_request_path_field_in_request/1,
+%%                     fun should_match_wildcard_vhost/1,
+%%                     fun should_return_db_info_for_wildcard_vhost_for_custom_db/1,
+%%                     fun should_replace_rewrite_variables_for_db_and_doc/1,
+%%                     fun should_return_db_info_for_vhost_with_resource/1,
+%%                     fun should_return_revs_info_for_vhost_with_resource/1,
+%%                     fun should_return_db_info_for_vhost_with_wildcard_resource/1,
+%%                     fun should_return_path_for_vhost_with_wildcard_host/1
+%%                 ]
+%%             }
+%%         }
+%%     }.
+
+%% oauth_test_() ->
+%%     {
+%%         "Virtual Hosts OAuth tests",
+%%         {
+%%             setup,
+%%             fun test_util:start_couch/0, fun test_util:stop_couch/1,
+%%             {
+%%                 foreach,
+%%                 fun setup_oauth/0, fun teardown/1,
+%%                 [
+%%                     fun should_require_auth/1,
+%%                     fun should_succeed_oauth/1,
+%%                     fun should_fail_oauth_with_wrong_credentials/1
+%%                 ]
+%%             }
+%%         }
+%%     }.
+
+
+%% should_return_database_info({Url, DbName}) ->
+%%     ?_test(begin
+%%         ok = config:set("vhosts", "example.com", "/" ++ DbName, false),
+%%         case test_request:get(Url, [], [{host_header, "example.com"}]) of
+%%             {ok, _, _, Body} ->
+%%                 {JsonBody} = ejson:decode(Body),
+%%                 ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
+%%             Else ->
+%%                 erlang:error({assertion_failed,
+%%                              [{module, ?MODULE},
+%%                               {line, ?LINE},
+%%                               {reason, ?iofmt("Request failed: ~p", [Else])}]})
+%%         end
+%%     end).
+
+%% should_return_revs_info({Url, DbName}) ->
+%%     ?_test(begin
+%%         ok = config:set("vhosts", "example.com", "/" ++ DbName, false),
+%%         case test_request:get(Url ++ "/doc1?revs_info=true", [],
+%%                               [{host_header, "example.com"}]) of
+%%             {ok, _, _, Body} ->
+%%                 {JsonBody} = ejson:decode(Body),
+%%                 ?assert(proplists:is_defined(<<"_revs_info">>, JsonBody));
+%%             Else ->
+%%                 erlang:error({assertion_failed,
+%%                              [{module, ?MODULE},
+%%                               {line, ?LINE},
+%%                               {reason, ?iofmt("Request failed: ~p", [Else])}]})
+%%         end
+%%     end).
+
+%% should_serve_utils_for_vhost({Url, DbName}) ->
+%%     ?_test(begin
+%%         ok = config:set("vhosts", "example.com", "/" ++ DbName, false),
+%%         case test_request:get(Url ++ "/_utils/index.html", [],
+%%                               [{host_header, "example.com"}]) of
+%%             {ok, _, _, Body} ->
+%%                 ?assertMatch(<<"<!DOCTYPE html>", _/binary>>, Body);
+%%             Else ->
+%%                 erlang:error({assertion_failed,
+%%                              [{module, ?MODULE},
+%%                               {line, ?LINE},
+%%                               {reason, ?iofmt("Request failed: ~p", [Else])}]})
+%%         end
+%%     end).
+
+%% should_return_virtual_request_path_field_in_request({Url, DbName}) ->
+%%     ?_test(begin
+%%         ok = config:set("vhosts", "example1.com",
+%%                               "/" ++ DbName ++ "/_design/doc1/_rewrite/",
+%%                               false),
+%%         case test_request:get(Url, [], [{host_header, "example1.com"}]) of
+%%             {ok, _, _, Body} ->
+%%                 {Json} = ejson:decode(Body),
+%%                 ?assertEqual(<<"/">>,
+%%                              proplists:get_value(<<"requested_path">>, Json));
+%%             Else ->
+%%                 erlang:error({assertion_failed,
+%%                              [{module, ?MODULE},
+%%                               {line, ?LINE},
+%%                               {reason, ?iofmt("Request failed: ~p", [Else])}]})
+%%         end
+%%     end).
+
+%% should_return_real_request_path_field_in_request({Url, DbName}) ->
+%%     ?_test(begin
+%%         ok = config:set("vhosts", "example1.com",
+%%                               "/" ++ DbName ++ "/_design/doc1/_rewrite/",
+%%                               false),
+%%         case test_request:get(Url, [], [{host_header, "example1.com"}]) of
+%%             {ok, _, _, Body} ->
+%%                 {Json} = ejson:decode(Body),
+%%                 Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
+%%                 ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
+%%             Else ->
+%%                 erlang:error({assertion_failed,
+%%                              [{module, ?MODULE},
+%%                               {line, ?LINE},
+%%                               {reason, ?iofmt("Request failed: ~p", [Else])}]})
+%%         end
+%%     end).
+
+%% should_match_wildcard_vhost({Url, DbName}) ->
+%%     ?_test(begin
+%%         ok = config:set("vhosts", "*.example.com",
+%%                               "/" ++ DbName ++ "/_design/doc1/_rewrite", false),
+%%         case test_request:get(Url, [], [{host_header, "test.example.com"}]) of
+%%             {ok, _, _, Body} ->
+%%                 {Json} = ejson:decode(Body),
+%%                 Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
+%%                 ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
+%%             Else ->
+%%                 erlang:error({assertion_failed,
+%%                              [{module, ?MODULE},
+%%                               {line, ?LINE},
+%%                               {reason, ?iofmt("Request failed: ~p", [Else])}]})
+%%         end
+%%     end).
+
+%% should_return_db_info_for_wildcard_vhost_for_custom_db({Url, DbName}) ->
+%%     ?_test(begin
+%%         ok = config:set("vhosts", ":dbname.example1.com",
+%%                               "/:dbname", false),
+%%         Host = DbName ++ ".example1.com",
+%%         case test_request:get(Url, [], [{host_header, Host}]) of
+%%             {ok, _, _, Body} ->
+%%                 {JsonBody} = ejson:decode(Body),
+%%                 ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
+%%             Else ->
+%%                 erlang:error({assertion_failed,
+%%                              [{module, ?MODULE},
+%%                               {line, ?LINE},
+%%                               {reason, ?iofmt("Request failed: ~p", [Else])}]})
+%%         end
+%%     end).
+
+%% should_replace_rewrite_variables_for_db_and_doc({Url, DbName}) ->
+%%     ?_test(begin
+%%         ok = config:set("vhosts",":appname.:dbname.example1.com",
+%%                               "/:dbname/_design/:appname/_rewrite/", false),
+%%         Host = "doc1." ++ DbName ++ ".example1.com",
+%%         case test_request:get(Url, [], [{host_header, Host}]) of
+%%             {ok, _, _, Body} ->
+%%                 {Json} = ejson:decode(Body),
+%%                 Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
+%%                 ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
+%%             Else ->
+%%                 erlang:error({assertion_failed,
+%%                              [{module, ?MODULE},
+%%                               {line, ?LINE},
+%%                               {reason, ?iofmt("Request failed: ~p", [Else])}]})
+%%         end
+%%     end).
+
+%% should_return_db_info_for_vhost_with_resource({Url, DbName}) ->
+%%     ?_test(begin
+%%         ok = config:set("vhosts",
+%%                               "example.com/test", "/" ++ DbName, false),
+%%         ReqUrl = Url ++ "/test",
+%%         case test_request:get(ReqUrl, [], [{host_header, "example.com"}]) of
+%%             {ok, _, _, Body} ->
+%%                 {JsonBody} = ejson:decode(Body),
+%%                 ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
+%%             Else ->
+%%                 erlang:error({assertion_failed,
+%%                              [{module, ?MODULE},
+%%                               {line, ?LINE},
+%%                               {reason, ?iofmt("Request failed: ~p", [Else])}]})
+%%         end
+%%     end).
+
+
+%% should_return_revs_info_for_vhost_with_resource({Url, DbName}) ->
+%%     ?_test(begin
+%%         ok = config:set("vhosts",
+%%                               "example.com/test", "/" ++ DbName, false),
+%%         ReqUrl = Url ++ "/test/doc1?revs_info=true",
+%%         case test_request:get(ReqUrl, [], [{host_header, "example.com"}]) of
+%%             {ok, _, _, Body} ->
+%%                 {JsonBody} = ejson:decode(Body),
+%%                 ?assert(proplists:is_defined(<<"_revs_info">>, JsonBody));
+%%             Else ->
+%%                 erlang:error({assertion_failed,
+%%                              [{module, ?MODULE},
+%%                               {line, ?LINE},
+%%                               {reason, ?iofmt("Request failed: ~p", [Else])}]})
+%%         end
+%%     end).
+
+%% should_return_db_info_for_vhost_with_wildcard_resource({Url, DbName}) ->
+%%     ?_test(begin
+%%         ok = config:set("vhosts", "*.example2.com/test", "/*", false),
+%%         ReqUrl = Url ++ "/test",
+%%         Host = DbName ++ ".example2.com",
+%%         case test_request:get(ReqUrl, [], [{host_header, Host}]) of
+%%             {ok, _, _, Body} ->
+%%                 {JsonBody} = ejson:decode(Body),
+%%                 ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
+%%             Else ->
+%%                 erlang:error({assertion_failed,
+%%                              [{module, ?MODULE},
+%%                               {line, ?LINE},
+%%                               {reason, ?iofmt("Request failed: ~p", [Else])}]})
+%%         end
+%%     end).
+
+%% should_return_path_for_vhost_with_wildcard_host({Url, DbName}) ->
+%%     ?_test(begin
+%%         ok = config:set("vhosts", "*/test1",
+%%                               "/" ++ DbName ++ "/_design/doc1/_show/test",
+%%                               false),
+%%         case test_request:get(Url ++ "/test1") of
+%%             {ok, _, _, Body} ->
+%%                 {Json} = ejson:decode(Body),
+%%                 Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
+%%                 ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
+%%             Else ->
+%%                 erlang:error({assertion_failed,
+%%                              [{module, ?MODULE},
+%%                               {line, ?LINE},
+%%                               {reason, ?iofmt("Request failed: ~p", [Else])}]})
+%%         end
+%%     end).
+
+%% should_require_auth({Url, _}) ->
+%%     ?_test(begin
+%%         case test_request:get(Url, [], [{host_header, "oauth-example.com"}]) of
+%%             {ok, Code, _, Body} ->
+%%                 ?assertEqual(401, Code),
+%%                 {JsonBody} = ejson:decode(Body),
+%%                 ?assertEqual(<<"unauthorized">>,
+%%                              couch_util:get_value(<<"error">>, JsonBody));
+%%             Else ->
+%%                 erlang:error({assertion_failed,
+%%                              [{module, ?MODULE},
+%%                               {line, ?LINE},
+%%                               {reason, ?iofmt("Request failed: ~p", [Else])}]})
+%%         end
+%%     end).
+
+%% should_succeed_oauth({Url, _}) ->
+%%     ?_test(begin
+%%         AuthDbName = config:get("couch_httpd_auth", "authentication_db"),
+%%         JoeDoc = couch_doc:from_json_obj({[
+%%             {<<"_id">>, <<"org.couchdb.user:joe">>},
+%%             {<<"type">>, <<"user">>},
+%%             {<<"name">>, <<"joe">>},
+%%             {<<"roles">>, []},
+%%             {<<"password_sha">>, <<"fe95df1ca59a9b567bdca5cbaf8412abd6e06121">>},
+%%             {<<"salt">>, <<"4e170ffeb6f34daecfd814dfb4001a73">>}
+%%         ]}),
+%%         {ok, AuthDb} = couch_db:open_int(?l2b(AuthDbName), [?ADMIN_USER]),
+%%         {ok, _} = couch_db:update_doc(AuthDb, JoeDoc, [?ADMIN_USER]),
+
+%%         Host = "oauth-example.com",
+%%         Consumer = {"consec1", "foo", hmac_sha1},
+%%         SignedParams = oauth:sign(
+%%             "GET", "http://" ++ Host ++ "/", [], Consumer, "otoksec1", "foobar"),
+%%         OAuthUrl = oauth:uri(Url, SignedParams),
+
+%%         case test_request:get(OAuthUrl, [], [{host_header, Host}]) of
+%%             {ok, Code, _, Body} ->
+%%                 ?assertEqual(200, Code),
+%%                 {JsonBody} = ejson:decode(Body),
+%%                 ?assertEqual(<<"test">>,
+%%                              couch_util:get_value(<<"name">>, JsonBody));
+%%             Else ->
+%%                 erlang:error({assertion_failed,
+%%                              [{module, ?MODULE},
+%%                               {line, ?LINE},
+%%                               {reason, ?iofmt("Request failed: ~p", [Else])}]})
+%%         end
+%%     end).
+
+%% should_fail_oauth_with_wrong_credentials({Url, _}) ->
+%%     ?_test(begin
+%%         AuthDbName = config:get("couch_httpd_auth", "authentication_db"),
+%%         JoeDoc = couch_doc:from_json_obj({[
+%%             {<<"_id">>, <<"org.couchdb.user:joe">>},
+%%             {<<"type">>, <<"user">>},
+%%             {<<"name">>, <<"joe">>},
+%%             {<<"roles">>, []},
+%%             {<<"password_sha">>, <<"fe95df1ca59a9b567bdca5cbaf8412abd6e06121">>},
+%%             {<<"salt">>, <<"4e170ffeb6f34daecfd814dfb4001a73">>}
+%%         ]}),
+%%         {ok, AuthDb} = couch_db:open_int(?l2b(AuthDbName), [?ADMIN_USER]),
+%%         {ok, _} = couch_db:update_doc(AuthDb, JoeDoc, [?ADMIN_USER]),
+
+%%         Host = "oauth-example.com",
+%%         Consumer = {"consec1", "bad_secret", hmac_sha1},
+%%         SignedParams = oauth:sign(
+%%             "GET", "http://" ++ Host ++ "/", [], Consumer, "otoksec1", "foobar"),
+%%         OAuthUrl = oauth:uri(Url, SignedParams),
+
+%%         case test_request:get(OAuthUrl, [], [{host_header, Host}]) of
+%%             {ok, Code, _, Body} ->
+%%                 ?assertEqual(401, Code),
+%%                 {JsonBody} = ejson:decode(Body),
+%%                 ?assertEqual(<<"unauthorized">>,
+%%                              couch_util:get_value(<<"error">>, JsonBody));
+%%             Else ->
+%%                 erlang:error({assertion_failed,
+%%                              [{module, ?MODULE},
+%%                               {line, ?LINE},
+%%                               {reason, ?iofmt("Request failed: ~p", [Else])}]})
+%%         end
+%%     end).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/6179af60/test/couchdb_views_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_views_tests.erl b/test/couchdb_views_tests.erl
index 03fb9cc..3f089e5 100644
--- a/test/couchdb_views_tests.erl
+++ b/test/couchdb_views_tests.erl
@@ -21,635 +21,635 @@
 -define(TIMEOUT, 1000).
 
 
-setup() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
-    ok = couch_db:close(Db),
-    FooRev = create_design_doc(DbName, <<"_design/foo">>, <<"bar">>),
-    query_view(DbName, "foo", "bar"),
-    BooRev = create_design_doc(DbName, <<"_design/boo">>, <<"baz">>),
-    query_view(DbName, "boo", "baz"),
-    {DbName, {FooRev, BooRev}}.
-
-setup_with_docs() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
-    ok = couch_db:close(Db),
-    create_docs(DbName),
-    create_design_doc(DbName, <<"_design/foo">>, <<"bar">>),
-    DbName.
-
-teardown({DbName, _}) ->
-    teardown(DbName);
-teardown(DbName) when is_binary(DbName) ->
-    couch_server:delete(DbName, [?ADMIN_USER]),
-    ok.
-
-
-view_indexes_cleanup_test_() ->
-    {
-        "View indexes cleanup",
-        {
-            setup,
-            fun test_util:start_couch/0, fun test_util:stop_couch/1,
-            {
-                foreach,
-                fun setup/0, fun teardown/1,
-                [
-                    fun should_have_two_indexes_alive_before_deletion/1,
-                    fun should_cleanup_index_file_after_ddoc_deletion/1,
-                    fun should_cleanup_all_index_files/1
-                ]
-            }
-        }
-    }.
-
-view_group_db_leaks_test_() ->
-    {
-        "View group db leaks",
-        {
-            setup,
-            fun test_util:start_couch/0, fun test_util:stop_couch/1,
-            {
-                foreach,
-                fun setup_with_docs/0, fun teardown/1,
-                [
-                    fun couchdb_1138/1,
-                    fun couchdb_1309/1
-                ]
-            }
-        }
-    }.
-
-view_group_shutdown_test_() ->
-    {
-        "View group shutdown",
-        {
-            setup,
-            fun test_util:start_couch/0, fun test_util:stop_couch/1,
-            [couchdb_1283()]
-        }
-    }.
-
-
-should_not_remember_docs_in_index_after_backup_restore_test() ->
-    %% COUCHDB-640
-    start(),
-    DbName = setup_with_docs(),
-
-    ok = backup_db_file(DbName),
-    create_doc(DbName, "doc666"),
-
-    Rows0 = query_view(DbName, "foo", "bar"),
-    ?assert(has_doc("doc1", Rows0)),
-    ?assert(has_doc("doc2", Rows0)),
-    ?assert(has_doc("doc3", Rows0)),
-    ?assert(has_doc("doc666", Rows0)),
-
-    restore_backup_db_file(DbName),
-
-    Rows1 = query_view(DbName, "foo", "bar"),
-    ?assert(has_doc("doc1", Rows1)),
-    ?assert(has_doc("doc2", Rows1)),
-    ?assert(has_doc("doc3", Rows1)),
-    ?assertNot(has_doc("doc666", Rows1)),
-
-    teardown(DbName),
-    stop(whereis(couch_server_sup)).
-
-
-should_upgrade_legacy_view_files_test() ->
-    start(),
-
-    ok = config:set("query_server_config", "commit_freq", "0", false),
-
-    DbName = <<"test">>,
-    DbFileName = "test.couch",
-    DbFilePath = filename:join([?FIXTURESDIR, DbFileName]),
-    OldViewName = "3b835456c235b1827e012e25666152f3.view",
-    FixtureViewFilePath = filename:join([?FIXTURESDIR, OldViewName]),
-    NewViewName = "a1c5929f912aca32f13446122cc6ce50.view",
-
-    DbDir = config:get("couchdb", "database_dir"),
-    ViewDir = config:get("couchdb", "view_index_dir"),
-    OldViewFilePath = filename:join([ViewDir, ".test_design", OldViewName]),
-    NewViewFilePath = filename:join([ViewDir, ".test_design", "mrview",
-                                     NewViewName]),
-
-    % cleanup
-    Files = [
-        filename:join([DbDir, DbFileName]),
-        OldViewFilePath,
-        NewViewFilePath
-    ],
-    lists:foreach(fun(File) -> file:delete(File) end, Files),
-
-    % copy old db file into db dir
-    {ok, _} = file:copy(DbFilePath, filename:join([DbDir, DbFileName])),
-
-    % copy old view file into view dir
-    ok = filelib:ensure_dir(filename:join([ViewDir, ".test_design"])),
-    {ok, _} = file:copy(FixtureViewFilePath, OldViewFilePath),
-
-    % ensure old header
-    OldHeader = read_header(OldViewFilePath),
-    ?assertMatch(#index_header{}, OldHeader),
-
-    % query view for expected results
-    Rows0 = query_view(DbName, "test", "test"),
-    ?assertEqual(2, length(Rows0)),
-
-    % ensure old file gone
-    ?assertNot(filelib:is_regular(OldViewFilePath)),
-
-    % add doc to trigger update
-    DocUrl = db_url(DbName) ++ "/boo",
-    {ok, _, _, _} = test_request:put(
-        DocUrl, [{"Content-Type", "application/json"}], <<"{\"a\":3}">>),
-
-    % query view for expected results
-    Rows1 = query_view(DbName, "test", "test"),
-    ?assertEqual(3, length(Rows1)),
-
-    % ensure new header
-    timer:sleep(2000),  % have to wait for awhile to upgrade the index
-    NewHeader = read_header(NewViewFilePath),
-    ?assertMatch(#mrheader{}, NewHeader),
-
-    teardown(DbName),
-    stop(whereis(couch_server_sup)).
-
-
-should_have_two_indexes_alive_before_deletion({DbName, _}) ->
-    view_cleanup(DbName),
-    ?_assertEqual(2, count_index_files(DbName)).
-
-should_cleanup_index_file_after_ddoc_deletion({DbName, {FooRev, _}}) ->
-    delete_design_doc(DbName, <<"_design/foo">>, FooRev),
-    view_cleanup(DbName),
-    ?_assertEqual(1, count_index_files(DbName)).
-
-should_cleanup_all_index_files({DbName, {FooRev, BooRev}})->
-    delete_design_doc(DbName, <<"_design/foo">>, FooRev),
-    delete_design_doc(DbName, <<"_design/boo">>, BooRev),
-    view_cleanup(DbName),
-    ?_assertEqual(0, count_index_files(DbName)).
-
-couchdb_1138(DbName) ->
-    ?_test(begin
-        {ok, IndexerPid} = couch_index_server:get_index(
-            couch_mrview_index, DbName, <<"_design/foo">>),
-        ?assert(is_pid(IndexerPid)),
-        ?assert(is_process_alive(IndexerPid)),
-        ?assertEqual(2, count_db_refs(DbName)),
-
-        Rows0 = query_view(DbName, "foo", "bar"),
-        ?assertEqual(3, length(Rows0)),
-        ?assertEqual(2, count_db_refs(DbName)),
-        ?assert(is_process_alive(IndexerPid)),
-
-        create_doc(DbName, "doc1000"),
-        Rows1 = query_view(DbName, "foo", "bar"),
-        ?assertEqual(4, length(Rows1)),
-        ?assertEqual(2, count_db_refs(DbName)),
-        ?assert(is_process_alive(IndexerPid)),
-
-        Ref1 = get_db_ref_counter(DbName),
-        compact_db(DbName),
-        Ref2 = get_db_ref_counter(DbName),
-        ?assertEqual(2, couch_ref_counter:count(Ref2)),
-        ?assertNotEqual(Ref2, Ref1),
-        ?assertNot(is_process_alive(Ref1)),
-        ?assert(is_process_alive(IndexerPid)),
-
-        compact_view_group(DbName, "foo"),
-        ?assertEqual(2, count_db_refs(DbName)),
-        Ref3 = get_db_ref_counter(DbName),
-        ?assertEqual(Ref3, Ref2),
-        ?assert(is_process_alive(IndexerPid)),
-
-        create_doc(DbName, "doc1001"),
-        Rows2 = query_view(DbName, "foo", "bar"),
-        ?assertEqual(5, length(Rows2)),
-        ?assertEqual(2, count_db_refs(DbName)),
-        ?assert(is_process_alive(IndexerPid))
-    end).
-
-couchdb_1309(DbName) ->
-    ?_test(begin
-        {ok, IndexerPid} = couch_index_server:get_index(
-            couch_mrview_index, DbName, <<"_design/foo">>),
-        ?assert(is_pid(IndexerPid)),
-        ?assert(is_process_alive(IndexerPid)),
-        ?assertEqual(2, count_db_refs(DbName)),
-
-        create_doc(DbName, "doc1001"),
-        Rows0 = query_view(DbName, "foo", "bar"),
-        check_rows_value(Rows0, null),
-        ?assertEqual(4, length(Rows0)),
-        ?assertEqual(2, count_db_refs(DbName)),
-        ?assert(is_process_alive(IndexerPid)),
-
-        update_design_doc(DbName,  <<"_design/foo">>, <<"bar">>),
-        {ok, NewIndexerPid} = couch_index_server:get_index(
-            couch_mrview_index, DbName, <<"_design/foo">>),
-        ?assert(is_pid(NewIndexerPid)),
-        ?assert(is_process_alive(NewIndexerPid)),
-        ?assertNotEqual(IndexerPid, NewIndexerPid),
-        ?assertEqual(2, count_db_refs(DbName)),
-
-        Rows1 = query_view(DbName, "foo", "bar", ok),
-        ?assertEqual(0, length(Rows1)),
-        Rows2 = query_view(DbName, "foo", "bar"),
-        check_rows_value(Rows2, 1),
-        ?assertEqual(4, length(Rows2)),
-
-        MonRef0 = erlang:monitor(process, IndexerPid),
-        receive
-            {'DOWN', MonRef0, _, _, _} ->
-                ok
-        after ?TIMEOUT ->
-            erlang:error(
-                {assertion_failed,
-                 [{module, ?MODULE}, {line, ?LINE},
-                  {reason, "old view group is not dead after ddoc update"}]})
-        end,
-
-        MonRef1 = erlang:monitor(process, NewIndexerPid),
-        ok = couch_server:delete(DbName, [?ADMIN_USER]),
-        receive
-            {'DOWN', MonRef1, _, _, _} ->
-                ok
-        after ?TIMEOUT ->
-            erlang:error(
-                {assertion_failed,
-                 [{module, ?MODULE}, {line, ?LINE},
-                  {reason, "new view group did not die after DB deletion"}]})
-        end
-    end).
-
-couchdb_1283() ->
-    ?_test(begin
-        ok = config:set("couchdb", "max_dbs_open", "3", false),
-        ok = config:set("couchdb", "delayed_commits", "false", false),
-
-        {ok, MDb1} = couch_db:create(?tempdb(), [?ADMIN_USER]),
-        DDoc = couch_doc:from_json_obj({[
-            {<<"_id">>, <<"_design/foo">>},
-            {<<"language">>, <<"javascript">>},
-            {<<"views">>, {[
-                {<<"foo">>, {[
-                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
-                ]}},
-                {<<"foo2">>, {[
-                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
-                ]}},
-                {<<"foo3">>, {[
-                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
-                ]}},
-                {<<"foo4">>, {[
-                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
-                ]}},
-                {<<"foo5">>, {[
-                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
-                ]}}
-            ]}}
-        ]}),
-        {ok, _} = couch_db:update_doc(MDb1, DDoc, []),
-        ok = populate_db(MDb1, 100, 100),
-        query_view(MDb1#db.name, "foo", "foo"),
-        ok = couch_db:close(MDb1),
-
-        {ok, Db1} = couch_db:create(?tempdb(), [?ADMIN_USER]),
-        ok = couch_db:close(Db1),
-        {ok, Db2} = couch_db:create(?tempdb(), [?ADMIN_USER]),
-        ok = couch_db:close(Db2),
-        {ok, Db3} = couch_db:create(?tempdb(), [?ADMIN_USER]),
-        ok = couch_db:close(Db3),
-
-        Writer1 = spawn_writer(Db1#db.name),
-        Writer2 = spawn_writer(Db2#db.name),
-
-        ?assert(is_process_alive(Writer1)),
-        ?assert(is_process_alive(Writer2)),
-
-        ?assertEqual(ok, get_writer_status(Writer1)),
-        ?assertEqual(ok, get_writer_status(Writer2)),
-
-        {ok, MonRef} = couch_mrview:compact(MDb1#db.name, <<"_design/foo">>,
-                                            [monitor]),
-
-        Writer3 = spawn_writer(Db3#db.name),
-        ?assert(is_process_alive(Writer3)),
-        ?assertEqual({error, all_dbs_active}, get_writer_status(Writer3)),
-
-        ?assert(is_process_alive(Writer1)),
-        ?assert(is_process_alive(Writer2)),
-        ?assert(is_process_alive(Writer3)),
-
-        receive
-            {'DOWN', MonRef, process, _, Reason} ->
-                ?assertEqual(normal, Reason)
-        after ?TIMEOUT ->
-            erlang:error(
-                {assertion_failed,
-                 [{module, ?MODULE}, {line, ?LINE},
-                  {reason, "Failure compacting view group"}]})
-        end,
-
-        ?assertEqual(ok, writer_try_again(Writer3)),
-        ?assertEqual(ok, get_writer_status(Writer3)),
-
-        ?assert(is_process_alive(Writer1)),
-        ?assert(is_process_alive(Writer2)),
-        ?assert(is_process_alive(Writer3)),
-
-        ?assertEqual(ok, stop_writer(Writer1)),
-        ?assertEqual(ok, stop_writer(Writer2)),
-        ?assertEqual(ok, stop_writer(Writer3))
-    end).
-
-create_doc(DbName, DocId) when is_list(DocId) ->
-    create_doc(DbName, ?l2b(DocId));
-create_doc(DbName, DocId) when is_binary(DocId) ->
-    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
-    Doc666 = couch_doc:from_json_obj({[
-        {<<"_id">>, DocId},
-        {<<"value">>, 999}
-    ]}),
-    {ok, _} = couch_db:update_docs(Db, [Doc666]),
-    couch_db:ensure_full_commit(Db),
-    couch_db:close(Db).
-
-create_docs(DbName) ->
-    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
-    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).
-
-populate_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_db(Db, BatchSize, N - length(Docs));
-populate_db(_Db, _, _) ->
-    ok.
-
-create_design_doc(DbName, DDName, ViewName) ->
-    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
-    DDoc = couch_doc:from_json_obj({[
-        {<<"_id">>, DDName},
-        {<<"language">>, <<"javascript">>},
-        {<<"views">>, {[
-            {ViewName, {[
-                {<<"map">>, <<"function(doc) { emit(doc.value, null); }">>}
-            ]}}
-        ]}}
-    ]}),
-    {ok, Rev} = couch_db:update_doc(Db, DDoc, []),
-    couch_db:ensure_full_commit(Db),
-    couch_db:close(Db),
-    Rev.
-
-update_design_doc(DbName, DDName, ViewName) ->
-    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
-    {ok, Doc} = couch_db:open_doc(Db, DDName, [?ADMIN_USER]),
-    {Props} = couch_doc:to_json_obj(Doc, []),
-    Rev = couch_util:get_value(<<"_rev">>, Props),
-    DDoc = couch_doc:from_json_obj({[
-        {<<"_id">>, DDName},
-        {<<"_rev">>, Rev},
-        {<<"language">>, <<"javascript">>},
-        {<<"views">>, {[
-            {ViewName, {[
-                {<<"map">>, <<"function(doc) { emit(doc.value, 1); }">>}
-            ]}}
-        ]}}
-    ]}),
-    {ok, NewRev} = couch_db:update_doc(Db, DDoc, [?ADMIN_USER]),
-    couch_db:ensure_full_commit(Db),
-    couch_db:close(Db),
-    NewRev.
-
-delete_design_doc(DbName, DDName, Rev) ->
-    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
-    DDoc = couch_doc:from_json_obj({[
-        {<<"_id">>, DDName},
-        {<<"_rev">>, couch_doc:rev_to_str(Rev)},
-        {<<"_deleted">>, true}
-    ]}),
-    {ok, _} = couch_db:update_doc(Db, DDoc, [Rev]),
-    couch_db:close(Db).
-
-db_url(DbName) ->
-    Addr = config:get("httpd", "bind_address", "127.0.0.1"),
-    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
-    "http://" ++ Addr ++ ":" ++ Port ++ "/" ++ ?b2l(DbName).
-
-query_view(DbName, DDoc, View) ->
-    query_view(DbName, DDoc, View, false).
-
-query_view(DbName, DDoc, View, Stale) ->
-    {ok, Code, _Headers, Body} = test_request:get(
-        db_url(DbName) ++ "/_design/" ++ DDoc ++ "/_view/" ++ View
-        ++ case Stale of
-               false -> [];
-               _ -> "?stale=" ++ atom_to_list(Stale)
-           end),
-    ?assertEqual(200, Code),
-    {Props} = ejson:decode(Body),
-    couch_util:get_value(<<"rows">>, Props, []).
-
-check_rows_value(Rows, Value) ->
-    lists:foreach(
-        fun({Row}) ->
-            ?assertEqual(Value, couch_util:get_value(<<"value">>, Row))
-        end, Rows).
-
-view_cleanup(DbName) ->
-    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
-    couch_mrview:cleanup(Db),
-    couch_db:close(Db).
-
-get_db_ref_counter(DbName) ->
-    {ok, #db{fd_ref_counter = Ref} = Db} = couch_db:open_int(DbName, []),
-    ok = couch_db:close(Db),
-    Ref.
-
-count_db_refs(DbName) ->
-    Ref = get_db_ref_counter(DbName),
-    % have to sleep a bit to let couchdb cleanup all refs and leave only
-    % active ones. otherwise the related tests will randomly fail due to
-    % count number mismatch
-    timer:sleep(200),
-    couch_ref_counter:count(Ref).
-
-count_index_files(DbName) ->
-    % call server to fetch the index files
-    RootDir = config:get("couchdb", "view_index_dir"),
-    length(filelib:wildcard(RootDir ++ "/." ++
-        binary_to_list(DbName) ++ "_design"++"/mrview/*")).
-
-has_doc(DocId1, Rows) ->
-    DocId = iolist_to_binary(DocId1),
-    lists:any(fun({R}) -> lists:member({<<"id">>, DocId}, R) end, Rows).
-
-backup_db_file(DbName) ->
-    DbDir = config:get("couchdb", "database_dir"),
-    DbFile = filename:join([DbDir, ?b2l(DbName) ++ ".couch"]),
-    {ok, _} = file:copy(DbFile, DbFile ++ ".backup"),
-    ok.
-
-restore_backup_db_file(DbName) ->
-    DbDir = config:get("couchdb", "database_dir"),
-    stop(whereis(couch_server_sup)),
-    DbFile = filename:join([DbDir, ?b2l(DbName) ++ ".couch"]),
-    ok = file:delete(DbFile),
-    ok = file:rename(DbFile ++ ".backup", DbFile),
-    start(),
-    ok.
-
-compact_db(DbName) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    {ok, _} = couch_db:start_compact(Db),
-    ok = couch_db:close(Db),
-    wait_db_compact_done(DbName, 10).
-
-wait_db_compact_done(_DbName, 0) ->
-    erlang:error({assertion_failed,
-                  [{module, ?MODULE},
-                   {line, ?LINE},
-                   {reason, "DB compaction failed to finish"}]});
-wait_db_compact_done(DbName, N) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    ok = couch_db:close(Db),
-    case is_pid(Db#db.compactor_pid) of
-    false ->
-        ok;
-    true ->
-        ok = timer:sleep(?DELAY),
-        wait_db_compact_done(DbName, N - 1)
-    end.
-
-compact_view_group(DbName, DDocId) when is_list(DDocId) ->
-    compact_view_group(DbName, ?l2b("_design/" ++ DDocId));
-compact_view_group(DbName, DDocId) when is_binary(DDocId) ->
-    ok = couch_mrview:compact(DbName, DDocId),
-    wait_view_compact_done(DbName, DDocId, 10).
-
-wait_view_compact_done(_DbName, _DDocId, 0) ->
-    erlang:error({assertion_failed,
-                  [{module, ?MODULE},
-                   {line, ?LINE},
-                   {reason, "DB compaction failed to finish"}]});
-wait_view_compact_done(DbName, DDocId, N) ->
-    {ok, Code, _Headers, Body} = test_request:get(
-        db_url(DbName) ++ "/" ++ ?b2l(DDocId) ++ "/_info"),
-    ?assertEqual(200, Code),
-    {Info} = ejson: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(?DELAY),
-            wait_view_compact_done(DbName, DDocId, N - 1)
-    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 ?TIMEOUT ->
-        timeout
-    end.
-
-writer_try_again(Writer) ->
-    Ref = make_ref(),
-    Writer ! {try_again, Ref},
-    receive
-        {ok, Ref} ->
-            ok
-    after ?TIMEOUT ->
-        timeout
-    end.
-
-stop_writer(Writer) ->
-    Ref = make_ref(),
-    Writer ! {stop, Ref},
-    receive
-        {ok, Ref} ->
-            ok
-    after ?TIMEOUT ->
-        erlang:error({assertion_failed,
-                      [{module, ?MODULE},
-                       {line, ?LINE},
-                       {reason, "Timeout on stopping process"}]})
-    end.
-
-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.
-
-read_header(File) ->
-    {ok, Fd} = couch_file:open(File),
-    {ok, {_Sig, Header}} = couch_file:read_header(Fd),
-    couch_file:close(Fd),
-    Header.
+%% setup() ->
+%%     DbName = ?tempdb(),
+%%     {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+%%     ok = couch_db:close(Db),
+%%     FooRev = create_design_doc(DbName, <<"_design/foo">>, <<"bar">>),
+%%     query_view(DbName, "foo", "bar"),
+%%     BooRev = create_design_doc(DbName, <<"_design/boo">>, <<"baz">>),
+%%     query_view(DbName, "boo", "baz"),
+%%     {DbName, {FooRev, BooRev}}.
+
+%% setup_with_docs() ->
+%%     DbName = ?tempdb(),
+%%     {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+%%     ok = couch_db:close(Db),
+%%     create_docs(DbName),
+%%     create_design_doc(DbName, <<"_design/foo">>, <<"bar">>),
+%%     DbName.
+
+%% teardown({DbName, _}) ->
+%%     teardown(DbName);
+%% teardown(DbName) when is_binary(DbName) ->
+%%     couch_server:delete(DbName, [?ADMIN_USER]),
+%%     ok.
+
+
+%% view_indexes_cleanup_test_() ->
+%%     {
+%%         "View indexes cleanup",
+%%         {
+%%             setup,
+%%             fun test_util:start_couch/0, fun test_util:stop_couch/1,
+%%             {
+%%                 foreach,
+%%                 fun setup/0, fun teardown/1,
+%%                 [
+%%                     fun should_have_two_indexes_alive_before_deletion/1,
+%%                     fun should_cleanup_index_file_after_ddoc_deletion/1,
+%%                     fun should_cleanup_all_index_files/1
+%%                 ]
+%%             }
+%%         }
+%%     }.
+
+%% view_group_db_leaks_test_() ->
+%%     {
+%%         "View group db leaks",
+%%         {
+%%             setup,
+%%             fun test_util:start_couch/0, fun test_util:stop_couch/1,
+%%             {
+%%                 foreach,
+%%                 fun setup_with_docs/0, fun teardown/1,
+%%                 [
+%%                     fun couchdb_1138/1,
+%%                     fun couchdb_1309/1
+%%                 ]
+%%             }
+%%         }
+%%     }.
+
+%% view_group_shutdown_test_() ->
+%%     {
+%%         "View group shutdown",
+%%         {
+%%             setup,
+%%             fun test_util:start_couch/0, fun test_util:stop_couch/1,
+%%             [couchdb_1283()]
+%%         }
+%%     }.
+
+
+%% should_not_remember_docs_in_index_after_backup_restore_test() ->
+%%     %% COUCHDB-640
+%%     start(),
+%%     DbName = setup_with_docs(),
+
+%%     ok = backup_db_file(DbName),
+%%     create_doc(DbName, "doc666"),
+
+%%     Rows0 = query_view(DbName, "foo", "bar"),
+%%     ?assert(has_doc("doc1", Rows0)),
+%%     ?assert(has_doc("doc2", Rows0)),
+%%     ?assert(has_doc("doc3", Rows0)),
+%%     ?assert(has_doc("doc666", Rows0)),
+
+%%     restore_backup_db_file(DbName),
+
+%%     Rows1 = query_view(DbName, "foo", "bar"),
+%%     ?assert(has_doc("doc1", Rows1)),
+%%     ?assert(has_doc("doc2", Rows1)),
+%%     ?assert(has_doc("doc3", Rows1)),
+%%     ?assertNot(has_doc("doc666", Rows1)),
+
+%%     teardown(DbName),
+%%     stop(whereis(couch_server_sup)).
+
+
+%% should_upgrade_legacy_view_files_test() ->
+%%     start(),
+
+%%     ok = config:set("query_server_config", "commit_freq", "0", false),
+
+%%     DbName = <<"test">>,
+%%     DbFileName = "test.couch",
+%%     DbFilePath = filename:join([?FIXTURESDIR, DbFileName]),
+%%     OldViewName = "3b835456c235b1827e012e25666152f3.view",
+%%     FixtureViewFilePath = filename:join([?FIXTURESDIR, OldViewName]),
+%%     NewViewName = "a1c5929f912aca32f13446122cc6ce50.view",
+
+%%     DbDir = config:get("couchdb", "database_dir"),
+%%     ViewDir = config:get("couchdb", "view_index_dir"),
+%%     OldViewFilePath = filename:join([ViewDir, ".test_design", OldViewName]),
+%%     NewViewFilePath = filename:join([ViewDir, ".test_design", "mrview",
+%%                                      NewViewName]),
+
+%%     % cleanup
+%%     Files = [
+%%         filename:join([DbDir, DbFileName]),
+%%         OldViewFilePath,
+%%         NewViewFilePath
+%%     ],
+%%     lists:foreach(fun(File) -> file:delete(File) end, Files),
+
+%%     % copy old db file into db dir
+%%     {ok, _} = file:copy(DbFilePath, filename:join([DbDir, DbFileName])),
+
+%%     % copy old view file into view dir
+%%     ok = filelib:ensure_dir(filename:join([ViewDir, ".test_design"])),
+%%     {ok, _} = file:copy(FixtureViewFilePath, OldViewFilePath),
+
+%%     % ensure old header
+%%     OldHeader = read_header(OldViewFilePath),
+%%     ?assertMatch(#index_header{}, OldHeader),
+
+%%     % query view for expected results
+%%     Rows0 = query_view(DbName, "test", "test"),
+%%     ?assertEqual(2, length(Rows0)),
+
+%%     % ensure old file gone
+%%     ?assertNot(filelib:is_regular(OldViewFilePath)),
+
+%%     % add doc to trigger update
+%%     DocUrl = db_url(DbName) ++ "/boo",
+%%     {ok, _, _, _} = test_request:put(
+%%         DocUrl, [{"Content-Type", "application/json"}], <<"{\"a\":3}">>),
+
+%%     % query view for expected results
+%%     Rows1 = query_view(DbName, "test", "test"),
+%%     ?assertEqual(3, length(Rows1)),
+
+%%     % ensure new header
+%%     timer:sleep(2000),  % have to wait for awhile to upgrade the index
+%%     NewHeader = read_header(NewViewFilePath),
+%%     ?assertMatch(#mrheader{}, NewHeader),
+
+%%     teardown(DbName),
+%%     stop(whereis(couch_server_sup)).
+
+
+%% should_have_two_indexes_alive_before_deletion({DbName, _}) ->
+%%     view_cleanup(DbName),
+%%     ?_assertEqual(2, count_index_files(DbName)).
+
+%% should_cleanup_index_file_after_ddoc_deletion({DbName, {FooRev, _}}) ->
+%%     delete_design_doc(DbName, <<"_design/foo">>, FooRev),
+%%     view_cleanup(DbName),
+%%     ?_assertEqual(1, count_index_files(DbName)).
+
+%% should_cleanup_all_index_files({DbName, {FooRev, BooRev}})->
+%%     delete_design_doc(DbName, <<"_design/foo">>, FooRev),
+%%     delete_design_doc(DbName, <<"_design/boo">>, BooRev),
+%%     view_cleanup(DbName),
+%%     ?_assertEqual(0, count_index_files(DbName)).
+
+%% couchdb_1138(DbName) ->
+%%     ?_test(begin
+%%         {ok, IndexerPid} = couch_index_server:get_index(
+%%             couch_mrview_index, DbName, <<"_design/foo">>),
+%%         ?assert(is_pid(IndexerPid)),
+%%         ?assert(is_process_alive(IndexerPid)),
+%%         ?assertEqual(2, count_db_refs(DbName)),
+
+%%         Rows0 = query_view(DbName, "foo", "bar"),
+%%         ?assertEqual(3, length(Rows0)),
+%%         ?assertEqual(2, count_db_refs(DbName)),
+%%         ?assert(is_process_alive(IndexerPid)),
+
+%%         create_doc(DbName, "doc1000"),
+%%         Rows1 = query_view(DbName, "foo", "bar"),
+%%         ?assertEqual(4, length(Rows1)),
+%%         ?assertEqual(2, count_db_refs(DbName)),
+%%         ?assert(is_process_alive(IndexerPid)),
+
+%%         Ref1 = get_db_ref_counter(DbName),
+%%         compact_db(DbName),
+%%         Ref2 = get_db_ref_counter(DbName),
+%%         ?assertEqual(2, couch_ref_counter:count(Ref2)),
+%%         ?assertNotEqual(Ref2, Ref1),
+%%         ?assertNot(is_process_alive(Ref1)),
+%%         ?assert(is_process_alive(IndexerPid)),
+
+%%         compact_view_group(DbName, "foo"),
+%%         ?assertEqual(2, count_db_refs(DbName)),
+%%         Ref3 = get_db_ref_counter(DbName),
+%%         ?assertEqual(Ref3, Ref2),
+%%         ?assert(is_process_alive(IndexerPid)),
+
+%%         create_doc(DbName, "doc1001"),
+%%         Rows2 = query_view(DbName, "foo", "bar"),
+%%         ?assertEqual(5, length(Rows2)),
+%%         ?assertEqual(2, count_db_refs(DbName)),
+%%         ?assert(is_process_alive(IndexerPid))
+%%     end).
+
+%% couchdb_1309(DbName) ->
+%%     ?_test(begin
+%%         {ok, IndexerPid} = couch_index_server:get_index(
+%%             couch_mrview_index, DbName, <<"_design/foo">>),
+%%         ?assert(is_pid(IndexerPid)),
+%%         ?assert(is_process_alive(IndexerPid)),
+%%         ?assertEqual(2, count_db_refs(DbName)),
+
+%%         create_doc(DbName, "doc1001"),
+%%         Rows0 = query_view(DbName, "foo", "bar"),
+%%         check_rows_value(Rows0, null),
+%%         ?assertEqual(4, length(Rows0)),
+%%         ?assertEqual(2, count_db_refs(DbName)),
+%%         ?assert(is_process_alive(IndexerPid)),
+
+%%         update_design_doc(DbName,  <<"_design/foo">>, <<"bar">>),
+%%         {ok, NewIndexerPid} = couch_index_server:get_index(
+%%             couch_mrview_index, DbName, <<"_design/foo">>),
+%%         ?assert(is_pid(NewIndexerPid)),
+%%         ?assert(is_process_alive(NewIndexerPid)),
+%%         ?assertNotEqual(IndexerPid, NewIndexerPid),
+%%         ?assertEqual(2, count_db_refs(DbName)),
+
+%%         Rows1 = query_view(DbName, "foo", "bar", ok),
+%%         ?assertEqual(0, length(Rows1)),
+%%         Rows2 = query_view(DbName, "foo", "bar"),
+%%         check_rows_value(Rows2, 1),
+%%         ?assertEqual(4, length(Rows2)),
+
+%%         MonRef0 = erlang:monitor(process, IndexerPid),
+%%         receive
+%%             {'DOWN', MonRef0, _, _, _} ->
+%%                 ok
+%%         after ?TIMEOUT ->
+%%             erlang:error(
+%%                 {assertion_failed,
+%%                  [{module, ?MODULE}, {line, ?LINE},
+%%                   {reason, "old view group is not dead after ddoc update"}]})
+%%         end,
+
+%%         MonRef1 = erlang:monitor(process, NewIndexerPid),
+%%         ok = couch_server:delete(DbName, [?ADMIN_USER]),
+%%         receive
+%%             {'DOWN', MonRef1, _, _, _} ->
+%%                 ok
+%%         after ?TIMEOUT ->
+%%             erlang:error(
+%%                 {assertion_failed,
+%%                  [{module, ?MODULE}, {line, ?LINE},
+%%                   {reason, "new view group did not die after DB deletion"}]})
+%%         end
+%%     end).
+
+%% couchdb_1283() ->
+%%     ?_test(begin
+%%         ok = config:set("couchdb", "max_dbs_open", "3", false),
+%%         ok = config:set("couchdb", "delayed_commits", "false", false),
+
+%%         {ok, MDb1} = couch_db:create(?tempdb(), [?ADMIN_USER]),
+%%         DDoc = couch_doc:from_json_obj({[
+%%             {<<"_id">>, <<"_design/foo">>},
+%%             {<<"language">>, <<"javascript">>},
+%%             {<<"views">>, {[
+%%                 {<<"foo">>, {[
+%%                     {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
+%%                 ]}},
+%%                 {<<"foo2">>, {[
+%%                     {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
+%%                 ]}},
+%%                 {<<"foo3">>, {[
+%%                     {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
+%%                 ]}},
+%%                 {<<"foo4">>, {[
+%%                     {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
+%%                 ]}},
+%%                 {<<"foo5">>, {[
+%%                     {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
+%%                 ]}}
+%%             ]}}
+%%         ]}),
+%%         {ok, _} = couch_db:update_doc(MDb1, DDoc, []),
+%%         ok = populate_db(MDb1, 100, 100),
+%%         query_view(MDb1#db.name, "foo", "foo"),
+%%         ok = couch_db:close(MDb1),
+
+%%         {ok, Db1} = couch_db:create(?tempdb(), [?ADMIN_USER]),
+%%         ok = couch_db:close(Db1),
+%%         {ok, Db2} = couch_db:create(?tempdb(), [?ADMIN_USER]),
+%%         ok = couch_db:close(Db2),
+%%         {ok, Db3} = couch_db:create(?tempdb(), [?ADMIN_USER]),
+%%         ok = couch_db:close(Db3),
+
+%%         Writer1 = spawn_writer(Db1#db.name),
+%%         Writer2 = spawn_writer(Db2#db.name),
+
+%%         ?assert(is_process_alive(Writer1)),
+%%         ?assert(is_process_alive(Writer2)),
+
+%%         ?assertEqual(ok, get_writer_status(Writer1)),
+%%         ?assertEqual(ok, get_writer_status(Writer2)),
+
+%%         {ok, MonRef} = couch_mrview:compact(MDb1#db.name, <<"_design/foo">>,
+%%                                             [monitor]),
+
+%%         Writer3 = spawn_writer(Db3#db.name),
+%%         ?assert(is_process_alive(Writer3)),
+%%         ?assertEqual({error, all_dbs_active}, get_writer_status(Writer3)),
+
+%%         ?assert(is_process_alive(Writer1)),
+%%         ?assert(is_process_alive(Writer2)),
+%%         ?assert(is_process_alive(Writer3)),
+
+%%         receive
+%%             {'DOWN', MonRef, process, _, Reason} ->
+%%                 ?assertEqual(normal, Reason)
+%%         after ?TIMEOUT ->
+%%             erlang:error(
+%%                 {assertion_failed,
+%%                  [{module, ?MODULE}, {line, ?LINE},
+%%                   {reason, "Failure compacting view group"}]})
+%%         end,
+
+%%         ?assertEqual(ok, writer_try_again(Writer3)),
+%%         ?assertEqual(ok, get_writer_status(Writer3)),
+
+%%         ?assert(is_process_alive(Writer1)),
+%%         ?assert(is_process_alive(Writer2)),
+%%         ?assert(is_process_alive(Writer3)),
+
+%%         ?assertEqual(ok, stop_writer(Writer1)),
+%%         ?assertEqual(ok, stop_writer(Writer2)),
+%%         ?assertEqual(ok, stop_writer(Writer3))
+%%     end).
+
+%% create_doc(DbName, DocId) when is_list(DocId) ->
+%%     create_doc(DbName, ?l2b(DocId));
+%% create_doc(DbName, DocId) when is_binary(DocId) ->
+%%     {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
+%%     Doc666 = couch_doc:from_json_obj({[
+%%         {<<"_id">>, DocId},
+%%         {<<"value">>, 999}
+%%     ]}),
+%%     {ok, _} = couch_db:update_docs(Db, [Doc666]),
+%%     couch_db:ensure_full_commit(Db),
+%%     couch_db:close(Db).
+
+%% create_docs(DbName) ->
+%%     {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
+%%     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).
+
+%% populate_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_db(Db, BatchSize, N - length(Docs));
+%% populate_db(_Db, _, _) ->
+%%     ok.
+
+%% create_design_doc(DbName, DDName, ViewName) ->
+%%     {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
+%%     DDoc = couch_doc:from_json_obj({[
+%%         {<<"_id">>, DDName},
+%%         {<<"language">>, <<"javascript">>},
+%%         {<<"views">>, {[
+%%             {ViewName, {[
+%%                 {<<"map">>, <<"function(doc) { emit(doc.value, null); }">>}
+%%             ]}}
+%%         ]}}
+%%     ]}),
+%%     {ok, Rev} = couch_db:update_doc(Db, DDoc, []),
+%%     couch_db:ensure_full_commit(Db),
+%%     couch_db:close(Db),
+%%     Rev.
+
+%% update_design_doc(DbName, DDName, ViewName) ->
+%%     {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
+%%     {ok, Doc} = couch_db:open_doc(Db, DDName, [?ADMIN_USER]),
+%%     {Props} = couch_doc:to_json_obj(Doc, []),
+%%     Rev = couch_util:get_value(<<"_rev">>, Props),
+%%     DDoc = couch_doc:from_json_obj({[
+%%         {<<"_id">>, DDName},
+%%         {<<"_rev">>, Rev},
+%%         {<<"language">>, <<"javascript">>},
+%%         {<<"views">>, {[
+%%             {ViewName, {[
+%%                 {<<"map">>, <<"function(doc) { emit(doc.value, 1); }">>}
+%%             ]}}
+%%         ]}}
+%%     ]}),
+%%     {ok, NewRev} = couch_db:update_doc(Db, DDoc, [?ADMIN_USER]),
+%%     couch_db:ensure_full_commit(Db),
+%%     couch_db:close(Db),
+%%     NewRev.
+
+%% delete_design_doc(DbName, DDName, Rev) ->
+%%     {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
+%%     DDoc = couch_doc:from_json_obj({[
+%%         {<<"_id">>, DDName},
+%%         {<<"_rev">>, couch_doc:rev_to_str(Rev)},
+%%         {<<"_deleted">>, true}
+%%     ]}),
+%%     {ok, _} = couch_db:update_doc(Db, DDoc, [Rev]),
+%%     couch_db:close(Db).
+
+%% db_url(DbName) ->
+%%     Addr = config:get("httpd", "bind_address", "127.0.0.1"),
+%%     Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+%%     "http://" ++ Addr ++ ":" ++ Port ++ "/" ++ ?b2l(DbName).
+
+%% query_view(DbName, DDoc, View) ->
+%%     query_view(DbName, DDoc, View, false).
+
+%% query_view(DbName, DDoc, View, Stale) ->
+%%     {ok, Code, _Headers, Body} = test_request:get(
+%%         db_url(DbName) ++ "/_design/" ++ DDoc ++ "/_view/" ++ View
+%%         ++ case Stale of
+%%                false -> [];
+%%                _ -> "?stale=" ++ atom_to_list(Stale)
+%%            end),
+%%     ?assertEqual(200, Code),
+%%     {Props} = ejson:decode(Body),
+%%     couch_util:get_value(<<"rows">>, Props, []).
+
+%% check_rows_value(Rows, Value) ->
+%%     lists:foreach(
+%%         fun({Row}) ->
+%%             ?assertEqual(Value, couch_util:get_value(<<"value">>, Row))
+%%         end, Rows).
+
+%% view_cleanup(DbName) ->
+%%     {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
+%%     couch_mrview:cleanup(Db),
+%%     couch_db:close(Db).
+
+%% get_db_ref_counter(DbName) ->
+%%     {ok, #db{fd_ref_counter = Ref} = Db} = couch_db:open_int(DbName, []),
+%%     ok = couch_db:close(Db),
+%%     Ref.
+
+%% count_db_refs(DbName) ->
+%%     Ref = get_db_ref_counter(DbName),
+%%     % have to sleep a bit to let couchdb cleanup all refs and leave only
+%%     % active ones. otherwise the related tests will randomly fail due to
+%%     % count number mismatch
+%%     timer:sleep(200),
+%%     couch_ref_counter:count(Ref).
+
+%% count_index_files(DbName) ->
+%%     % call server to fetch the index files
+%%     RootDir = config:get("couchdb", "view_index_dir"),
+%%     length(filelib:wildcard(RootDir ++ "/." ++
+%%         binary_to_list(DbName) ++ "_design"++"/mrview/*")).
+
+%% has_doc(DocId1, Rows) ->
+%%     DocId = iolist_to_binary(DocId1),
+%%     lists:any(fun({R}) -> lists:member({<<"id">>, DocId}, R) end, Rows).
+
+%% backup_db_file(DbName) ->
+%%     DbDir = config:get("couchdb", "database_dir"),
+%%     DbFile = filename:join([DbDir, ?b2l(DbName) ++ ".couch"]),
+%%     {ok, _} = file:copy(DbFile, DbFile ++ ".backup"),
+%%     ok.
+
+%% restore_backup_db_file(DbName) ->
+%%     DbDir = config:get("couchdb", "database_dir"),
+%%     stop(whereis(couch_server_sup)),
+%%     DbFile = filename:join([DbDir, ?b2l(DbName) ++ ".couch"]),
+%%     ok = file:delete(DbFile),
+%%     ok = file:rename(DbFile ++ ".backup", DbFile),
+%%     start(),
+%%     ok.
+
+%% compact_db(DbName) ->
+%%     {ok, Db} = couch_db:open_int(DbName, []),
+%%     {ok, _} = couch_db:start_compact(Db),
+%%     ok = couch_db:close(Db),
+%%     wait_db_compact_done(DbName, 10).
+
+%% wait_db_compact_done(_DbName, 0) ->
+%%     erlang:error({assertion_failed,
+%%                   [{module, ?MODULE},
+%%                    {line, ?LINE},
+%%                    {reason, "DB compaction failed to finish"}]});
+%% wait_db_compact_done(DbName, N) ->
+%%     {ok, Db} = couch_db:open_int(DbName, []),
+%%     ok = couch_db:close(Db),
+%%     case is_pid(Db#db.compactor_pid) of
+%%     false ->
+%%         ok;
+%%     true ->
+%%         ok = timer:sleep(?DELAY),
+%%         wait_db_compact_done(DbName, N - 1)
+%%     end.
+
+%% compact_view_group(DbName, DDocId) when is_list(DDocId) ->
+%%     compact_view_group(DbName, ?l2b("_design/" ++ DDocId));
+%% compact_view_group(DbName, DDocId) when is_binary(DDocId) ->
+%%     ok = couch_mrview:compact(DbName, DDocId),
+%%     wait_view_compact_done(DbName, DDocId, 10).
+
+%% wait_view_compact_done(_DbName, _DDocId, 0) ->
+%%     erlang:error({assertion_failed,
+%%                   [{module, ?MODULE},
+%%                    {line, ?LINE},
+%%                    {reason, "DB compaction failed to finish"}]});
+%% wait_view_compact_done(DbName, DDocId, N) ->
+%%     {ok, Code, _Headers, Body} = test_request:get(
+%%         db_url(DbName) ++ "/" ++ ?b2l(DDocId) ++ "/_info"),
+%%     ?assertEqual(200, Code),
+%%     {Info} = ejson: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(?DELAY),
+%%             wait_view_compact_done(DbName, DDocId, N - 1)
+%%     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 ?TIMEOUT ->
+%%         timeout
+%%     end.
+
+%% writer_try_again(Writer) ->
+%%     Ref = make_ref(),
+%%     Writer ! {try_again, Ref},
+%%     receive
+%%         {ok, Ref} ->
+%%             ok
+%%     after ?TIMEOUT ->
+%%         timeout
+%%     end.
+
+%% stop_writer(Writer) ->
+%%     Ref = make_ref(),
+%%     Writer ! {stop, Ref},
+%%     receive
+%%         {ok, Ref} ->
+%%             ok
+%%     after ?TIMEOUT ->
+%%         erlang:error({assertion_failed,
+%%                       [{module, ?MODULE},
+%%                        {line, ?LINE},
+%%                        {reason, "Timeout on stopping process"}]})
+%%     end.
+
+%% 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.
+
+%% read_header(File) ->
+%%     {ok, Fd} = couch_file:open(File),
+%%     {ok, {_Sig, Header}} = couch_file:read_header(Fd),
+%%     couch_file:close(Fd),
+%%     Header.


[36/50] [abbrv] Move files out of test/couchdb into top level test/ folder

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_auth_cache_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_auth_cache_tests.erl b/test/couchdb/couch_auth_cache_tests.erl
deleted file mode 100644
index 3b2321c..0000000
--- a/test/couchdb/couch_auth_cache_tests.erl
+++ /dev/null
@@ -1,238 +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(couch_auth_cache_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
--define(SALT, <<"SALT">>).
--define(TIMEOUT, 1000).
-
-
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
-setup() ->
-    DbName = ?tempdb(),
-    couch_config:set("couch_httpd_auth", "authentication_db",
-                     ?b2l(DbName), false),
-    DbName.
-
-teardown(DbName) ->
-    ok = couch_server:delete(DbName, [?ADMIN_USER]),
-    ok.
-
-
-couch_auth_cache_test_() ->
-    {
-        "CouchDB auth cache tests",
-        {
-            setup,
-            fun start/0, fun stop/1,
-            {
-                foreach,
-                fun setup/0, fun teardown/1,
-                [
-                    fun should_get_nil_on_missed_cache/1,
-                    fun should_get_right_password_hash/1,
-                    fun should_ensure_doc_hash_equals_cached_one/1,
-                    fun should_update_password/1,
-                    fun should_cleanup_cache_after_userdoc_deletion/1,
-                    fun should_restore_cache_after_userdoc_recreation/1,
-                    fun should_drop_cache_on_auth_db_change/1,
-                    fun should_restore_cache_on_auth_db_change/1,
-                    fun should_recover_cache_after_shutdown/1
-                ]
-            }
-        }
-    }.
-
-
-should_get_nil_on_missed_cache(_) ->
-    ?_assertEqual(nil, couch_auth_cache:get_user_creds("joe")).
-
-should_get_right_password_hash(DbName) ->
-    ?_test(begin
-        PasswordHash = hash_password("pass1"),
-        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
-        Creds = couch_auth_cache:get_user_creds("joe"),
-        ?assertEqual(PasswordHash,
-                      couch_util:get_value(<<"password_sha">>, Creds))
-    end).
-
-should_ensure_doc_hash_equals_cached_one(DbName) ->
-    ?_test(begin
-        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
-        Creds = couch_auth_cache:get_user_creds("joe"),
-
-        CachedHash = couch_util:get_value(<<"password_sha">>, Creds),
-        StoredHash = get_user_doc_password_sha(DbName, "joe"),
-        ?assertEqual(StoredHash, CachedHash)
-    end).
-
-should_update_password(DbName) ->
-    ?_test(begin
-        PasswordHash = hash_password("pass2"),
-        {ok, Rev} = update_user_doc(DbName, "joe", "pass1"),
-        {ok, _} = update_user_doc(DbName, "joe", "pass2", Rev),
-        Creds = couch_auth_cache:get_user_creds("joe"),
-        ?assertEqual(PasswordHash,
-                      couch_util:get_value(<<"password_sha">>, Creds))
-    end).
-
-should_cleanup_cache_after_userdoc_deletion(DbName) ->
-    ?_test(begin
-        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
-        delete_user_doc(DbName, "joe"),
-        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe"))
-    end).
-
-should_restore_cache_after_userdoc_recreation(DbName) ->
-    ?_test(begin
-        PasswordHash = hash_password("pass5"),
-        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
-        delete_user_doc(DbName, "joe"),
-        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe")),
-
-        {ok, _} = update_user_doc(DbName, "joe", "pass5"),
-        Creds = couch_auth_cache:get_user_creds("joe"),
-
-        ?assertEqual(PasswordHash,
-                      couch_util:get_value(<<"password_sha">>, Creds))
-    end).
-
-should_drop_cache_on_auth_db_change(DbName) ->
-    ?_test(begin
-        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
-        full_commit(DbName),
-        couch_config:set("couch_httpd_auth", "authentication_db",
-                         ?b2l(?tempdb()), false),
-        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe"))
-    end).
-
-should_restore_cache_on_auth_db_change(DbName) ->
-    ?_test(begin
-        PasswordHash = hash_password("pass1"),
-        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
-        Creds = couch_auth_cache:get_user_creds("joe"),
-        full_commit(DbName),
-
-        DbName1 = ?tempdb(),
-        couch_config:set("couch_httpd_auth", "authentication_db",
-                         ?b2l(DbName1), false),
-
-        {ok, _} = update_user_doc(DbName1, "joe", "pass5"),
-        full_commit(DbName1),
-
-        couch_config:set("couch_httpd_auth", "authentication_db",
-                         ?b2l(DbName), false),
-
-        Creds = couch_auth_cache:get_user_creds("joe"),
-        ?assertEqual(PasswordHash,
-                      couch_util:get_value(<<"password_sha">>, Creds))
-    end).
-
-should_recover_cache_after_shutdown(DbName) ->
-    ?_test(begin
-        PasswordHash = hash_password("pass2"),
-        {ok, Rev0} = update_user_doc(DbName, "joe", "pass1"),
-        {ok, Rev1} = update_user_doc(DbName, "joe", "pass2", Rev0),
-        full_commit(DbName),
-        shutdown_db(DbName),
-        {ok, Rev1} = get_doc_rev(DbName, "joe"),
-        ?assertEqual(PasswordHash, get_user_doc_password_sha(DbName, "joe"))
-    end).
-
-
-update_user_doc(DbName, UserName, Password) ->
-    update_user_doc(DbName, UserName, Password, nil).
-
-update_user_doc(DbName, UserName, Password, Rev) ->
-    User = iolist_to_binary(UserName),
-    Doc = couch_doc:from_json_obj({[
-        {<<"_id">>, <<"org.couchdb.user:", User/binary>>},
-        {<<"name">>, User},
-        {<<"type">>, <<"user">>},
-        {<<"salt">>, ?SALT},
-        {<<"password_sha">>, hash_password(Password)},
-        {<<"roles">>, []}
-    ] ++ case Rev of
-            nil -> [];
-            _ ->   [{<<"_rev">>, Rev}]
-         end
-    }),
-    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
-    {ok, NewRev} = couch_db:update_doc(AuthDb, Doc, []),
-    ok = couch_db:close(AuthDb),
-    {ok, couch_doc:rev_to_str(NewRev)}.
-
-hash_password(Password) ->
-    ?l2b(couch_util:to_hex(crypto:sha(iolist_to_binary([Password, ?SALT])))).
-
-shutdown_db(DbName) ->
-    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
-    ok = couch_db:close(AuthDb),
-    couch_util:shutdown_sync(AuthDb#db.main_pid),
-    ok = timer:sleep(1000).
-
-get_doc_rev(DbName, UserName) ->
-    DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
-    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
-    UpdateRev =
-    case couch_db:open_doc(AuthDb, DocId, []) of
-    {ok, Doc} ->
-        {Props} = couch_doc:to_json_obj(Doc, []),
-        couch_util:get_value(<<"_rev">>, Props);
-    {not_found, missing} ->
-        nil
-    end,
-    ok = couch_db:close(AuthDb),
-    {ok, UpdateRev}.
-
-get_user_doc_password_sha(DbName, UserName) ->
-    DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
-    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
-    {ok, Doc} = couch_db:open_doc(AuthDb, DocId, []),
-    ok = couch_db:close(AuthDb),
-    {Props} = couch_doc:to_json_obj(Doc, []),
-    couch_util:get_value(<<"password_sha">>, Props).
-
-delete_user_doc(DbName, UserName) ->
-    DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
-    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
-    {ok, Doc} = couch_db:open_doc(AuthDb, DocId, []),
-    {Props} = couch_doc:to_json_obj(Doc, []),
-    DeletedDoc = couch_doc:from_json_obj({[
-        {<<"_id">>, DocId},
-        {<<"_rev">>, couch_util:get_value(<<"_rev">>, Props)},
-        {<<"_deleted">>, true}
-    ]}),
-    {ok, _} = couch_db:update_doc(AuthDb, DeletedDoc, []),
-    ok = couch_db:close(AuthDb).
-
-full_commit(DbName) ->
-    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
-    {ok, _} = couch_db:ensure_full_commit(AuthDb),
-    ok = couch_db:close(AuthDb).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_btree_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_btree_tests.erl b/test/couchdb/couch_btree_tests.erl
deleted file mode 100644
index 911640f..0000000
--- a/test/couchdb/couch_btree_tests.erl
+++ /dev/null
@@ -1,551 +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(couch_btree_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(ROWS, 1000).
-
-
-setup() ->
-    {ok, Fd} = couch_file:open(?tempfile(), [create, overwrite]),
-    {ok, Btree} = couch_btree:open(nil, Fd, [{compression, none},
-                                             {reduce, fun reduce_fun/2}]),
-    {Fd, Btree}.
-
-setup_kvs(_) ->
-    setup().
-
-setup_red() ->
-    {_, 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)),
-    {Fd, Btree} = setup(),
-    {ok, Btree1} = couch_btree:add_remove(Btree, EvenOddKVs, []),
-    {Fd, Btree1}.
-setup_red(_) ->
-    setup_red().
-
-teardown(Fd) when is_pid(Fd) ->
-    ok = couch_file:close(Fd);
-teardown({Fd, _}) ->
-    teardown(Fd).
-teardown(_, {Fd, _}) ->
-    teardown(Fd).
-
-
-kvs_test_funs() ->
-    [
-        fun should_set_fd_correctly/2,
-        fun should_set_root_correctly/2,
-        fun should_create_zero_sized_btree/2,
-        fun should_set_reduce_option/2,
-        fun should_fold_over_empty_btree/2,
-        fun should_add_all_keys/2,
-        fun should_continuously_add_new_kv/2,
-        fun should_continuously_remove_keys/2,
-        fun should_insert_keys_in_reversed_order/2,
-        fun should_add_every_odd_key_remove_every_even/2,
-        fun should_add_every_even_key_remove_every_old/2
-    ].
-
-red_test_funs() ->
-    [
-        fun should_reduce_whole_range/2,
-        fun should_reduce_first_half/2,
-        fun should_reduce_second_half/2
-    ].
-
-
-btree_open_test_() ->
-    {ok, Fd} = couch_file:open(?tempfile(), [create, overwrite]),
-    {ok, Btree} = couch_btree:open(nil, Fd, [{compression, none}]),
-    {
-        "Ensure that created btree is really a btree record",
-        ?_assert(is_record(Btree, btree))
-    }.
-
-sorted_kvs_test_() ->
-    Funs = kvs_test_funs(),
-    Sorted = [{Seq, random:uniform()} || Seq <- lists:seq(1, ?ROWS)],
-    {
-        "BTree with sorted keys",
-        {
-            foreachx,
-            fun setup_kvs/1, fun teardown/2,
-            [{Sorted, Fun} || Fun <- Funs]
-        }
-    }.
-
-rsorted_kvs_test_() ->
-    Sorted = [{Seq, random:uniform()} || Seq <- lists:seq(1, ?ROWS)],
-    Funs = kvs_test_funs(),
-    Reversed = Sorted,
-    {
-        "BTree with backward sorted keys",
-        {
-            foreachx,
-            fun setup_kvs/1, fun teardown/2,
-            [{Reversed, Fun} || Fun <- Funs]
-        }
-    }.
-
-shuffled_kvs_test_() ->
-    Funs = kvs_test_funs(),
-    Sorted = [{Seq, random:uniform()} || Seq <- lists:seq(1, ?ROWS)],
-    Shuffled = shuffle(Sorted),
-    {
-        "BTree with shuffled keys",
-        {
-            foreachx,
-            fun setup_kvs/1, fun teardown/2,
-            [{Shuffled, Fun} || Fun <- Funs]
-        }
-    }.
-
-reductions_test_() ->
-    {
-        "BTree reductions",
-        [
-            {
-                "Common tests",
-                {
-                    foreach,
-                    fun setup_red/0, fun teardown/1,
-                    [
-                        fun should_reduce_without_specified_direction/1,
-                        fun should_reduce_forward/1,
-                        fun should_reduce_backward/1
-                    ]
-                }
-            },
-            {
-                "Range requests",
-                [
-                    {
-                        "Forward direction",
-                        {
-                            foreachx,
-                            fun setup_red/1, fun teardown/2,
-                            [{fwd, F} || F <- red_test_funs()]
-                        }
-                    },
-                    {
-                        "Backward direction",
-                        {
-                            foreachx,
-                            fun setup_red/1, fun teardown/2,
-                            [{rev, F} || F <- red_test_funs()]
-                        }
-                    }
-                ]
-            }
-        ]
-    }.
-
-
-should_set_fd_correctly(_, {Fd, Btree}) ->
-    ?_assertMatch(Fd, Btree#btree.fd).
-
-should_set_root_correctly(_, {_, Btree}) ->
-    ?_assertMatch(nil, Btree#btree.root).
-
-should_create_zero_sized_btree(_, {_, Btree}) ->
-    ?_assertMatch(0, couch_btree:size(Btree)).
-
-should_set_reduce_option(_, {_, Btree}) ->
-    ReduceFun = fun reduce_fun/2,
-    Btree1 = couch_btree:set_options(Btree, [{reduce, ReduceFun}]),
-    ?_assertMatch(ReduceFun, Btree1#btree.reduce).
-
-should_fold_over_empty_btree(_, {_, Btree}) ->
-    {ok, _, EmptyRes} = couch_btree:foldl(Btree, fun(_, X) -> {ok, X+1} end, 0),
-    ?_assertEqual(EmptyRes, 0).
-
-should_add_all_keys(KeyValues, {Fd, Btree}) ->
-    {ok, Btree1} = couch_btree:add_remove(Btree, KeyValues, []),
-    [
-        should_return_complete_btree_on_adding_all_keys(KeyValues, Btree1),
-        should_have_non_zero_size(Btree1),
-        should_have_lesser_size_than_file(Fd, Btree1),
-        should_keep_root_pointer_to_kp_node(Fd, Btree1),
-        should_remove_all_keys(KeyValues, Btree1)
-    ].
-
-should_return_complete_btree_on_adding_all_keys(KeyValues, Btree) ->
-    ?_assert(test_btree(Btree, KeyValues)).
-
-should_have_non_zero_size(Btree) ->
-    ?_assert(couch_btree:size(Btree) > 0).
-
-should_have_lesser_size_than_file(Fd, Btree) ->
-    ?_assert((couch_btree:size(Btree) =< couch_file:bytes(Fd))).
-
-should_keep_root_pointer_to_kp_node(Fd, Btree) ->
-    ?_assertMatch({ok, {kp_node, _}},
-                  couch_file:pread_term(Fd, element(1, Btree#btree.root))).
-
-should_remove_all_keys(KeyValues, Btree) ->
-    Keys = keys(KeyValues),
-    {ok, Btree1} = couch_btree:add_remove(Btree, [], Keys),
-    {
-        "Should remove all the keys",
-        [
-            should_produce_valid_btree(Btree1, []),
-            should_be_empty(Btree1)
-        ]
-    }.
-
-should_continuously_add_new_kv(KeyValues, {_, Btree}) ->
-    {Btree1, _} = lists:foldl(
-        fun(KV, {BtAcc, PrevSize}) ->
-            {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [KV], []),
-            ?assert(couch_btree:size(BtAcc2) > PrevSize),
-            {BtAcc2, couch_btree:size(BtAcc2)}
-        end, {Btree, couch_btree:size(Btree)}, KeyValues),
-    {
-        "Should continuously add key-values to btree",
-        [
-            should_produce_valid_btree(Btree1, KeyValues),
-            should_not_be_empty(Btree1)
-        ]
-    }.
-
-should_continuously_remove_keys(KeyValues, {_, Btree}) ->
-    {ok, Btree1} = couch_btree:add_remove(Btree, KeyValues, []),
-    {Btree2, _} = lists:foldl(
-        fun({K, _}, {BtAcc, PrevSize}) ->
-            {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [], [K]),
-            ?assert(couch_btree:size(BtAcc2) < PrevSize),
-            {BtAcc2, couch_btree:size(BtAcc2)}
-        end, {Btree1, couch_btree:size(Btree1)}, KeyValues),
-    {
-        "Should continuously remove keys from btree",
-        [
-            should_produce_valid_btree(Btree2, []),
-            should_be_empty(Btree2)
-        ]
-    }.
-
-should_insert_keys_in_reversed_order(KeyValues, {_, Btree}) ->
-    KeyValuesRev = lists:reverse(KeyValues),
-    {Btree1, _} = lists:foldl(
-        fun(KV, {BtAcc, PrevSize}) ->
-            {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [KV], []),
-            ?assert(couch_btree:size(BtAcc2) > PrevSize),
-            {BtAcc2, couch_btree:size(BtAcc2)}
-        end, {Btree, couch_btree:size(Btree)}, KeyValuesRev),
-    should_produce_valid_btree(Btree1, KeyValues).
-
-should_add_every_odd_key_remove_every_even(KeyValues, {_, Btree}) ->
-    {ok, Btree1} = couch_btree:add_remove(Btree, KeyValues, []),
-    {_, 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),
-    ?_assert(test_add_remove(Btree1, Rem2Keys0, Rem2Keys1)).
-
-should_add_every_even_key_remove_every_old(KeyValues, {_, Btree}) ->
-    {ok, Btree1} = couch_btree:add_remove(Btree, KeyValues, []),
-    {_, 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),
-    ?_assert(test_add_remove(Btree1, Rem2Keys1, Rem2Keys0)).
-
-
-should_reduce_without_specified_direction({_, Btree}) ->
-    ?_assertMatch(
-        {ok, [{{"odd", _}, ?ROWS div 2}, {{"even", _}, ?ROWS div 2}]},
-        fold_reduce(Btree, [])).
-
-should_reduce_forward({_, Btree}) ->
-    ?_assertMatch(
-        {ok, [{{"odd", _}, ?ROWS div 2}, {{"even", _}, ?ROWS div 2}]},
-        fold_reduce(Btree, [{dir, fwd}])).
-
-should_reduce_backward({_, Btree}) ->
-    ?_assertMatch(
-        {ok, [{{"even", _}, ?ROWS div 2}, {{"odd", _}, ?ROWS div 2}]},
-        fold_reduce(Btree, [{dir, rev}])).
-
-should_reduce_whole_range(fwd, {_, Btree}) ->
-    {SK, EK} = {{"even", 0}, {"odd", ?ROWS - 1}},
-    [
-        {
-            "include endkey",
-            ?_assertMatch(
-                {ok, [{{"odd", 1}, ?ROWS div 2},
-                      {{"even", 2}, ?ROWS div 2}]},
-                fold_reduce(Btree, [{dir, fwd},
-                                    {start_key, SK},
-                                    {end_key, EK}]))
-        },
-        {
-            "exclude endkey",
-            ?_assertMatch(
-                {ok, [{{"odd", 1}, (?ROWS div 2) - 1},
-                      {{"even", 2}, ?ROWS div 2}]},
-                fold_reduce(Btree, [{dir, fwd},
-                                    {start_key, SK},
-                                    {end_key_gt, EK}]))
-        }
-    ];
-should_reduce_whole_range(rev, {_, Btree}) ->
-    {SK, EK} = {{"odd", ?ROWS - 1}, {"even", 2}},
-    [
-        {
-            "include endkey",
-            ?_assertMatch(
-                {ok, [{{"even", ?ROWS}, ?ROWS div 2},
-                      {{"odd", ?ROWS - 1}, ?ROWS div 2}]},
-                fold_reduce(Btree, [{dir, rev},
-                                    {start_key, SK},
-                                    {end_key, EK}]))
-        },
-        {
-            "exclude endkey",
-            ?_assertMatch(
-                {ok, [{{"even", ?ROWS}, (?ROWS div 2) - 1},
-                      {{"odd", ?ROWS - 1}, ?ROWS div 2}]},
-                fold_reduce(Btree, [{dir, rev},
-                                    {start_key, SK},
-                                    {end_key_gt, EK}]))
-        }
-    ].
-
-should_reduce_first_half(fwd, {_, Btree}) ->
-    {SK, EK} = {{"even", 0}, {"odd", (?ROWS div 2) - 1}},
-    [
-        {
-            "include endkey",
-            ?_assertMatch(
-                {ok, [{{"odd", 1}, ?ROWS div 4},
-                      {{"even", 2}, ?ROWS div 2}]},
-                fold_reduce(Btree, [{dir, fwd},
-                                    {start_key, SK}, {end_key, EK}]))
-        },
-        {
-            "exclude endkey",
-            ?_assertMatch(
-                {ok, [{{"odd", 1}, (?ROWS div 4) - 1},
-                      {{"even", 2}, ?ROWS div 2}]},
-                fold_reduce(Btree, [{dir, fwd},
-                                    {start_key, SK},
-                                    {end_key_gt, EK}]))
-        }
-    ];
-should_reduce_first_half(rev, {_, Btree}) ->
-    {SK, EK} = {{"odd", ?ROWS - 1}, {"even", ?ROWS div 2}},
-    [
-        {
-            "include endkey",
-            ?_assertMatch(
-                {ok, [{{"even", ?ROWS}, (?ROWS div 4) + 1},
-                      {{"odd", ?ROWS - 1}, ?ROWS div 2}]},
-                fold_reduce(Btree, [{dir, rev},
-                                    {start_key, SK},
-                                    {end_key, EK}]))
-        },
-        {
-            "exclude endkey",
-            ?_assertMatch(
-                {ok, [{{"even", ?ROWS}, ?ROWS div 4},
-                      {{"odd", ?ROWS - 1}, ?ROWS div 2}]},
-                fold_reduce(Btree, [{dir, rev},
-                                    {start_key, SK},
-                                    {end_key_gt, EK}]))
-        }
-    ].
-
-should_reduce_second_half(fwd, {_, Btree}) ->
-    {SK, EK} = {{"even", ?ROWS div 2}, {"odd", ?ROWS - 1}},
-    [
-        {
-            "include endkey",
-            ?_assertMatch(
-                {ok, [{{"odd", 1}, ?ROWS div 2},
-                      {{"even", ?ROWS div 2}, (?ROWS div 4) + 1}]},
-                fold_reduce(Btree, [{dir, fwd},
-                                    {start_key, SK},
-                                    {end_key, EK}]))
-        },
-        {
-            "exclude endkey",
-            ?_assertMatch(
-                {ok, [{{"odd", 1}, (?ROWS div 2) - 1},
-                      {{"even", ?ROWS div 2}, (?ROWS div 4) + 1}]},
-                fold_reduce(Btree, [{dir, fwd},
-                                    {start_key, SK},
-                                    {end_key_gt, EK}]))
-        }
-    ];
-should_reduce_second_half(rev, {_, Btree}) ->
-    {SK, EK} = {{"odd", (?ROWS div 2) + 1}, {"even", 2}},
-    [
-        {
-            "include endkey",
-            ?_assertMatch(
-                {ok, [{{"even", ?ROWS}, ?ROWS div 2},
-                      {{"odd", (?ROWS div 2) + 1}, (?ROWS div 4) + 1}]},
-                fold_reduce(Btree, [{dir, rev},
-                                    {start_key, SK},
-                                    {end_key, EK}]))
-        },
-        {
-            "exclude endkey",
-            ?_assertMatch(
-                {ok, [{{"even", ?ROWS}, (?ROWS div 2) - 1},
-                      {{"odd", (?ROWS div 2) + 1}, (?ROWS div 4) + 1}]},
-                fold_reduce(Btree, [{dir, rev},
-                                    {start_key, SK},
-                                    {end_key_gt, EK}]))
-        }
-    ].
-
-should_produce_valid_btree(Btree, KeyValues) ->
-    ?_assert(test_btree(Btree, KeyValues)).
-
-should_be_empty(Btree) ->
-    ?_assertEqual(couch_btree:size(Btree), 0).
-
-should_not_be_empty(Btree) ->
-    ?_assert(couch_btree:size(Btree) > 0).
-
-fold_reduce(Btree, Opts) ->
-    GroupFun = fun({K1, _}, {K2, _}) ->
-        K1 == K2
-    end,
-    FoldFun = fun(GroupedKey, Unreduced, Acc) ->
-        {ok, [{GroupedKey, couch_btree:final_reduce(Btree, Unreduced)} | Acc]}
-    end,
-    couch_btree:fold_reduce(Btree, FoldFun, [],
-                            [{key_group_fun, GroupFun}] ++ Opts).
-
-
-keys(KVs) ->
-    [K || {K, _} <- KVs].
-
-reduce_fun(reduce, KVs) ->
-    length(KVs);
-reduce_fun(rereduce, Reds) ->
-    lists:sum(Reds).
-
-
-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.
-
-test_btree(Btree, KeyValues) ->
-    ok = test_key_access(Btree, KeyValues),
-    ok = test_lookup_access(Btree, KeyValues),
-    ok = test_final_reductions(Btree, KeyValues),
-    ok = test_traversal_callbacks(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.
-
-test_traversal_callbacks(Btree, _KeyValues) ->
-    FoldFun = fun
-        (visit, _GroupedKey, _Unreduced, Acc) ->
-            {ok, Acc andalso false};
-        (traverse, _LK, _Red, Acc) ->
-            {skip, Acc andalso true}
-    end,
-    % With 250 items the root is a kp. Always skipping should reduce to true.
-    {ok, _, true} = couch_btree:fold(Btree, FoldFun, true, [{dir, fwd}]),
-    ok.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_changes_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_changes_tests.erl b/test/couchdb/couch_changes_tests.erl
deleted file mode 100644
index a129ba2..0000000
--- a/test/couchdb/couch_changes_tests.erl
+++ /dev/null
@@ -1,612 +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(couch_changes_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(ADMIN_USER, {user_ctx, #user_ctx{roles = [<<"_admin">>]}}).
--define(TIMEOUT, 3000).
--define(TEST_TIMEOUT, 10000).
-
--record(row, {
-    id,
-    seq,
-    deleted = false
-}).
-
-
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
-setup() ->
-    DbName = ?tempdb(),
-    {ok, Db} = create_db(DbName),
-    Revs = [R || {ok, R} <- [
-        save_doc(Db, {[{<<"_id">>, <<"doc1">>}]}),
-        save_doc(Db, {[{<<"_id">>, <<"doc2">>}]}),
-        save_doc(Db, {[{<<"_id">>, <<"doc3">>}]}),
-        save_doc(Db, {[{<<"_id">>, <<"doc4">>}]}),
-        save_doc(Db, {[{<<"_id">>, <<"doc5">>}]})
-    ]],
-    Rev = lists:nth(3, Revs),
-    {ok, Rev1} = save_doc(Db, {[{<<"_id">>, <<"doc3">>}, {<<"_rev">>, Rev}]}),
-    Revs1 = Revs ++ [Rev1],
-    Revs2 = Revs1 ++ [R || {ok, R} <- [
-        save_doc(Db, {[{<<"_id">>, <<"doc6">>}]}),
-        save_doc(Db, {[{<<"_id">>, <<"_design/foo">>}]}),
-        save_doc(Db, {[{<<"_id">>, <<"doc7">>}]}),
-        save_doc(Db, {[{<<"_id">>, <<"doc8">>}]})
-    ]],
-    {DbName, list_to_tuple(Revs2)}.
-
-teardown({DbName, _}) ->
-    delete_db(DbName),
-    ok.
-
-
-changes_test_() ->
-    {
-        "Changes feeed",
-        {
-            setup,
-            fun start/0, fun stop/1,
-            [
-                filter_by_doc_id(),
-                filter_by_design(),
-                continuous_feed(),
-                filter_by_custom_function()
-            ]
-        }
-    }.
-
-filter_by_doc_id() ->
-    {
-        "Filter _doc_id",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                fun should_filter_by_specific_doc_ids/1,
-                fun should_filter_by_specific_doc_ids_descending/1,
-                fun should_filter_by_specific_doc_ids_with_since/1,
-                fun should_filter_by_specific_doc_ids_no_result/1,
-                fun should_handle_deleted_docs/1
-            ]
-        }
-    }.
-
-filter_by_design() ->
-    {
-        "Filter _design",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                fun should_emit_only_design_documents/1
-            ]
-        }
-    }.
-
-filter_by_custom_function() ->
-    {
-        "Filter function",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                fun should_receive_heartbeats/1
-            ]
-        }
-    }.
-
-continuous_feed() ->
-    {
-        "Continuous Feed",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                fun should_filter_continuous_feed_by_specific_doc_ids/1
-            ]
-        }
-    }.
-
-
-should_filter_by_specific_doc_ids({DbName, _}) ->
-    ?_test(
-        begin
-            ChangesArgs = #changes_args{
-                filter = "_doc_ids"
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-
-            {Rows, LastSeq} = wait_finished(Consumer),
-            {ok, Db} = couch_db:open_int(DbName, []),
-            UpSeq = couch_db:get_update_seq(Db),
-            couch_db:close(Db),
-            stop_consumer(Consumer),
-
-            ?assertEqual(2, length(Rows)),
-            [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
-            ?assertEqual(<<"doc4">>, Id1),
-            ?assertEqual(4, Seq1),
-            ?assertEqual(<<"doc3">>, Id2),
-            ?assertEqual(6, Seq2),
-            ?assertEqual(UpSeq, LastSeq)
-        end).
-
-should_filter_by_specific_doc_ids_descending({DbName, _}) ->
-    ?_test(
-        begin
-            ChangesArgs = #changes_args{
-                filter = "_doc_ids",
-                dir = rev
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-
-            {Rows, LastSeq} = wait_finished(Consumer),
-            {ok, Db} = couch_db:open_int(DbName, []),
-            couch_db:close(Db),
-            stop_consumer(Consumer),
-
-            ?assertEqual(2, length(Rows)),
-            [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
-            ?assertEqual(<<"doc3">>, Id1),
-            ?assertEqual(6, Seq1),
-            ?assertEqual(<<"doc4">>, Id2),
-            ?assertEqual(4, Seq2),
-            ?assertEqual(4, LastSeq)
-        end).
-
-should_filter_by_specific_doc_ids_with_since({DbName, _}) ->
-    ?_test(
-        begin
-            ChangesArgs = #changes_args{
-                filter = "_doc_ids",
-                since = 5
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-
-            {Rows, LastSeq} = wait_finished(Consumer),
-            {ok, Db} = couch_db:open_int(DbName, []),
-            UpSeq = couch_db:get_update_seq(Db),
-            couch_db:close(Db),
-            stop_consumer(Consumer),
-
-            ?assertEqual(1, length(Rows)),
-            [#row{seq = Seq1, id = Id1}] = Rows,
-            ?assertEqual(<<"doc3">>, Id1),
-            ?assertEqual(6, Seq1),
-            ?assertEqual(UpSeq, LastSeq)
-        end).
-
-should_filter_by_specific_doc_ids_no_result({DbName, _}) ->
-    ?_test(
-        begin
-            ChangesArgs = #changes_args{
-                filter = "_doc_ids",
-                since = 6
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-
-            {Rows, LastSeq} = wait_finished(Consumer),
-            {ok, Db} = couch_db:open_int(DbName, []),
-            UpSeq = couch_db:get_update_seq(Db),
-            couch_db:close(Db),
-            stop_consumer(Consumer),
-
-            ?assertEqual(0, length(Rows)),
-            ?assertEqual(UpSeq, LastSeq)
-        end).
-
-should_handle_deleted_docs({DbName, Revs}) ->
-    ?_test(
-        begin
-            Rev3_2 = element(6, Revs),
-            {ok, Db} = couch_db:open_int(DbName, []),
-            {ok, _} = save_doc(
-                Db,
-                {[{<<"_id">>, <<"doc3">>},
-                  {<<"_deleted">>, true},
-                  {<<"_rev">>, Rev3_2}]}),
-
-            ChangesArgs = #changes_args{
-                filter = "_doc_ids",
-                since = 9
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-
-            {Rows, LastSeq} = wait_finished(Consumer),
-            couch_db:close(Db),
-            stop_consumer(Consumer),
-
-            ?assertEqual(1, length(Rows)),
-            ?assertMatch(
-                [#row{seq = LastSeq, id = <<"doc3">>, deleted = true}],
-                Rows
-            ),
-            ?assertEqual(11, LastSeq)
-        end).
-
-should_filter_continuous_feed_by_specific_doc_ids({DbName, Revs}) ->
-    ?_test(
-        begin
-            {ok, Db} = couch_db:open_int(DbName, []),
-            ChangesArgs = #changes_args{
-                filter = "_doc_ids",
-                feed = "continuous"
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-            pause(Consumer),
-
-            Rows = get_rows(Consumer),
-            ?assertEqual(2, length(Rows)),
-            [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
-            ?assertEqual(<<"doc4">>, Id1),
-            ?assertEqual(4, Seq1),
-            ?assertEqual(<<"doc3">>, Id2),
-            ?assertEqual(6, Seq2),
-
-            clear_rows(Consumer),
-            {ok, _Rev9} = save_doc(Db, {[{<<"_id">>, <<"doc9">>}]}),
-            {ok, _Rev10} = save_doc(Db, {[{<<"_id">>, <<"doc10">>}]}),
-            unpause(Consumer),
-            pause(Consumer),
-            ?assertEqual([], get_rows(Consumer)),
-
-            Rev4 = element(4, Revs),
-            Rev3_2 = element(6, Revs),
-            {ok, Rev4_2} = save_doc(Db, {[{<<"_id">>, <<"doc4">>},
-                                          {<<"_rev">>, Rev4}]}),
-            {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc11">>}]}),
-            {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc4">>},
-                                     {<<"_rev">>, Rev4_2}]}),
-            {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc12">>}]}),
-            {ok, Rev3_3} = save_doc(Db, {[{<<"_id">>, <<"doc3">>},
-                                          {<<"_rev">>, Rev3_2}]}),
-            unpause(Consumer),
-            pause(Consumer),
-
-            NewRows = get_rows(Consumer),
-            ?assertEqual(2, length(NewRows)),
-            [Row14, Row16] = NewRows,
-            ?assertEqual(<<"doc4">>, Row14#row.id),
-            ?assertEqual(15, Row14#row.seq),
-            ?assertEqual(<<"doc3">>, Row16#row.id),
-            ?assertEqual(17, Row16#row.seq),
-
-            clear_rows(Consumer),
-            {ok, _Rev3_4} = save_doc(Db, {[{<<"_id">>, <<"doc3">>},
-                                           {<<"_rev">>, Rev3_3}]}),
-            unpause(Consumer),
-            pause(Consumer),
-
-            FinalRows = get_rows(Consumer),
-
-            unpause(Consumer),
-            stop_consumer(Consumer),
-
-            ?assertMatch([#row{seq = 18, id = <<"doc3">>}], FinalRows)
-        end).
-
-should_emit_only_design_documents({DbName, Revs}) ->
-    ?_test(
-        begin
-            ChangesArgs = #changes_args{
-                filter = "_design"
-            },
-            Consumer = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
-
-            {Rows, LastSeq} = wait_finished(Consumer),
-            {ok, Db} = couch_db:open_int(DbName, []),
-            UpSeq = couch_db:get_update_seq(Db),
-            couch_db:close(Db),
-
-            ?assertEqual(1, length(Rows)),
-            ?assertEqual(UpSeq, LastSeq),
-            ?assertEqual([#row{seq = 8, id = <<"_design/foo">>}], Rows),
-
-            stop_consumer(Consumer),
-
-            {ok, Db2} = couch_db:open_int(DbName, [?ADMIN_USER]),
-            {ok, _} = save_doc(Db2, {[{<<"_id">>, <<"_design/foo">>},
-                                      {<<"_rev">>, element(8, Revs)},
-                                      {<<"_deleted">>, true}]}),
-
-            Consumer2 = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
-
-            {Rows2, LastSeq2} = wait_finished(Consumer2),
-            UpSeq2 = UpSeq + 1,
-            couch_db:close(Db2),
-
-            ?assertEqual(1, length(Rows2)),
-            ?assertEqual(UpSeq2, LastSeq2),
-            ?assertEqual([#row{seq = 11,
-                               id = <<"_design/foo">>,
-                               deleted = true}],
-                          Rows2)
-        end).
-
-should_receive_heartbeats(_) ->
-    {timeout, ?TEST_TIMEOUT div 1000,
-     ?_test(
-         begin
-             DbName = ?tempdb(),
-             Timeout = 100,
-             {ok, Db} = create_db(DbName),
-
-             {ok, _} = save_doc(Db, {[
-                 {<<"_id">>, <<"_design/filtered">>},
-                 {<<"language">>, <<"javascript">>},
-                     {<<"filters">>, {[
-                         {<<"foo">>, <<"function(doc) {
-                             return ['doc10', 'doc11', 'doc12'].indexOf(doc._id) != -1;}">>
-                     }]}}
-             ]}),
-
-             ChangesArgs = #changes_args{
-                 filter = "filtered/foo",
-                 feed = "continuous",
-                 timeout = 10000,
-                 heartbeat = 1000
-             },
-             Consumer = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
-
-             {ok, _Rev1} = save_doc(Db, {[{<<"_id">>, <<"doc1">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev2} = save_doc(Db, {[{<<"_id">>, <<"doc2">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev3} = save_doc(Db, {[{<<"_id">>, <<"doc3">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev4} = save_doc(Db, {[{<<"_id">>, <<"doc4">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev5} = save_doc(Db, {[{<<"_id">>, <<"doc5">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev6} = save_doc(Db, {[{<<"_id">>, <<"doc6">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev7} = save_doc(Db, {[{<<"_id">>, <<"doc7">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev8} = save_doc(Db, {[{<<"_id">>, <<"doc8">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev9} = save_doc(Db, {[{<<"_id">>, <<"doc9">>}]}),
-
-             Heartbeats = get_heartbeats(Consumer),
-             ?assert(Heartbeats > 0),
-
-             {ok, _Rev10} = save_doc(Db, {[{<<"_id">>, <<"doc10">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev11} = save_doc(Db, {[{<<"_id">>, <<"doc11">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev12} = save_doc(Db, {[{<<"_id">>, <<"doc12">>}]}),
-
-             Heartbeats2 = get_heartbeats(Consumer),
-             ?assert(Heartbeats2 > Heartbeats),
-
-             Rows = get_rows(Consumer),
-             ?assertEqual(3, length(Rows)),
-
-             {ok, _Rev13} = save_doc(Db, {[{<<"_id">>, <<"doc13">>}]}),
-             timer:sleep(Timeout),
-             {ok, _Rev14} = save_doc(Db, {[{<<"_id">>, <<"doc14">>}]}),
-             timer:sleep(Timeout),
-
-             Heartbeats3 = get_heartbeats(Consumer),
-             ?assert(Heartbeats3 > Heartbeats2)
-        end)}.
-
-
-save_doc(Db, Json) ->
-    Doc = couch_doc:from_json_obj(Json),
-    {ok, Rev} = couch_db:update_doc(Db, Doc, []),
-    {ok, couch_doc:rev_to_str(Rev)}.
-
-get_rows(Consumer) ->
-    Ref = make_ref(),
-    Consumer ! {get_rows, Ref},
-    Resp = receive
-        {rows, Ref, Rows} ->
-            Rows
-    after ?TIMEOUT ->
-        timeout
-    end,
-    ?assertNotEqual(timeout, Resp),
-    Resp.
-
-get_heartbeats(Consumer) ->
-    Ref = make_ref(),
-    Consumer ! {get_heartbeats, Ref},
-    Resp = receive
-        {hearthbeats, Ref, HeartBeats} ->
-            HeartBeats
-    after ?TIMEOUT ->
-        timeout
-    end,
-    ?assertNotEqual(timeout, Resp),
-    Resp.
-
-clear_rows(Consumer) ->
-    Ref = make_ref(),
-    Consumer ! {reset, Ref},
-    Resp = receive
-        {ok, Ref} ->
-            ok
-    after ?TIMEOUT ->
-        timeout
-    end,
-    ?assertNotEqual(timeout, Resp),
-    Resp.
-
-stop_consumer(Consumer) ->
-    Ref = make_ref(),
-    Consumer ! {stop, Ref},
-    Resp = receive
-        {ok, Ref} ->
-            ok
-    after ?TIMEOUT ->
-        timeout
-    end,
-    ?assertNotEqual(timeout, Resp),
-    Resp.
-
-pause(Consumer) ->
-    Ref = make_ref(),
-    Consumer ! {pause, Ref},
-    Resp = receive
-        {paused, Ref} ->
-            ok
-    after ?TIMEOUT ->
-        timeout
-    end,
-    ?assertNotEqual(timeout, Resp),
-    Resp.
-
-unpause(Consumer) ->
-    Ref = make_ref(),
-    Consumer ! {continue, Ref},
-    Resp = receive
-        {ok, Ref} ->
-            ok
-    after ?TIMEOUT ->
-       timeout
-    end,
-    ?assertNotEqual(timeout, Resp),
-    Resp.
-
-wait_finished(_Consumer) ->
-    Resp = receive
-        {consumer_finished, Rows, LastSeq} ->
-            {Rows, LastSeq}
-    after ?TIMEOUT ->
-        timeout
-    end,
-    ?assertNotEqual(timeout, Resp),
-    Resp.
-
-spawn_consumer(DbName, ChangesArgs0, Req) ->
-    Parent = self(),
-    spawn(fun() ->
-        put(heartbeat_count, 0),
-        Callback = fun
-            ({change, {Change}, _}, _, Acc) ->
-                Id = couch_util:get_value(<<"id">>, Change),
-                Seq = couch_util:get_value(<<"seq">>, Change),
-                Del = couch_util:get_value(<<"deleted">>, Change, false),
-                [#row{id = Id, seq = Seq, deleted = Del} | Acc];
-            ({stop, LastSeq}, _, Acc) ->
-                Parent ! {consumer_finished, lists:reverse(Acc), LastSeq},
-                stop_loop(Parent, Acc);
-            (timeout, _, Acc) ->
-                put(heartbeat_count, get(heartbeat_count) + 1),
-                maybe_pause(Parent, Acc);
-            (_, _, Acc) ->
-                maybe_pause(Parent, Acc)
-        end,
-        {ok, Db} = couch_db:open_int(DbName, []),
-        ChangesArgs = case (ChangesArgs0#changes_args.timeout =:= undefined)
-            andalso (ChangesArgs0#changes_args.heartbeat =:= undefined) of
-            true ->
-                ChangesArgs0#changes_args{timeout = 10, heartbeat = 10};
-            false ->
-                ChangesArgs0
-        end,
-        FeedFun = couch_changes:handle_changes(ChangesArgs, Req, Db),
-        try
-            FeedFun({Callback, []})
-        catch throw:{stop, _} ->
-            ok
-        end,
-        catch couch_db:close(Db)
-    end).
-
-maybe_pause(Parent, Acc) ->
-    receive
-        {get_rows, Ref} ->
-            Parent ! {rows, Ref, lists:reverse(Acc)},
-            maybe_pause(Parent, Acc);
-        {get_heartbeats, Ref} ->
-            Parent ! {hearthbeats, Ref, get(heartbeat_count)},
-            maybe_pause(Parent, Acc);
-        {reset, Ref} ->
-            Parent ! {ok, Ref},
-            maybe_pause(Parent, []);
-        {pause, Ref} ->
-            Parent ! {paused, Ref},
-            pause_loop(Parent, Acc);
-        {stop, Ref} ->
-            Parent ! {ok, Ref},
-            throw({stop, Acc});
-        V ->
-            erlang:error({assertion_failed,
-                      [{module, ?MODULE},
-                       {line, ?LINE},
-                       {value, V},
-                       {reason, "Received unexpected message"}]})
-    after 0 ->
-        Acc
-    end.
-
-pause_loop(Parent, Acc) ->
-    receive
-        {stop, Ref} ->
-            Parent ! {ok, Ref},
-            throw({stop, Acc});
-        {reset, Ref} ->
-            Parent ! {ok, Ref},
-            pause_loop(Parent, []);
-        {continue, Ref} ->
-            Parent ! {ok, Ref},
-            Acc;
-        {get_rows, Ref} ->
-            Parent ! {rows, Ref, lists:reverse(Acc)},
-            pause_loop(Parent, Acc)
-    end.
-
-stop_loop(Parent, Acc) ->
-    receive
-        {get_rows, Ref} ->
-            Parent ! {rows, Ref, lists:reverse(Acc)},
-            stop_loop(Parent, Acc);
-        {stop, Ref} ->
-            Parent ! {ok, Ref},
-            Acc
-    end.
-
-create_db(DbName) ->
-    couch_db:create(DbName, [?ADMIN_USER, overwrite]).
-
-delete_db(DbName) ->
-    ok = couch_server:delete(DbName, [?ADMIN_USER]).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_config_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_config_tests.erl b/test/couchdb/couch_config_tests.erl
deleted file mode 100644
index 9e9dfe7..0000000
--- a/test/couchdb/couch_config_tests.erl
+++ /dev/null
@@ -1,463 +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(couch_config_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(SHORT_TIMEOUT, 100).
--define(TIMEOUT, 1000).
-
--define(CONFIG_DEFAULT,
-        filename:join([?BUILDDIR, "etc", "couchdb", "default_dev.ini"])).
--define(CONFIG_FIXTURE_1,
-        filename:join([?FIXTURESDIR, "couch_config_tests_1.ini"])).
--define(CONFIG_FIXTURE_2,
-        filename:join([?FIXTURESDIR, "couch_config_tests_2.ini"])).
--define(CONFIG_FIXTURE_TEMP,
-    begin
-        FileName = filename:join([?TEMPDIR, "couch_config_temp.ini"]),
-        {ok, Fd} = file:open(FileName, write),
-        ok = file:truncate(Fd),
-        ok = file:close(Fd),
-        FileName
-    end).
-
-
-setup() ->
-    setup(?CONFIG_CHAIN).
-setup({temporary, Chain}) ->
-    setup(Chain);
-setup({persistent, Chain}) ->
-    setup(lists:append(Chain, [?CONFIG_FIXTURE_TEMP]));
-setup(Chain) ->
-    {ok, Pid} = couch_config:start_link(Chain),
-    Pid.
-
-setup_empty() ->
-    setup([]).
-
-setup_register() ->
-    ConfigPid = setup(),
-    SentinelFunc = fun() ->
-        % Ping/Pong to make sure we wait for this
-        % process to die
-        receive
-            {ping, From} ->
-                From ! pong
-        end
-    end,
-    SentinelPid = spawn(SentinelFunc),
-    {ConfigPid, SentinelPid}.
-
-teardown({ConfigPid, SentinelPid}) ->
-    teardown(ConfigPid),
-    case process_info(SentinelPid) of
-        undefined -> ok;
-        _ ->
-            SentinelPid ! {ping, self()},
-            receive
-                pong ->
-                    ok
-            after 100 ->
-                throw({timeout_error, registered_pid})
-            end
-    end;
-teardown(Pid) ->
-    couch_config:stop(),
-    erlang:monitor(process, Pid),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout_error, config_stop})
-    end.
-teardown(_, Pid) ->
-    teardown(Pid).
-
-
-couch_config_test_() ->
-    {
-        "CouchDB config tests",
-        [
-            couch_config_get_tests(),
-            couch_config_set_tests(),
-            couch_config_del_tests(),
-            config_override_tests(),
-            config_persistent_changes_tests(),
-            config_register_tests(),
-            config_no_files_tests()
-        ]
-    }.
-
-couch_config_get_tests() ->
-    {
-        "Config get tests",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                should_load_all_configs(),
-                should_locate_daemons_section(),
-                should_locate_mrview_handler(),
-                should_return_undefined_atom_on_missed_section(),
-                should_return_undefined_atom_on_missed_option(),
-                should_return_custom_default_value_on_missed_option(),
-                should_only_return_default_on_missed_option(),
-                should_get_binary_option()
-            ]
-        }
-    }.
-
-couch_config_set_tests() ->
-    {
-        "Config set tests",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                should_update_option(),
-                should_create_new_section(),
-                should_set_binary_option()
-            ]
-        }
-    }.
-
-couch_config_del_tests() ->
-    {
-        "Config deletion tests",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                should_return_undefined_atom_after_option_deletion(),
-                should_be_ok_on_deleting_unknown_options(),
-                should_delete_binary_option()
-            ]
-        }
-    }.
-
-config_override_tests() ->
-    {
-        "Configs overide tests",
-        {
-            foreachx,
-            fun setup/1, fun teardown/2,
-            [
-                {{temporary, [?CONFIG_DEFAULT]},
-                 fun should_ensure_in_defaults/2},
-                {{temporary, [?CONFIG_DEFAULT, ?CONFIG_FIXTURE_1]},
-                 fun should_override_options/2},
-                {{temporary, [?CONFIG_DEFAULT, ?CONFIG_FIXTURE_2]},
-                 fun should_create_new_sections_on_override/2},
-                {{temporary, [?CONFIG_DEFAULT, ?CONFIG_FIXTURE_1,
-                              ?CONFIG_FIXTURE_2]},
-                 fun should_win_last_in_chain/2}
-            ]
-        }
-    }.
-
-config_persistent_changes_tests() ->
-    {
-        "Config persistent changes",
-        {
-            foreachx,
-            fun setup/1, fun teardown/2,
-            [
-                {{persistent, [?CONFIG_DEFAULT]},
-                 fun should_write_changes/2},
-                {{temporary, [?CONFIG_DEFAULT]},
-                 fun should_ensure_that_default_wasnt_modified/2},
-                {{temporary, [?CONFIG_FIXTURE_TEMP]},
-                 fun should_ensure_that_written_to_last_config_in_chain/2}
-            ]
-        }
-    }.
-
-config_register_tests() ->
-    {
-        "Config changes subscriber",
-        {
-            foreach,
-            fun setup_register/0, fun teardown/1,
-            [
-                fun should_handle_port_changes/1,
-                fun should_pass_persistent_flag/1,
-                fun should_not_trigger_handler_on_other_options_changes/1,
-                fun should_not_trigger_handler_after_related_process_death/1
-            ]
-        }
-    }.
-
-config_no_files_tests() ->
-    {
-        "Test couch_config with no files",
-        {
-            foreach,
-            fun setup_empty/0, fun teardown/1,
-            [
-                should_ensure_that_no_ini_files_loaded(),
-                should_create_non_persistent_option(),
-                should_create_persistent_option()
-            ]
-        }
-    }.
-
-
-should_load_all_configs() ->
-    ?_assert(length(couch_config:all()) > 0).
-
-should_locate_daemons_section() ->
-    ?_assert(length(couch_config:get("daemons")) > 0).
-
-should_locate_mrview_handler() ->
-    ?_assertEqual("{couch_mrview_http, handle_view_req}",
-                  couch_config:get("httpd_design_handlers", "_view")).
-
-should_return_undefined_atom_on_missed_section() ->
-    ?_assertEqual(undefined,
-                  couch_config:get("foo", "bar")).
-
-should_return_undefined_atom_on_missed_option() ->
-    ?_assertEqual(undefined,
-                  couch_config:get("httpd", "foo")).
-
-should_return_custom_default_value_on_missed_option() ->
-    ?_assertEqual("bar",
-                  couch_config:get("httpd", "foo", "bar")).
-
-should_only_return_default_on_missed_option() ->
-    ?_assertEqual("0",
-                  couch_config:get("httpd", "port", "bar")).
-
-should_get_binary_option() ->
-    ?_assertEqual(<<"baz">>,
-                  couch_config:get(<<"foo">>, <<"bar">>, <<"baz">>)).
-
-should_update_option() ->
-    ?_assertEqual("severe",
-        begin
-            ok = couch_config:set("log", "level", "severe", false),
-            couch_config:get("log", "level")
-        end).
-
-should_create_new_section() ->
-    ?_assertEqual("bang",
-        begin
-            undefined = couch_config:get("new_section", "bizzle"),
-            ok = couch_config:set("new_section", "bizzle", "bang", false),
-            couch_config:get("new_section", "bizzle")
-        end).
-
-should_set_binary_option() ->
-    ?_assertEqual(<<"baz">>,
-        begin
-            ok = couch_config:set(<<"foo">>, <<"bar">>, <<"baz">>, false),
-            couch_config:get(<<"foo">>, <<"bar">>)
-        end).
-
-should_return_undefined_atom_after_option_deletion() ->
-    ?_assertEqual(undefined,
-        begin
-            ok = couch_config:delete("log", "level", false),
-            couch_config:get("log", "level")
-        end).
-
-should_be_ok_on_deleting_unknown_options() ->
-    ?_assertEqual(ok, couch_config:delete("zoo", "boo", false)).
-
-should_delete_binary_option() ->
-    ?_assertEqual(undefined,
-        begin
-            ok = couch_config:set(<<"foo">>, <<"bar">>, <<"baz">>, false),
-            ok = couch_config:delete(<<"foo">>, <<"bar">>, false),
-            couch_config:get(<<"foo">>, <<"bar">>)
-        end).
-
-should_ensure_in_defaults(_, _) ->
-    ?_test(begin
-        ?assertEqual("100",
-                     couch_config:get("couchdb", "max_dbs_open")),
-        ?assertEqual("5984",
-                     couch_config:get("httpd", "port")),
-        ?assertEqual(undefined,
-                     couch_config:get("fizbang", "unicode"))
-    end).
-
-should_override_options(_, _) ->
-    ?_test(begin
-        ?assertEqual("10",
-                     couch_config:get("couchdb", "max_dbs_open")),
-        ?assertEqual("4895",
-                     couch_config:get("httpd", "port"))
-    end).
-
-should_create_new_sections_on_override(_, _) ->
-    ?_test(begin
-        ?assertEqual("80",
-                     couch_config:get("httpd", "port")),
-        ?assertEqual("normalized",
-                     couch_config:get("fizbang", "unicode"))
-    end).
-
-should_win_last_in_chain(_, _) ->
-    ?_assertEqual("80", couch_config:get("httpd", "port")).
-
-should_write_changes(_, _) ->
-    ?_test(begin
-        ?assertEqual("5984",
-                     couch_config:get("httpd", "port")),
-        ?assertEqual(ok,
-                     couch_config:set("httpd", "port", "8080")),
-        ?assertEqual("8080",
-                     couch_config:get("httpd", "port")),
-        ?assertEqual(ok,
-                     couch_config:delete("httpd", "bind_address", "8080")),
-        ?assertEqual(undefined,
-                     couch_config:get("httpd", "bind_address"))
-    end).
-
-should_ensure_that_default_wasnt_modified(_, _) ->
-    ?_test(begin
-        ?assertEqual("5984",
-                     couch_config:get("httpd", "port")),
-        ?assertEqual("127.0.0.1",
-                     couch_config:get("httpd", "bind_address"))
-    end).
-
-should_ensure_that_written_to_last_config_in_chain(_, _) ->
-    ?_test(begin
-        ?assertEqual("8080",
-                     couch_config:get("httpd", "port")),
-        ?assertEqual(undefined,
-                     couch_config:get("httpd", "bind_address"))
-    end).
-
-should_handle_port_changes({_, SentinelPid}) ->
-    ?_assert(begin
-        MainProc = self(),
-        Port = "8080",
-
-        couch_config:register(
-            fun("httpd", "port", Value) ->
-                % couch_config catches every error raised from handler
-                % so it's not possible to just assert on wrong value.
-                % We have to return the result as message
-                MainProc ! (Value =:= Port)
-            end,
-            SentinelPid
-        ),
-        ok = couch_config:set("httpd", "port", Port, false),
-
-        receive
-            R ->
-                R
-        after ?TIMEOUT ->
-             erlang:error({assertion_failed,
-                           [{module, ?MODULE},
-                            {line, ?LINE},
-                            {reason, "Timeout"}]})
-        end
-    end).
-
-should_pass_persistent_flag({_, SentinelPid}) ->
-    ?_assert(begin
-        MainProc = self(),
-
-        couch_config:register(
-            fun("httpd", "port", _, Persist) ->
-                % couch_config catches every error raised from handler
-                % so it's not possible to just assert on wrong value.
-                % We have to return the result as message
-                MainProc ! Persist
-            end,
-            SentinelPid
-        ),
-        ok = couch_config:set("httpd", "port", "8080", false),
-
-        receive
-            false ->
-                true
-        after ?SHORT_TIMEOUT ->
-            false
-        end
-    end).
-
-should_not_trigger_handler_on_other_options_changes({_, SentinelPid}) ->
-    ?_assert(begin
-        MainProc = self(),
-
-        couch_config:register(
-            fun("httpd", "port", _) ->
-                MainProc ! ok
-            end,
-            SentinelPid
-        ),
-        ok = couch_config:set("httpd", "bind_address", "0.0.0.0", false),
-
-        receive
-            ok ->
-                false
-        after ?SHORT_TIMEOUT ->
-            true
-        end
-    end).
-
-should_not_trigger_handler_after_related_process_death({_, SentinelPid}) ->
-    ?_assert(begin
-        MainProc = self(),
-
-        couch_config:register(
-            fun("httpd", "port", _) ->
-                MainProc ! ok
-            end,
-            SentinelPid
-        ),
-
-        SentinelPid ! {ping, MainProc},
-        receive
-            pong ->
-                ok
-        after ?SHORT_TIMEOUT ->
-             erlang:error({assertion_failed,
-                           [{module, ?MODULE},
-                            {line, ?LINE},
-                            {reason, "Timeout"}]})
-        end,
-
-        ok = couch_config:set("httpd", "port", "12345", false),
-
-        receive
-            ok ->
-                false
-        after ?SHORT_TIMEOUT ->
-            true
-        end
-    end).
-
-should_ensure_that_no_ini_files_loaded() ->
-    ?_assertEqual(0, length(couch_config:all())).
-
-should_create_non_persistent_option() ->
-    ?_assertEqual("80",
-        begin
-            ok = couch_config:set("httpd", "port", "80", false),
-            couch_config:get("httpd", "port")
-        end).
-
-should_create_persistent_option() ->
-    ?_assertEqual("127.0.0.1",
-        begin
-            ok = couch_config:set("httpd", "bind_address", "127.0.0.1"),
-            couch_config:get("httpd", "bind_address")
-        end).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_db_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_db_tests.erl b/test/couchdb/couch_db_tests.erl
deleted file mode 100644
index 3089714..0000000
--- a/test/couchdb/couch_db_tests.erl
+++ /dev/null
@@ -1,114 +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(couch_db_tests).
-
--include("couch_eunit.hrl").
-
--define(TIMEOUT, 120).
-
-
-setup() ->
-    {ok, _} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    couch_config:set("log", "include_sasl", "false", false),
-    ok.
-
-teardown(_) ->
-    couch_server_sup:stop().
-
-
-create_delete_db_test_()->
-    {
-        "Database create/delete tests",
-        {
-            setup,
-            fun setup/0, fun teardown/1,
-            fun(_) ->
-                [should_create_db(),
-                 should_delete_db(),
-                 should_create_multiple_dbs(),
-                 should_delete_multiple_dbs(),
-                 should_create_delete_database_continuously()]
-            end
-        }
-    }.
-
-
-should_create_db() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, []),
-    ok = couch_db:close(Db),
-    {ok, AllDbs} = couch_server:all_databases(),
-    ?_assert(lists:member(DbName, AllDbs)).
-
-should_delete_db() ->
-    DbName = ?tempdb(),
-    couch_db:create(DbName, []),
-    couch_server:delete(DbName, []),
-    {ok, AllDbs} = couch_server:all_databases(),
-    ?_assertNot(lists:member(DbName, AllDbs)).
-
-should_create_multiple_dbs() ->
-    gen_server:call(couch_server, {set_max_dbs_open, 3}),
-
-    DbNames = [?tempdb() || _ <- lists:seq(1, 6)],
-    lists:foreach(fun(DbName) ->
-        {ok, Db} = couch_db:create(DbName, []),
-        ok = couch_db:close(Db)
-    end, DbNames),
-
-    {ok, AllDbs} = couch_server:all_databases(),
-    NumCreated = lists:foldl(fun(DbName, Acc) ->
-        ?assert(lists:member(DbName, AllDbs)),
-        Acc+1
-    end, 0, DbNames),
-
-    ?_assertEqual(NumCreated, 6).
-
-should_delete_multiple_dbs() ->
-    DbNames = [?tempdb() || _ <- lists:seq(1, 6)],
-    lists:foreach(fun(DbName) ->
-        {ok, Db} = couch_db:create(DbName, []),
-        ok = couch_db:close(Db)
-    end, DbNames),
-
-    lists:foreach(fun(DbName) ->
-        ok = couch_server:delete(DbName, [])
-    end, DbNames),
-
-    {ok, AllDbs} = couch_server:all_databases(),
-    NumDeleted = lists:foldl(fun(DbName, Acc) ->
-        ?assertNot(lists:member(DbName, AllDbs)),
-        Acc + 1
-    end, 0, DbNames),
-
-    ?_assertEqual(NumDeleted, 6).
-
-should_create_delete_database_continuously() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, []),
-    couch_db:close(Db),
-    [{timeout, ?TIMEOUT, {integer_to_list(N) ++ " times",
-                           ?_assert(loop(DbName, N))}}
-     || N <- [10, 100, 1000]].
-
-loop(_, 0) ->
-    true;
-loop(DbName, N) ->
-    ok = cycle(DbName),
-    loop(DbName, N - 1).
-
-cycle(DbName) ->
-    ok = couch_server:delete(DbName, []),
-    {ok, Db} = couch_db:create(DbName, []),
-    couch_db:close(Db),
-    ok.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_doc_json_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_doc_json_tests.erl b/test/couchdb/couch_doc_json_tests.erl
deleted file mode 100644
index 1592b6b..0000000
--- a/test/couchdb/couch_doc_json_tests.erl
+++ /dev/null
@@ -1,391 +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(couch_doc_json_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
-
-setup() ->
-    couch_config:start_link(?CONFIG_CHAIN),
-    couch_config:set("attachments", "compression_level", "0", false),
-    ok.
-
-teardown(_) ->
-    couch_config:stop().
-
-
-json_doc_test_() ->
-    {
-        setup,
-        fun setup/0, fun teardown/1,
-        [
-            {
-                "Document from JSON",
-                [
-                    from_json_success_cases(),
-                    from_json_error_cases()
-                ]
-            },
-            {
-                "Document to JSON",
-                [
-                    to_json_success_cases()
-                ]
-            }
-        ]
-    }.
-
-from_json_success_cases() ->
-    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:map(
-        fun({EJson, Expect, Msg}) ->
-            {Msg, ?_assertMatch(Expect, couch_doc:from_json_obj(EJson))}
-        end,
-        Cases).
-
-from_json_error_cases() ->
-    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:map(fun
-        ({EJson, Expect, Msg}) ->
-            Error = (catch couch_doc:from_json_obj(EJson)),
-            {Msg, ?_assertMatch(Expect, Error)};
-        ({EJson, Msg}) ->
-            try
-                couch_doc:from_json_obj(EJson),
-                {"Conversion failed to raise an exception", ?_assert(false)}
-            catch
-                _:_ -> {Msg, ?_assert(true)}
-            end
-    end, Cases).
-
-to_json_success_cases() ->
-    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:map(fun
-        ({Doc, EJson, Msg}) ->
-            {Msg, ?_assertMatch(EJson, couch_doc:to_json_obj(Doc, []))};
-        ({Options, Doc, EJson, Msg}) ->
-            {Msg, ?_assertMatch(EJson, couch_doc:to_json_obj(Doc, Options))}
-    end, Cases).


[24/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 190-json-stream-parse.t etap test suite to eunit


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/bdc3e8bb
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/bdc3e8bb
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/bdc3e8bb

Branch: refs/heads/1963-eunit-bigcouch
Commit: bdc3e8bb29076d57178e065586349d1fe72d26b2
Parents: 102d8e0
Author: Alexander Shorin <kx...@apache.org>
Authored: Wed Jun 4 13:22:13 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:44 2014 -0700

----------------------------------------------------------------------
 test/couchdb/json_stream_parse_tests.erl | 151 ++++++++++++++++++++++++++
 1 file changed, 151 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/bdc3e8bb/test/couchdb/json_stream_parse_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/json_stream_parse_tests.erl b/test/couchdb/json_stream_parse_tests.erl
new file mode 100644
index 0000000..92303b6
--- /dev/null
+++ b/test/couchdb/json_stream_parse_tests.erl
@@ -0,0 +1,151 @@
+% 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(json_stream_parse_tests).
+
+-include("couch_eunit.hrl").
+
+-define(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"}
+    ]
+).
+
+
+raw_json_input_test_() ->
+    Tests = lists:map(
+        fun({EJson, JsonString, Desc}) ->
+            {Desc,
+             ?_assert(equiv(EJson, json_stream_parse:to_ejson(JsonString)))}
+        end, ?CASES),
+    {"Tests with raw JSON string as the input", Tests}.
+
+one_byte_data_fun_test_() ->
+    Tests = lists:map(
+        fun({EJson, JsonString, Desc}) ->
+            DataFun = fun() -> single_byte_data_fun(JsonString) end,
+            {Desc,
+             ?_assert(equiv(EJson, json_stream_parse:to_ejson(DataFun)))}
+        end, ?CASES),
+    {"Tests with a 1 byte output data function as the input", Tests}.
+
+test_multiple_bytes_data_fun_test_() ->
+    Tests = lists:map(
+        fun({EJson, JsonString, Desc}) ->
+            DataFun = fun() -> multiple_bytes_data_fun(JsonString) end,
+            {Desc,
+             ?_assert(equiv(EJson, json_stream_parse:to_ejson(DataFun)))}
+        end, ?CASES),
+    {"Tests with a multiple bytes output data function as the input", Tests}.
+
+
+%% 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]).


[10/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 076-file-compression.t etap test suite to eunit

The original test suite was decoupled into compaction and comparison
cases.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/0511102f
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/0511102f
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/0511102f

Branch: refs/heads/1963-eunit-bigcouch
Commit: 0511102f17bccd1bfb730b90832a986143b11dc2
Parents: 7fc7aa3
Author: Alexander Shorin <kx...@apache.org>
Authored: Thu May 22 20:17:47 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:43 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_file_compression_tests.erl | 239 +++++++++++++++++++
 1 file changed, 239 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/0511102f/test/couchdb/couchdb_file_compression_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_file_compression_tests.erl b/test/couchdb/couchdb_file_compression_tests.erl
new file mode 100644
index 0000000..fd3f513
--- /dev/null
+++ b/test/couchdb/couchdb_file_compression_tests.erl
@@ -0,0 +1,239 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_file_compression_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
+-define(DDOC_ID, <<"_design/test">>).
+-define(DOCS_COUNT, 5000).
+-define(TIMEOUT, 30000).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    Pid.
+
+stop(Pid) ->
+    erlang:monitor(process, Pid),
+    couch_server_sup:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    couch_config:set("couchdb", "file_compression", "none", false),
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+    ok = populate_db(Db, ?DOCS_COUNT),
+    DDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, ?DDOC_ID},
+        {<<"language">>, <<"javascript">>},
+        {<<"views">>, {[
+                {<<"by_id">>, {[
+                    {<<"map">>, <<"function(doc){emit(doc._id, doc.string);}">>}
+                ]}}
+            ]}
+        }
+    ]}),
+    {ok, _} = couch_db:update_doc(Db, DDoc, []),
+    refresh_index(DbName),
+    ok = couch_db:close(Db),
+    DbName.
+
+teardown(DbName) ->
+    ok = couch_server:delete(DbName, [?ADMIN_USER]),
+    ok.
+
+
+couch_auth_cache_test_() ->
+    {
+        "CouchDB file compression tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    fun should_use_none/1,
+                    fun should_use_deflate_1/1,
+                    fun should_use_deflate_9/1,
+                    fun should_use_snappy/1,
+                    fun should_compare_compression_methods/1
+                ]
+            }
+        }
+    }.
+
+
+should_use_none(DbName) ->
+    couch_config:set("couchdb", "file_compression", "none", false),
+    {
+        "Use no compression",
+        [
+            {"compact database", ?_test(compact_db(DbName))},
+            {"compact view", ?_test(compact_view(DbName))}
+        ]
+    }.
+
+should_use_deflate_1(DbName) ->
+    couch_config:set("couchdb", "file_compression", "deflate_1", false),
+    {
+        "Use deflate compression at level 1",
+        [
+            {"compact database", ?_test(compact_db(DbName))},
+            {"compact view", ?_test(compact_view(DbName))}
+        ]
+    }.
+
+should_use_deflate_9(DbName) ->
+    couch_config:set("couchdb", "file_compression", "deflate_9", false),
+    {
+        "Use deflate compression at level 9",
+        [
+            {"compact database", ?_test(compact_db(DbName))},
+            {"compact view", ?_test(compact_view(DbName))}
+        ]
+    }.
+
+should_use_snappy(DbName) ->
+    couch_config:set("couchdb", "file_compression", "snappy", false),
+    {
+        "Use snappy compression",
+        [
+            {"compact database", ?_test(compact_db(DbName))},
+            {"compact view", ?_test(compact_view(DbName))}
+        ]
+    }.
+
+should_compare_compression_methods(DbName) ->
+    {"none > snappy > deflate_1 > deflate_9",
+     {timeout, ?TIMEOUT div 1000, ?_test(compare_compression_methods(DbName))}}.
+
+compare_compression_methods(DbName) ->
+    couch_config:set("couchdb", "file_compression", "none", false),
+    compact_db(DbName),
+    compact_view(DbName),
+    DbSizeNone = db_disk_size(DbName),
+    ViewSizeNone = view_disk_size(DbName),
+
+    couch_config:set("couchdb", "file_compression", "snappy", false),
+    compact_db(DbName),
+    compact_view(DbName),
+    DbSizeSnappy = db_disk_size(DbName),
+    ViewSizeSnappy = view_disk_size(DbName),
+
+    ?assert(DbSizeNone > DbSizeSnappy),
+    ?assert(ViewSizeNone > ViewSizeSnappy),
+
+    couch_config:set("couchdb", "file_compression", "deflate_1", false),
+    compact_db(DbName),
+    compact_view(DbName),
+    DbSizeDeflate1 = db_disk_size(DbName),
+    ViewSizeDeflate1 = view_disk_size(DbName),
+
+    ?assert(DbSizeSnappy > DbSizeDeflate1),
+    ?assert(ViewSizeSnappy > ViewSizeDeflate1),
+
+    couch_config:set("couchdb", "file_compression", "deflate_9", false),
+    compact_db(DbName),
+    compact_view(DbName),
+    DbSizeDeflate9 = db_disk_size(DbName),
+    ViewSizeDeflate9 = view_disk_size(DbName),
+
+    ?assert(DbSizeDeflate1 > DbSizeDeflate9),
+    ?assert(ViewSizeDeflate1 > ViewSizeDeflate9).
+
+
+populate_db(_Db, NumDocs) when NumDocs =< 0 ->
+    ok;
+populate_db(Db, NumDocs) ->
+    Docs = lists:map(
+        fun(_) ->
+            couch_doc:from_json_obj({[
+                {<<"_id">>, couch_uuids:random()},
+                {<<"string">>, ?l2b(lists:duplicate(1000, $X))}
+            ]})
+        end,
+        lists:seq(1, 500)),
+    {ok, _} = couch_db:update_docs(Db, Docs, []),
+    populate_db(Db, NumDocs - 500).
+
+refresh_index(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, DDoc} = couch_db:open_doc(Db, ?DDOC_ID, [ejson_body]),
+    couch_mrview:query_view(Db, DDoc, <<"by_id">>, [{stale, false}]),
+    ok = couch_db:close(Db).
+
+compact_db(DbName) ->
+    DiskSizeBefore = db_disk_size(DbName),
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, CompactPid} = couch_db:start_compact(Db),
+    MonRef = erlang:monitor(process, CompactPid),
+    receive
+        {'DOWN', MonRef, process, CompactPid, normal} ->
+            ok;
+        {'DOWN', MonRef, process, CompactPid, Reason} ->
+            erlang:error({assertion_failed,
+                          [{module, ?MODULE},
+                           {line, ?LINE},
+                           {reason, "Error compacting database: "
+                                    ++ couch_util:to_list(Reason)}]})
+    after ?TIMEOUT ->
+        erlang:error({assertion_failed,
+                      [{module, ?MODULE},
+                       {line, ?LINE},
+                       {reason, "Timeout waiting for database compaction"}]})
+    end,
+    ok = couch_db:close(Db),
+    DiskSizeAfter = db_disk_size(DbName),
+    ?assert(DiskSizeBefore > DiskSizeAfter).
+
+compact_view(DbName) ->
+    DiskSizeBefore = view_disk_size(DbName),
+    {ok, MonRef} = couch_mrview:compact(DbName, ?DDOC_ID, [monitor]),
+    receive
+        {'DOWN', MonRef, process, _CompactPid, normal} ->
+            ok;
+        {'DOWN', MonRef, process, _CompactPid, Reason} ->
+            erlang:error({assertion_failed,
+                          [{module, ?MODULE},
+                           {line, ?LINE},
+                           {reason, "Error compacting view group: "
+                                    ++ couch_util:to_list(Reason)}]})
+    after ?TIMEOUT ->
+        erlang:error({assertion_failed,
+                      [{module, ?MODULE},
+                       {line, ?LINE},
+                       {reason, "Timeout waiting for view group compaction"}]})
+    end,
+    DiskSizeAfter = view_disk_size(DbName),
+    ?assert(DiskSizeBefore > DiskSizeAfter).
+
+db_disk_size(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, Info} = couch_db:get_db_info(Db),
+    ok = couch_db:close(Db),
+    couch_util:get_value(disk_size, Info).
+
+view_disk_size(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, DDoc} = couch_db:open_doc(Db, ?DDOC_ID, [ejson_body]),
+    {ok, Info} = couch_mrview:get_info(Db, DDoc),
+    ok = couch_db:close(Db),
+    couch_util:get_value(disk_size, Info).


[41/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Switch to using test_util:{start,stop}_couch


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/e86e5537
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/e86e5537
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/e86e5537

Branch: refs/heads/1963-eunit-bigcouch
Commit: e86e5537d076306f7e34e574d0bc43642518613c
Parents: 71f3dbe
Author: Russell Branca <ch...@apache.org>
Authored: Mon Aug 11 15:40:05 2014 -0700
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:24:05 2014 -0700

----------------------------------------------------------------------
 test/couch_auth_cache_tests.erl         |  2 +-
 test/couch_changes_tests.erl            | 16 +---------------
 test/couch_db_tests.erl                 |  7 ++-----
 test/couch_util_tests.erl               |  4 ++--
 test/couchdb_attachments_tests.erl      | 16 +++-------------
 test/couchdb_compaction_daemon.erl      | 16 +++-------------
 test/couchdb_cors_tests.erl             | 16 +++-------------
 test/couchdb_csp_tests.erl              | 16 +---------------
 test/couchdb_file_compression_tests.erl | 16 +---------------
 test/couchdb_http_proxy_tests.erl       |  8 ++------
 test/couchdb_os_proc_pool.erl           | 16 +++-------------
 test/couchdb_update_conflicts_tests.erl | 16 +++-------------
 test/couchdb_vhosts_tests.erl           | 18 ++----------------
 test/couchdb_views_tests.erl            | 20 +++-----------------
 14 files changed, 30 insertions(+), 157 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/e86e5537/test/couch_auth_cache_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_auth_cache_tests.erl b/test/couch_auth_cache_tests.erl
index b2c43c3..371cb63 100644
--- a/test/couch_auth_cache_tests.erl
+++ b/test/couch_auth_cache_tests.erl
@@ -36,7 +36,7 @@ couch_auth_cache_test_() ->
         "CouchDB auth cache tests",
         {
             setup,
-            fun start/0, fun stop/1,
+            fun test_util:start_couch/0, fun test_util:stop_couch/1,
             {
                 foreach,
                 fun setup/0, fun teardown/1,

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/e86e5537/test/couch_changes_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_changes_tests.erl b/test/couch_changes_tests.erl
index 7fd4c55..3ae1b52 100644
--- a/test/couch_changes_tests.erl
+++ b/test/couch_changes_tests.erl
@@ -26,20 +26,6 @@
 }).
 
 
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
 setup() ->
     DbName = ?tempdb(),
     {ok, Db} = create_db(DbName),
@@ -71,7 +57,7 @@ changes_test_() ->
         "Changes feeed",
         {
             setup,
-            fun start/0, fun stop/1,
+            fun test_util:start_couch/0, fun test_util:stop_couch/1,
             [
                 filter_by_doc_id(),
                 filter_by_design(),

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/e86e5537/test/couch_db_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_db_tests.erl b/test/couch_db_tests.erl
index d1fdf06..90f0537 100644
--- a/test/couch_db_tests.erl
+++ b/test/couch_db_tests.erl
@@ -18,20 +18,17 @@
 
 
 setup() ->
-    {ok, _} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    ok = test_util:start_couch(),
     couch_config:set("log", "include_sasl", "false", false),
     ok.
 
-teardown(_) ->
-    couch_server_sup:stop().
-
 
 create_delete_db_test_()->
     {
         "Database create/delete tests",
         {
             setup,
-            fun setup/0, fun teardown/1,
+            fun setup/0, fun test_util:stop_couch/1,
             fun(_) ->
                 [should_create_db(),
                  should_delete_db(),

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/e86e5537/test/couch_util_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_util_tests.erl b/test/couch_util_tests.erl
index 17e6942..c5689af 100644
--- a/test/couch_util_tests.erl
+++ b/test/couch_util_tests.erl
@@ -23,13 +23,13 @@ setup() ->
     %% On other hand, we cannot unload driver here due to
     %% {error, not_loaded_by_this_process} while it is. Any ideas is welcome.
     %%
-    couch_server_sup:start_link(?CONFIG_CHAIN),
+    ok = test_util:start_couch(),
     %% couch_config:start_link(?CONFIG_CHAIN),
     %% {ok, _} = couch_drv:start_link(),
     ok.
 
 teardown(_) ->
-    couch_server_sup:stop(),
+    ok = test_util:stop_couch(),
     %% couch_config:stop(),
     %% erl_ddll:unload_driver(couch_icu_driver),
     ok.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/e86e5537/test/couchdb_attachments_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_attachments_tests.erl b/test/couchdb_attachments_tests.erl
index 70587f8..0391822 100644
--- a/test/couchdb_attachments_tests.erl
+++ b/test/couchdb_attachments_tests.erl
@@ -27,22 +27,12 @@
 
 
 start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    ok = test_util:start_couch(),
     % ensure in default compression settings for attachments_compression_tests
     couch_config:set("attachments", "compression_level",
                      ?i2l(?COMPRESSION_LEVEL), false),
     couch_config:set("attachments", "compressible_types", "text/*", false),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
+    ok.
 
 setup() ->
     DbName = ?tempdb(),
@@ -91,7 +81,7 @@ attachments_test_() ->
         "Attachments tests",
         {
             setup,
-            fun start/0, fun stop/1,
+            fun start/0, fun test_util:stop_couch/1,
             [
                 attachments_md5_tests(),
                 attachments_compression_tests()

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/e86e5537/test/couchdb_compaction_daemon.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_compaction_daemon.erl b/test/couchdb_compaction_daemon.erl
index 39e6118..de166a4 100644
--- a/test/couchdb_compaction_daemon.erl
+++ b/test/couchdb_compaction_daemon.erl
@@ -22,20 +22,10 @@
 
 
 start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    ok = test_util:start_couch(),
     couch_config:set("compaction_daemon", "check_interval", "3", false),
     couch_config:set("compaction_daemon", "min_file_size", "100000", false),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
+    ok.
 
 setup() ->
     DbName = ?tempdb(),
@@ -60,7 +50,7 @@ compaction_daemon_test_() ->
         "Compaction daemon tests",
         {
             setup,
-            fun start/0, fun stop/1,
+            fun start/0, fun test_util:stop_couch/1,
             {
                 foreach,
                 fun setup/0, fun teardown/1,

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/e86e5537/test/couchdb_cors_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_cors_tests.erl b/test/couchdb_cors_tests.erl
index 9f927c4..336d5ee 100644
--- a/test/couchdb_cors_tests.erl
+++ b/test/couchdb_cors_tests.erl
@@ -23,20 +23,10 @@
 
 
 start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    ok = test_util:start_couch(),
     ok = couch_config:set("httpd", "enable_cors", "true", false),
     ok = couch_config:set("vhosts", "example.com", "/", false),
-    Pid.
-
-stop(Pid) ->
-    couch_server_sup:stop(),
-    erlang:monitor(process, Pid),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
+    ok.
 
 setup() ->
     DbName = ?tempdb(),
@@ -92,7 +82,7 @@ cors_test_() ->
         "CORS (COUCHDB-431)",
         {
             setup,
-            fun start/0, fun stop/1,
+            fun start/0, fun test_util:stop_couch/1,
             [
                 cors_tests(Funs),
                 vhost_cors_tests(Funs),

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/e86e5537/test/couchdb_csp_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_csp_tests.erl b/test/couchdb_csp_tests.erl
index 9733ad4..0626a08 100644
--- a/test/couchdb_csp_tests.erl
+++ b/test/couchdb_csp_tests.erl
@@ -17,20 +17,6 @@
 -define(TIMEOUT, 1000).
 
 
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    Pid.
-
-stop(Pid) ->
-    couch_server_sup:stop(),
-    erlang:monitor(process, Pid),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
 setup() ->
     ok = couch_config:set("csp", "enable", "true", false),
     Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
@@ -46,7 +32,7 @@ csp_test_() ->
         "Content Security Policy tests",
         {
             setup,
-            fun start/0, fun stop/1,
+            fun test_util:start_couch/0, fun test_util:stop_couch/1,
             {
                 foreach,
                 fun setup/0, fun teardown/1,

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/e86e5537/test/couchdb_file_compression_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_file_compression_tests.erl b/test/couchdb_file_compression_tests.erl
index dc3f939..5573dd8 100644
--- a/test/couchdb_file_compression_tests.erl
+++ b/test/couchdb_file_compression_tests.erl
@@ -21,20 +21,6 @@
 -define(TIMEOUT, 30000).
 
 
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
 setup() ->
     couch_config:set("couchdb", "file_compression", "none", false),
     DbName = ?tempdb(),
@@ -65,7 +51,7 @@ couch_auth_cache_test_() ->
         "CouchDB file compression tests",
         {
             setup,
-            fun start/0, fun stop/1,
+            fun test_util:start_couch/0, fun test_util:stop_couch/1,
             {
                 foreach,
                 fun setup/0, fun teardown/1,

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/e86e5537/test/couchdb_http_proxy_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_http_proxy_tests.erl b/test/couchdb_http_proxy_tests.erl
index 262eb15..0c554ff 100644
--- a/test/couchdb_http_proxy_tests.erl
+++ b/test/couchdb_http_proxy_tests.erl
@@ -31,17 +31,13 @@ start() ->
     % we have to write any config changes to temp ini file to not loose them
     % when supervisor will kill all children due to reaching restart threshold
     % (each httpd_global_handlers changes causes couch_httpd restart)
-    couch_server_sup:start_link(?CONFIG_CHAIN ++ [?CONFIG_FIXTURE_TEMP]),
+    ok = test_util:start_couch(test_util:config_files() ++ [?CONFIG_FIXTURE_TEMP]),
     % 49151 is IANA Reserved, let's assume no one is listening there
     couch_config:set("httpd_global_handlers", "_error",
         "{couch_httpd_proxy, handle_proxy_req, <<\"http://127.0.0.1:49151/\">>}"
     ),
     ok.
 
-stop(_) ->
-    couch_server_sup:stop(),
-    ok.
-
 setup() ->
     {ok, Pid} = test_web:start_link(),
     Value = lists:flatten(io_lib:format(
@@ -68,7 +64,7 @@ http_proxy_test_() ->
         "HTTP Proxy handler tests",
         {
             setup,
-            fun start/0, fun stop/1,
+            fun start/0, fun test_util:stop_couch/1,
             {
                 foreach,
                 fun setup/0, fun teardown/1,

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/e86e5537/test/couchdb_os_proc_pool.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_os_proc_pool.erl b/test/couchdb_os_proc_pool.erl
index 1a37bd6..ae07d58 100644
--- a/test/couchdb_os_proc_pool.erl
+++ b/test/couchdb_os_proc_pool.erl
@@ -19,19 +19,9 @@
 
 
 start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    ok = test_util:start_couch(),
     couch_config:set("query_server_config", "os_process_limit", "3", false),
-    Pid.
-
-stop(Pid) ->
-    couch_server_sup:stop(),
-    erlang:monitor(process, Pid),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
+    ok.
 
 
 os_proc_pool_test_() ->
@@ -39,7 +29,7 @@ os_proc_pool_test_() ->
         "OS processes pool tests",
         {
             setup,
-            fun start/0, fun stop/1,
+            fun start/0, fun test_util:stop_couch/1,
             [
                 should_block_new_proc_on_full_pool(),
                 should_free_slot_on_proc_unexpected_exit()

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/e86e5537/test/couchdb_update_conflicts_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_update_conflicts_tests.erl b/test/couchdb_update_conflicts_tests.erl
index adf1e5c..2450313 100644
--- a/test/couchdb_update_conflicts_tests.erl
+++ b/test/couchdb_update_conflicts_tests.erl
@@ -23,19 +23,9 @@
 
 
 start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    ok = test_util:start_couch(),
     couch_config:set("couchdb", "delayed_commits", "true", false),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
+    ok.
 
 setup() ->
     DbName = ?tempdb(),
@@ -61,7 +51,7 @@ view_indexes_cleanup_test_() ->
         "Update conflicts",
         {
             setup,
-            fun start/0, fun stop/1,
+            fun start/0, fun test_util:stop_couch/1,
             [
                 concurrent_updates(),
                 couchdb_188()

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/e86e5537/test/couchdb_vhosts_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_vhosts_tests.erl b/test/couchdb_vhosts_tests.erl
index fc55c1c..7432022 100644
--- a/test/couchdb_vhosts_tests.erl
+++ b/test/couchdb_vhosts_tests.erl
@@ -20,20 +20,6 @@
 -define(iofmt(S, A), lists:flatten(io_lib:format(S, A))).
 
 
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
 setup() ->
     DbName = ?tempdb(),
     {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
@@ -111,7 +97,7 @@ vhosts_test_() ->
         "Virtual Hosts rewrite tests",
         {
             setup,
-            fun start/0, fun stop/1,
+            fun test_util:start_couch/0, fun test_util:stop_couch/1,
             {
                 foreach,
                 fun setup/0, fun teardown/1,
@@ -138,7 +124,7 @@ oauth_test_() ->
         "Virtual Hosts OAuth tests",
         {
             setup,
-            fun start/0, fun stop/1,
+            fun test_util:start_couch/0, fun test_util:stop_couch/1,
             {
                 foreach,
                 fun setup_oauth/0, fun teardown/1,

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/e86e5537/test/couchdb_views_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_views_tests.erl b/test/couchdb_views_tests.erl
index 24b5e5b..6efa7a1 100644
--- a/test/couchdb_views_tests.erl
+++ b/test/couchdb_views_tests.erl
@@ -21,20 +21,6 @@
 -define(TIMEOUT, 1000).
 
 
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
 setup() ->
     DbName = ?tempdb(),
     {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
@@ -65,7 +51,7 @@ view_indexes_cleanup_test_() ->
         "View indexes cleanup",
         {
             setup,
-            fun start/0, fun stop/1,
+            fun test_util:start_couch/0, fun test_util:stop_couch/1,
             {
                 foreach,
                 fun setup/0, fun teardown/1,
@@ -83,7 +69,7 @@ view_group_db_leaks_test_() ->
         "View group db leaks",
         {
             setup,
-            fun start/0, fun stop/1,
+            fun test_util:start_couch/0, fun test_util:stop_couch/1,
             {
                 foreach,
                 fun setup_with_docs/0, fun teardown/1,
@@ -100,7 +86,7 @@ view_group_shutdown_test_() ->
         "View group shutdown",
         {
             setup,
-            fun start/0, fun stop/1,
+            fun test_util:start_couch/0, fun test_util:stop_couch/1,
             [couchdb_1283()]
         }
     }.


[03/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 121-stats-aggregates.t etap test suite to eunit

Merged into couch_stats_tests suite.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/c1240070
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/c1240070
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/c1240070

Branch: refs/heads/1963-eunit-bigcouch
Commit: c12400708628b91ad4ee866490a9d2d96da07726
Parents: d441903
Author: Alexander Shorin <kx...@apache.org>
Authored: Tue May 27 18:27:53 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:43 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couch_stats_tests.erl              | 225 ++++++++++++++++++-
 .../couchdb/fixtures/couch_stats_aggregates.cfg |  19 ++
 .../couchdb/fixtures/couch_stats_aggregates.ini |  20 ++
 3 files changed, 261 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/c1240070/test/couchdb/couch_stats_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_stats_tests.erl b/test/couchdb/couch_stats_tests.erl
index aaaa687..d156449 100644
--- a/test/couchdb/couch_stats_tests.erl
+++ b/test/couchdb/couch_stats_tests.erl
@@ -15,18 +15,41 @@
 -include("couch_eunit.hrl").
 -include_lib("couchdb/couch_db.hrl").
 
+-define(STATS_CFG_FIXTURE,
+    filename:join([?FIXTURESDIR, "couch_stats_aggregates.cfg"])).
+-define(STATS_INI_FIXTURE,
+    filename:join([?FIXTURESDIR, "couch_stats_aggregates.ini"])).
 -define(TIMEOUT, 1000).
--define(SLEEPTIME, 100).
+-define(TIMEWAIT, 500).
 
 
 setup_collector() ->
     couch_stats_collector:start(),
     ok.
 
+setup_aggregator(_) ->
+    {ok, Pid} = couch_config:start_link([?STATS_INI_FIXTURE]),
+    {ok, _} = couch_stats_collector:start(),
+    {ok, _} = couch_stats_aggregator:start(?STATS_CFG_FIXTURE),
+    Pid.
+
 teardown_collector(_) ->
     couch_stats_collector:stop(),
     ok.
 
+teardown_aggregator(_, Pid) ->
+    couch_stats_aggregator:stop(),
+    couch_stats_collector:stop(),
+    erlang:monitor(process, Pid),
+    couch_config:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, config_stop})
+    end,
+    ok.
+
 
 couch_stats_collector_test_() ->
     {
@@ -51,6 +74,39 @@ couch_stats_collector_test_() ->
         }
     }.
 
+couch_stats_aggregator_test_() ->
+    Funs = [
+        fun should_init_empty_aggregate/2,
+        fun should_get_empty_aggregate/2,
+        fun should_change_stats_on_values_add/2,
+        fun should_change_stats_for_all_times_on_values_add/2,
+        fun should_change_stats_on_values_change/2,
+        fun should_change_stats_for_all_times_on_values_change/2,
+        fun should_not_remove_data_after_some_time_for_0_sample/2,
+        fun should_remove_data_after_some_time_for_other_samples/2
+    ],
+    {
+        "CouchDB stats aggregator tests",
+        [
+            {
+                "Absolute values",
+                {
+                    foreachx,
+                    fun setup_aggregator/1, fun teardown_aggregator/2,
+                    [{absolute, Fun} || Fun <- Funs]
+                }
+            },
+            {
+                "Counters",
+                {
+                    foreachx,
+                    fun setup_aggregator/1, fun teardown_aggregator/2,
+                    [{counter, Fun} || Fun <- Funs]
+                }
+            }
+        ]
+    }.
+
 
 should_increment_counter() ->
     ?_assertEqual(100,
@@ -122,7 +178,7 @@ should_decrement_counter_on_process_exit() ->
             end,
             % sleep for awhile to let collector handle the updates
             % suddenly, it couldn't notice process death instantly
-            timer:sleep(?SLEEPTIME),
+            timer:sleep(?TIMEWAIT),
             couch_stats_collector:get(hoopla)
         end).
 
@@ -138,7 +194,7 @@ should_decrement_for_each_track_process_count_call_on_exit() ->
             after ?TIMEOUT ->
                 throw(timeout)
             end,
-            timer:sleep(?SLEEPTIME),
+            timer:sleep(?TIMEWAIT),
             couch_stats_collector:get(hoopla)
         end).
 
@@ -170,6 +226,158 @@ should_return_absolute_values() ->
             lists:sort(couch_stats_collector:all(absolute))
         end).
 
+should_init_empty_aggregate(absolute, _) ->
+    {Aggs} = couch_stats_aggregator:all(),
+    ?_assertEqual({[{'11', make_agg(<<"randomosity">>,
+                                    null, null, null, null, null)}]},
+                  couch_util:get_value(number, Aggs));
+should_init_empty_aggregate(counter, _) ->
+    {Aggs} = couch_stats_aggregator:all(),
+    ?_assertEqual({[{stuff, make_agg(<<"yay description">>,
+                                     null, null, null, null, null)}]},
+                  couch_util:get_value(testing, Aggs)).
+
+should_get_empty_aggregate(absolute, _) ->
+    ?_assertEqual(make_agg(<<"randomosity">>, null, null, null, null, null),
+             couch_stats_aggregator:get_json({number, '11'}));
+should_get_empty_aggregate(counter, _) ->
+    ?_assertEqual(make_agg(<<"yay description">>, null, null, null, null, null),
+             couch_stats_aggregator:get_json({testing, stuff})).
+
+should_change_stats_on_values_add(absolute, _) ->
+    lists:foreach(fun(X) ->
+        couch_stats_collector:record({number, 11}, X)
+    end, lists:seq(0, 10)),
+    couch_stats_aggregator:collect_sample(),
+    ?_assertEqual(make_agg(<<"randomosity">>, 5.0, 5.0, null, 5.0, 5.0),
+                  couch_stats_aggregator:get_json({number, 11}));
+should_change_stats_on_values_add(counter, _) ->
+    lists:foreach(fun(_) ->
+        couch_stats_collector:increment({testing, stuff})
+    end, lists:seq(1, 100)),
+    couch_stats_aggregator:collect_sample(),
+    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 100.0, null, 100, 100),
+                  couch_stats_aggregator:get_json({testing, stuff})).
+
+should_change_stats_for_all_times_on_values_add(absolute, _) ->
+    lists:foreach(fun(X) ->
+        couch_stats_collector:record({number, 11}, X)
+    end, lists:seq(0, 10)),
+    couch_stats_aggregator:collect_sample(),
+    ?_assertEqual(make_agg(<<"randomosity">>, 5.0, 5.0, null, 5.0, 5.0),
+                  couch_stats_aggregator:get_json({number, 11}, 1));
+should_change_stats_for_all_times_on_values_add(counter, _) ->
+    lists:foreach(fun(_) ->
+        couch_stats_collector:increment({testing, stuff})
+    end, lists:seq(1, 100)),
+    couch_stats_aggregator:collect_sample(),
+    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 100.0, null, 100, 100),
+                  couch_stats_aggregator:get_json({testing, stuff}, 1)).
+
+should_change_stats_on_values_change(absolute, _) ->
+    ?_assertEqual(make_agg(<<"randomosity">>, 20.0, 10.0, 7.071, 5.0, 15.0),
+        begin
+            lists:foreach(fun(X) ->
+                couch_stats_collector:record({number, 11}, X)
+            end, lists:seq(0, 10)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_collector:record({number, 11}, 15),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({number, 11})
+        end);
+should_change_stats_on_values_change(counter, _) ->
+    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 50.0, 70.711, 0, 100),
+        begin
+            lists:foreach(fun(_) ->
+                couch_stats_collector:increment({testing, stuff})
+            end, lists:seq(1, 100)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({testing, stuff})
+        end).
+
+should_change_stats_for_all_times_on_values_change(absolute, _) ->
+    ?_assertEqual(make_agg(<<"randomosity">>, 20.0, 10.0, 7.071, 5.0, 15.0),
+        begin
+            lists:foreach(fun(X) ->
+                couch_stats_collector:record({number, 11}, X)
+            end, lists:seq(0, 10)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_collector:record({number, 11}, 15),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({number, 11}, 1)
+        end);
+should_change_stats_for_all_times_on_values_change(counter, _) ->
+    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 50.0, 70.711, 0, 100),
+        begin
+            lists:foreach(fun(_) ->
+                couch_stats_collector:increment({testing, stuff})
+            end, lists:seq(1, 100)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({testing, stuff}, 1)
+        end).
+
+should_not_remove_data_after_some_time_for_0_sample(absolute, _) ->
+    ?_assertEqual(make_agg(<<"randomosity">>, 20.0, 10.0, 7.071, 5.0, 15.0),
+        begin
+            lists:foreach(fun(X) ->
+                couch_stats_collector:record({number, 11}, X)
+            end, lists:seq(0, 10)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_collector:record({number, 11}, 15),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({number, 11})
+        end);
+should_not_remove_data_after_some_time_for_0_sample(counter, _) ->
+    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 33.333, 57.735, 0, 100),
+        begin
+            lists:foreach(fun(_) ->
+                couch_stats_collector:increment({testing, stuff})
+            end, lists:seq(1, 100)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({testing, stuff})
+        end).
+
+should_remove_data_after_some_time_for_other_samples(absolute, _) ->
+    ?_assertEqual(make_agg(<<"randomosity">>, 15.0, 15.0, null, 15.0, 15.0),
+        begin
+            lists:foreach(fun(X) ->
+                couch_stats_collector:record({number, 11}, X)
+            end, lists:seq(0, 10)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_collector:record({number, 11}, 15),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({number, 11}, 1)
+        end);
+should_remove_data_after_some_time_for_other_samples(counter, _) ->
+    ?_assertEqual(make_agg(<<"yay description">>, 0, 0.0, 0.0, 0, 0),
+        begin
+            lists:foreach(fun(_) ->
+                couch_stats_collector:increment({testing, stuff})
+            end, lists:seq(1, 100)),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            timer:sleep(?TIMEWAIT),
+            couch_stats_aggregator:collect_sample(),
+            couch_stats_aggregator:get_json({testing, stuff}, 1)
+        end).
+
 
 spawn_and_count(N) ->
     Self = self(),
@@ -191,3 +399,14 @@ repeat(_, 0) ->
 repeat(Fun, Count) ->
     Fun(),
     repeat(Fun, Count-1).
+
+make_agg(Desc, Sum, Mean, StdDev, Min, Max) ->
+    {[
+        {description, Desc},
+        {current, Sum},
+        {sum, Sum},
+        {mean, Mean},
+        {stddev, StdDev},
+        {min, Min},
+        {max, Max}
+    ]}.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/c1240070/test/couchdb/fixtures/couch_stats_aggregates.cfg
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/couch_stats_aggregates.cfg b/test/couchdb/fixtures/couch_stats_aggregates.cfg
new file mode 100644
index 0000000..30e475d
--- /dev/null
+++ b/test/couchdb/fixtures/couch_stats_aggregates.cfg
@@ -0,0 +1,19 @@
+% 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"}.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/c1240070/test/couchdb/fixtures/couch_stats_aggregates.ini
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/couch_stats_aggregates.ini b/test/couchdb/fixtures/couch_stats_aggregates.ini
new file mode 100644
index 0000000..cc5cd21
--- /dev/null
+++ b/test/couchdb/fixtures/couch_stats_aggregates.ini
@@ -0,0 +1,20 @@
+; 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]


[12/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 082-config-register.t etap test suite to eunit

Merged into couch_config_tests suite.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/5331d800
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/5331d800
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/5331d800

Branch: refs/heads/1963-eunit-bigcouch
Commit: 5331d8007825727e5495ec0879bfc7526a0cd05c
Parents: fc45cdd
Author: Alexander Shorin <kx...@apache.org>
Authored: Mon May 26 09:26:22 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:43 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couch_config_tests.erl | 147 ++++++++++++++++++++++++++++++-
 1 file changed, 146 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/5331d800/test/couchdb/couch_config_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_config_tests.erl b/test/couchdb/couch_config_tests.erl
index 4bdc333..fdd2479 100644
--- a/test/couchdb/couch_config_tests.erl
+++ b/test/couchdb/couch_config_tests.erl
@@ -15,6 +15,7 @@
 -include("couch_eunit.hrl").
 -include_lib("couchdb/couch_db.hrl").
 
+-define(SHORT_TIMEOUT, 100).
 -define(TIMEOUT, 1000).
 
 -define(CONFIG_DEFAULT,
@@ -43,6 +44,32 @@ setup(Chain) ->
     {ok, Pid} = couch_config:start_link(Chain),
     Pid.
 
+setup_register() ->
+    ConfigPid = setup(),
+    SentinelFunc = fun() ->
+        % Ping/Pong to make sure we wait for this
+        % process to die
+        receive
+            {ping, From} ->
+                From ! pong
+        end
+    end,
+    SentinelPid = spawn(SentinelFunc),
+    {ConfigPid, SentinelPid}.
+
+teardown({ConfigPid, SentinelPid}) ->
+    teardown(ConfigPid),
+    case process_info(SentinelPid) of
+        undefined -> ok;
+        _ ->
+            SentinelPid ! {ping, self()},
+            receive
+                pong ->
+                    ok
+            after 100 ->
+                throw({timeout_error, registered_pid})
+            end
+    end;
 teardown(Pid) ->
     couch_config:stop(),
     erlang:monitor(process, Pid),
@@ -64,7 +91,8 @@ couch_config_test_() ->
             couch_config_set_tests(),
             couch_config_del_tests(),
             config_override_tests(),
-            config_persistent_changes_tests()
+            config_persistent_changes_tests(),
+            config_register_tests()
         ]
     }.
 
@@ -152,6 +180,21 @@ config_persistent_changes_tests() ->
         }
     }.
 
+config_register_tests() ->
+    {
+        "Config changes subscriber",
+        {
+            foreach,
+            fun setup_register/0, fun teardown/1,
+            [
+                fun should_handle_port_changes/1,
+                fun should_pass_persistent_flag/1,
+                fun should_not_trigger_handler_on_other_options_changes/1,
+                fun should_not_trigger_handler_after_related_process_death/1
+            ]
+        }
+    }.
+
 
 should_load_all_configs() ->
     ?_assert(length(couch_config:all()) > 0).
@@ -281,3 +324,105 @@ should_ensure_that_written_to_last_config_in_chain(_, _) ->
         ?assertEqual(undefined,
                      couch_config:get("httpd", "bind_address"))
     end).
+
+should_handle_port_changes({_, SentinelPid}) ->
+    ?_assert(begin
+        MainProc = self(),
+        Port = "8080",
+
+        couch_config:register(
+            fun("httpd", "port", Value) ->
+                % couch_config catches every error raised from handler
+                % so it's not possible to just assert on wrong value.
+                % We have to return the result as message
+                MainProc ! (Value =:= Port)
+            end,
+            SentinelPid
+        ),
+        ok = couch_config:set("httpd", "port", Port, false),
+
+        receive
+            R ->
+                R
+        after ?TIMEOUT ->
+             erlang:error({assertion_failed,
+                           [{module, ?MODULE},
+                            {line, ?LINE},
+                            {reason, "Timeout"}]})
+        end
+    end).
+
+should_pass_persistent_flag({_, SentinelPid}) ->
+    ?_assert(begin
+        MainProc = self(),
+
+        couch_config:register(
+            fun("httpd", "port", _, Persist) ->
+                % couch_config catches every error raised from handler
+                % so it's not possible to just assert on wrong value.
+                % We have to return the result as message
+                MainProc ! Persist
+            end,
+            SentinelPid
+        ),
+        ok = couch_config:set("httpd", "port", "8080", false),
+
+        receive
+            false ->
+                true
+        after ?SHORT_TIMEOUT ->
+            false
+        end
+    end).
+
+should_not_trigger_handler_on_other_options_changes({_, SentinelPid}) ->
+    ?_assert(begin
+        MainProc = self(),
+
+        couch_config:register(
+            fun("httpd", "port", _) ->
+                MainProc ! ok
+            end,
+            SentinelPid
+        ),
+        ok = couch_config:set("httpd", "bind_address", "0.0.0.0", false),
+
+        receive
+            ok ->
+                false
+        after ?SHORT_TIMEOUT ->
+            true
+        end
+    end).
+
+should_not_trigger_handler_after_related_process_death({_, SentinelPid}) ->
+    ?_assert(begin
+        MainProc = self(),
+
+        couch_config:register(
+            fun("httpd", "port", _) ->
+                MainProc ! ok
+            end,
+            SentinelPid
+        ),
+
+        SentinelPid ! {ping, MainProc},
+        receive
+            pong ->
+                ok
+        after ?SHORT_TIMEOUT ->
+             erlang:error({assertion_failed,
+                           [{module, ?MODULE},
+                            {line, ?LINE},
+                            {reason, "Timeout"}]})
+        end,
+
+        ok = couch_config:set("httpd", "port", "12345", false),
+
+        receive
+            ok ->
+                false
+        after ?SHORT_TIMEOUT ->
+            true
+        end
+    end).


[27/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 231-cors.t etap test suite to eunit

Extend vhost and subresource testing for more generic code.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/44e2c267
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/44e2c267
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/44e2c267

Branch: refs/heads/1963-eunit-bigcouch
Commit: 44e2c267297aaf59444e2a194abc4203d113ae49
Parents: ffb002c
Author: Alexander Shorin <kx...@apache.org>
Authored: Tue Jun 10 19:11:45 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:45 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_cors_tests.erl | 344 +++++++++++++++++++++++++++++++
 test/couchdb/test_request.erl       |  14 +-
 2 files changed, 357 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/44e2c267/test/couchdb/couchdb_cors_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_cors_tests.erl b/test/couchdb/couchdb_cors_tests.erl
new file mode 100644
index 0000000..4e88ae7
--- /dev/null
+++ b/test/couchdb/couchdb_cors_tests.erl
@@ -0,0 +1,344 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_cors_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+
+-define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
+-define(SUPPORTED_METHODS,
+        "GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, COPY, OPTIONS").
+-define(TIMEOUT, 1000).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    ok = couch_config:set("httpd", "enable_cors", "true", false),
+    ok = couch_config:set("vhosts", "example.com", "/", false),
+    Pid.
+
+stop(Pid) ->
+    couch_server_sup:stop(),
+    erlang:monitor(process, Pid),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+    couch_db:close(Db),
+
+    couch_config:set("cors", "credentials", "false", false),
+    couch_config:set("cors", "origins", "http://example.com", false),
+
+    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+    Host = "http://" ++ Addr ++ ":" ++ Port,
+    {Host, ?b2l(DbName)}.
+
+setup({Mod, VHost}) ->
+    {Host, DbName} = setup(),
+    Url = case Mod of
+        server ->
+            Host;
+        db ->
+            Host ++ "/" ++ DbName
+    end,
+    DefaultHeaders = [{"Origin", "http://example.com"}]
+                     ++ maybe_append_vhost(VHost),
+    {Host, DbName, Url, DefaultHeaders}.
+
+teardown(DbName) when is_list(DbName) ->
+    ok = couch_server:delete(?l2b(DbName), [?ADMIN_USER]),
+    ok;
+teardown({_, DbName}) ->
+    teardown(DbName).
+
+teardown(_, {_, DbName, _, _}) ->
+    teardown(DbName).
+
+
+cors_test_() ->
+    Funs = [
+        fun should_not_allow_origin/2,
+        fun should_not_allow_origin_with_port_mismatch/2,
+        fun should_not_allow_origin_with_scheme_mismatch/2,
+        fun should_not_all_origin_due_case_mismatch/2,
+        fun should_make_simple_request/2,
+        fun should_make_preflight_request/2,
+        fun should_make_prefligh_request_with_port/2,
+        fun should_make_prefligh_request_with_scheme/2,
+        fun should_make_prefligh_request_with_wildcard_origin/2,
+        fun should_make_request_with_credentials/2,
+        fun should_make_origin_request_with_auth/2,
+        fun should_make_preflight_request_with_auth/2
+    ],
+    {
+        "CORS (COUCHDB-431)",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            [
+                cors_tests(Funs),
+                vhost_cors_tests(Funs),
+                headers_tests()
+            ]
+        }
+    }.
+
+headers_tests() ->
+    {
+        "Various headers tests",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_not_return_cors_headers_for_invalid_origin/1,
+                fun should_not_return_cors_headers_for_invalid_origin_preflight/1,
+                fun should_make_request_against_attachment/1,
+                fun should_make_range_request_against_attachment/1,
+                fun should_make_request_with_if_none_match_header/1
+            ]
+        }
+    }.
+
+cors_tests(Funs) ->
+    {
+        "CORS tests",
+        [
+            make_test_case(server, false, Funs),
+            make_test_case(db, false, Funs)
+        ]
+    }.
+
+vhost_cors_tests(Funs) ->
+    {
+        "Virtual Host CORS",
+        [
+            make_test_case(server, true, Funs),
+            make_test_case(db, true, Funs)
+        ]
+    }.
+
+make_test_case(Mod, UseVhost, Funs) ->
+    {
+        case Mod of server -> "Server"; db -> "Database" end,
+        {foreachx, fun setup/1, fun teardown/2, [{{Mod, UseVhost}, Fun}
+                                                 || Fun <- Funs]}
+    }.
+
+
+should_not_allow_origin(_, {_, _, Url, Headers0}) ->
+    ?_assertEqual(undefined,
+        begin
+            couch_config:delete("cors", "origins", false),
+            Headers1 = proplists:delete("Origin", Headers0),
+            Headers = [{"Origin", "http://127.0.0.1"}]
+                      ++ Headers1,
+            {ok, _, Resp, _} = test_request:get(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_not_allow_origin_with_port_mismatch({_, VHost}, {_, _, Url, _}) ->
+    ?_assertEqual(undefined,
+        begin
+            Headers = [{"Origin", "http://example.com:5984"},
+                       {"Access-Control-Request-Method", "GET"}]
+                      ++ maybe_append_vhost(VHost),
+            {ok, _, Resp, _} = test_request:options(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_not_allow_origin_with_scheme_mismatch({_, VHost}, {_, _, Url, _}) ->
+    ?_assertEqual(undefined,
+        begin
+            Headers = [{"Origin", "http://example.com:5984"},
+                       {"Access-Control-Request-Method", "GET"}]
+                      ++ maybe_append_vhost(VHost),
+            {ok, _, Resp, _} = test_request:options(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_not_all_origin_due_case_mismatch({_, VHost}, {_, _, Url, _}) ->
+    ?_assertEqual(undefined,
+        begin
+            Headers = [{"Origin", "http://ExAmPlE.CoM"},
+                       {"Access-Control-Request-Method", "GET"}]
+                      ++ maybe_append_vhost(VHost),
+            {ok, _, Resp, _} = test_request:options(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_make_simple_request(_, {_, _, Url, DefaultHeaders}) ->
+    ?_test(begin
+        {ok, _, Resp, _} = test_request:get(Url, DefaultHeaders),
+        ?assertEqual(
+            undefined,
+            proplists:get_value("Access-Control-Allow-Credentials", Resp)),
+        ?assertEqual(
+            "http://example.com",
+            proplists:get_value("Access-Control-Allow-Origin", Resp)),
+        ?assertEqual(
+            "Cache-Control, Content-Type, Server",
+            proplists:get_value("Access-Control-Expose-Headers", Resp))
+    end).
+
+should_make_preflight_request(_, {_, _, Url, DefaultHeaders}) ->
+    ?_assertEqual(?SUPPORTED_METHODS,
+        begin
+            Headers = DefaultHeaders
+                      ++ [{"Access-Control-Request-Method", "GET"}],
+            {ok, _, Resp, _} = test_request:options(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Methods", Resp)
+        end).
+
+should_make_prefligh_request_with_port({_, VHost}, {_, _, Url, _}) ->
+    ?_assertEqual("http://example.com:5984",
+        begin
+            couch_config:set("cors", "origins", "http://example.com:5984",
+                             false),
+            Headers = [{"Origin", "http://example.com:5984"},
+                       {"Access-Control-Request-Method", "GET"}]
+                      ++ maybe_append_vhost(VHost),
+            {ok, _, Resp, _} = test_request:options(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_make_prefligh_request_with_scheme({_, VHost}, {_, _, Url, _}) ->
+    ?_assertEqual("https://example.com:5984",
+        begin
+            couch_config:set("cors", "origins", "https://example.com:5984",
+                             false),
+            Headers = [{"Origin", "https://example.com:5984"},
+                       {"Access-Control-Request-Method", "GET"}]
+                      ++ maybe_append_vhost(VHost),
+            {ok, _, Resp, _} = test_request:options(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_make_prefligh_request_with_wildcard_origin({_, VHost}, {_, _, Url, _}) ->
+    ?_assertEqual("https://example.com:5984",
+        begin
+            couch_config:set("cors", "origins", "*", false),
+            Headers = [{"Origin", "https://example.com:5984"},
+                       {"Access-Control-Request-Method", "GET"}]
+                      ++ maybe_append_vhost(VHost),
+            {ok, _, Resp, _} = test_request:options(Url, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_make_request_with_credentials(_, {_, _, Url, DefaultHeaders}) ->
+    ?_assertEqual("true",
+        begin
+            ok = couch_config:set("cors", "credentials", "true", false),
+            {ok, _, Resp, _} = test_request:options(Url, DefaultHeaders),
+            proplists:get_value("Access-Control-Allow-Credentials", Resp)
+        end).
+
+should_make_origin_request_with_auth(_, {_, _, Url, DefaultHeaders}) ->
+    ?_assertEqual("http://example.com",
+        begin
+            Hashed = couch_passwords:hash_admin_password(<<"test">>),
+            couch_config:set("admins", "test", Hashed, false),
+            {ok, _, Resp, _} = test_request:get(
+                Url, DefaultHeaders, [{basic_auth, {"test", "test"}}]),
+            couch_config:delete("admins", "test", false),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_make_preflight_request_with_auth(_, {_, _, Url, DefaultHeaders}) ->
+    ?_assertEqual(?SUPPORTED_METHODS,
+        begin
+            Hashed = couch_passwords:hash_admin_password(<<"test">>),
+            couch_config:set("admins", "test", Hashed, false),
+            Headers = DefaultHeaders
+                      ++ [{"Access-Control-Request-Method", "GET"}],
+            {ok, _, Resp, _} = test_request:options(
+                Url, Headers, [{basic_auth, {"test", "test"}}]),
+            couch_config:delete("admins", "test", false),
+            proplists:get_value("Access-Control-Allow-Methods", Resp)
+        end).
+
+should_not_return_cors_headers_for_invalid_origin({Host, _}) ->
+    ?_assertEqual(undefined,
+        begin
+            Headers = [{"Origin", "http://127.0.0.1"}],
+            {ok, _, Resp, _} = test_request:get(Host, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_not_return_cors_headers_for_invalid_origin_preflight({Host, _}) ->
+    ?_assertEqual(undefined,
+        begin
+            Headers = [{"Origin", "http://127.0.0.1"},
+                       {"Access-Control-Request-Method", "GET"}],
+            {ok, _, Resp, _} = test_request:options(Host, Headers),
+            proplists:get_value("Access-Control-Allow-Origin", Resp)
+        end).
+
+should_make_request_against_attachment({Host, DbName}) ->
+    {"COUCHDB-1689",
+     ?_assertEqual(200,
+         begin
+             Url = Host ++ "/" ++ DbName,
+             {ok, Code0, _, _} = test_request:put(
+                 Url ++ "/doc/file.txt", [{"Content-Type", "text/plain"}],
+                 "hello, couch!"),
+             ?assert(Code0 =:= 201),
+             {ok, Code, _, _} = test_request:get(
+                 Url ++ "/doc?attachments=true",
+                 [{"Origin", "http://example.com"}]),
+             Code
+         end)}.
+
+should_make_range_request_against_attachment({Host, DbName}) ->
+    {"COUCHDB-1689",
+     ?_assertEqual(206,
+         begin
+             Url = Host ++ "/" ++ DbName,
+             {ok, Code0, _, _} = test_request:put(
+                 Url ++ "/doc/file.txt",
+                 [{"Content-Type", "application/octet-stream"}],
+                 "hello, couch!"),
+             ?assert(Code0 =:= 201),
+             {ok, Code, _, _} = test_request:get(
+                 Url ++ "/doc/file.txt", [{"Origin", "http://example.com"},
+                                          {"Range", "bytes=0-6"}]),
+             Code
+         end)}.
+
+should_make_request_with_if_none_match_header({Host, DbName}) ->
+    {"COUCHDB-1697",
+     ?_assertEqual(304,
+         begin
+             Url = Host ++ "/" ++ DbName,
+             {ok, Code0, Headers0, _} = test_request:put(
+                 Url ++ "/doc", [{"Content-Type", "application/json"}], "{}"),
+             ?assert(Code0 =:= 201),
+             ETag = proplists:get_value("ETag", Headers0),
+             {ok, Code, _, _} = test_request:get(
+                 Url ++ "/doc", [{"Origin", "http://example.com"},
+                                 {"If-None-Match", ETag}]),
+             Code
+        end)}.
+
+
+maybe_append_vhost(true) ->
+    [{"Host", "http://example.com"}];
+maybe_append_vhost(false) ->
+    [].

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/44e2c267/test/couchdb/test_request.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/test_request.erl b/test/couchdb/test_request.erl
index 36871b4..68e4956 100644
--- a/test/couchdb/test_request.erl
+++ b/test/couchdb/test_request.erl
@@ -12,7 +12,9 @@
 
 -module(test_request).
 
--export([get/1, get/2, get/3, put/2, put/3]).
+-export([get/1, get/2, get/3]).
+-export([put/2, put/3]).
+-export([options/1, options/2, options/3]).
 -export([request/3, request/4]).
 
 get(Url) ->
@@ -31,6 +33,16 @@ put(Url, Headers, Body) ->
     request(put, Url, Headers, Body).
 
 
+options(Url) ->
+    request(options, Url, []).
+
+options(Url, Headers) ->
+    request(options, Url, Headers).
+
+options(Url, Headers, Opts) ->
+    request(options, Url, Headers, [], Opts).
+
+
 request(Method, Url, Headers) ->
     request(Method, Url, Headers, []).
 


[09/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 080-config-get-set.t etap test suite to eunit


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/a77cdf51
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/a77cdf51
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/a77cdf51

Branch: refs/heads/1963-eunit-bigcouch
Commit: a77cdf51e37314d98a4ddd8c593edd4f202bc1b8
Parents: f51ec46
Author: Alexander Shorin <kx...@apache.org>
Authored: Fri May 23 09:29:22 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:43 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couch_config_tests.erl | 165 +++++++++++++++++++++++++++++++
 1 file changed, 165 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/a77cdf51/test/couchdb/couch_config_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_config_tests.erl b/test/couchdb/couch_config_tests.erl
new file mode 100644
index 0000000..ecff590
--- /dev/null
+++ b/test/couchdb/couch_config_tests.erl
@@ -0,0 +1,165 @@
+% 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(couch_config_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(TIMEOUT, 1000).
+
+
+setup() ->
+    {ok, Pid} = couch_config:start_link(?CONFIG_CHAIN),
+    Pid.
+
+teardown(Pid) ->
+    couch_config:stop(),
+    erlang:monitor(process, Pid),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout_error, config_stop})
+    end.
+
+
+couch_config_test_() ->
+    {
+        "CouchDB config tests",
+        [
+            couch_config_get_tests(),
+            couch_config_set_tests(),
+            couch_config_del_tests()
+        ]
+    }.
+
+couch_config_get_tests() ->
+    {
+        "Config get tests",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                should_load_all_configs(),
+                should_locate_daemons_section(),
+                should_locate_mrview_handler(),
+                should_return_undefined_atom_on_missed_section(),
+                should_return_undefined_atom_on_missed_option(),
+                should_return_custom_default_value_on_missed_option(),
+                should_only_return_default_on_missed_option(),
+                should_get_binary_option()
+            ]
+        }
+    }.
+
+couch_config_set_tests() ->
+    {
+        "Config set tests",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                should_update_option(),
+                should_create_new_section(),
+                should_set_binary_option()
+            ]
+        }
+    }.
+
+couch_config_del_tests() ->
+    {
+        "Config deletion tests",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                should_return_undefined_atom_after_option_deletion(),
+                should_be_ok_on_deleting_unknown_options(),
+                should_delete_binary_option()
+            ]
+        }
+    }.
+
+
+should_load_all_configs() ->
+    ?_assert(length(couch_config:all()) > 0).
+
+should_locate_daemons_section() ->
+    ?_assert(length(couch_config:get("daemons")) > 0).
+
+should_locate_mrview_handler() ->
+    ?_assertEqual("{couch_mrview_http, handle_view_req}",
+                  couch_config:get("httpd_design_handlers", "_view")).
+
+should_return_undefined_atom_on_missed_section() ->
+    ?_assertEqual(undefined,
+                  couch_config:get("foo", "bar")).
+
+should_return_undefined_atom_on_missed_option() ->
+    ?_assertEqual(undefined,
+                  couch_config:get("httpd", "foo")).
+
+should_return_custom_default_value_on_missed_option() ->
+    ?_assertEqual("bar",
+                  couch_config:get("httpd", "foo", "bar")).
+
+should_only_return_default_on_missed_option() ->
+    ?_assertEqual("0",
+                  couch_config:get("httpd", "port", "bar")).
+
+should_get_binary_option() ->
+    ?_assertEqual(<<"baz">>,
+                  couch_config:get(<<"foo">>, <<"bar">>, <<"baz">>)).
+
+should_update_option() ->
+    ?_assertEqual("severe",
+        begin
+            ok = couch_config:set("log", "level", "severe", false),
+            couch_config:get("log", "level")
+        end).
+
+should_create_new_section() ->
+    ?_assertEqual("bang",
+        begin
+            undefined = couch_config:get("new_section", "bizzle"),
+            ok = couch_config:set("new_section", "bizzle", "bang", false),
+            couch_config:get("new_section", "bizzle")
+        end).
+
+should_set_binary_option() ->
+    ?_assertEqual(<<"baz">>,
+        begin
+            ok = couch_config:set(<<"foo">>, <<"bar">>, <<"baz">>, false),
+            couch_config:get(<<"foo">>, <<"bar">>)
+        end).
+
+should_return_undefined_atom_after_option_deletion() ->
+    ?_assertEqual(undefined,
+        begin
+            ok = couch_config:delete("log", "level", false),
+            couch_config:get("log", "level")
+        end).
+
+should_be_ok_on_deleting_unknown_options() ->
+    ?_assertEqual(ok,
+        begin
+            couch_config:delete("zoo", "boo", false)
+        end).
+
+should_delete_binary_option() ->
+    ?_assertEqual(undefined,
+        begin
+            ok = couch_config:set(<<"foo">>, <<"bar">>, <<"baz">>, false),
+            ok = couch_config:delete(<<"foo">>, <<"bar">>, false),
+            couch_config:get(<<"foo">>, <<"bar">>)
+        end).


[07/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 075-auth-cache.t etap test suite to eunit

Timeouts are removed.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/7fc7aa32
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/7fc7aa32
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/7fc7aa32

Branch: refs/heads/1963-eunit-bigcouch
Commit: 7fc7aa322865068a5bd8f0800286698adca220c3
Parents: 92c3c84
Author: Alexander Shorin <kx...@apache.org>
Authored: Thu May 22 13:07:24 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:43 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couch_auth_cache_tests.erl | 246 +++++++++++++++++++++++++++
 1 file changed, 246 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/7fc7aa32/test/couchdb/couch_auth_cache_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_auth_cache_tests.erl b/test/couchdb/couch_auth_cache_tests.erl
new file mode 100644
index 0000000..34f7127
--- /dev/null
+++ b/test/couchdb/couch_auth_cache_tests.erl
@@ -0,0 +1,246 @@
+% 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(couch_auth_cache_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
+-define(SALT, <<"SALT">>).
+-define(TIMEOUT, 1000).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    Pid.
+
+stop(Pid) ->
+    erlang:monitor(process, Pid),
+    couch_server_sup:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    DbName = ?tempdb(),
+    couch_config:set("couch_httpd_auth", "authentication_db",
+                     ?b2l(DbName), false),
+    DbName.
+
+teardown(DbName) ->
+    ok = couch_server:delete(DbName, [?ADMIN_USER]),
+    ok.
+
+
+couch_auth_cache_test_() ->
+    {
+        "CouchDB auth cache tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    fun should_get_nil_on_missed_cache/1,
+                    fun should_get_right_password_hash/1,
+                    fun should_ensure_doc_hash_equals_cached_one/1,
+                    fun should_update_password/1,
+                    fun should_cleanup_cache_after_userdoc_deletion/1,
+                    fun should_restore_cache_after_userdoc_recreation/1,
+                    fun should_drop_cache_on_auth_db_change/1,
+                    fun should_restore_cache_on_auth_db_change/1,
+                    fun should_recover_cache_after_shutdown/1
+                ]
+            }
+        }
+    }.
+
+
+should_get_nil_on_missed_cache(_) ->
+    ?_assertEqual(nil, couch_auth_cache:get_user_creds("joe")).
+
+should_get_right_password_hash(DbName) ->
+    ?_assert(begin
+        PasswordHash = hash_password("pass1"),
+        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+        Creds = couch_auth_cache:get_user_creds("joe"),
+        ?assertEqual(PasswordHash,
+                      couch_util:get_value(<<"password_sha">>, Creds)),
+        true
+    end).
+
+should_ensure_doc_hash_equals_cached_one(DbName) ->
+    ?_assert(begin
+        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+        Creds = couch_auth_cache:get_user_creds("joe"),
+
+        CachedHash = couch_util:get_value(<<"password_sha">>, Creds),
+        StoredHash = get_user_doc_password_sha(DbName, "joe"),
+        ?assertEqual(StoredHash, CachedHash),
+        true
+    end).
+
+should_update_password(DbName) ->
+    ?_assert(begin
+        PasswordHash = hash_password("pass2"),
+        {ok, Rev} = update_user_doc(DbName, "joe", "pass1"),
+        {ok, _} = update_user_doc(DbName, "joe", "pass2", Rev),
+        Creds = couch_auth_cache:get_user_creds("joe"),
+        ?assertEqual(PasswordHash,
+                      couch_util:get_value(<<"password_sha">>, Creds)),
+        true
+    end).
+
+should_cleanup_cache_after_userdoc_deletion(DbName) ->
+    ?_assert(begin
+        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+        delete_user_doc(DbName, "joe"),
+        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe")),
+        true
+    end).
+
+should_restore_cache_after_userdoc_recreation(DbName) ->
+    ?_assert(begin
+        PasswordHash = hash_password("pass5"),
+        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+        delete_user_doc(DbName, "joe"),
+        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe")),
+
+        {ok, _} = update_user_doc(DbName, "joe", "pass5"),
+        Creds = couch_auth_cache:get_user_creds("joe"),
+
+        ?assertEqual(PasswordHash,
+                      couch_util:get_value(<<"password_sha">>, Creds)),
+        true
+    end).
+
+should_drop_cache_on_auth_db_change(DbName) ->
+    ?_assert(begin
+        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+        full_commit(DbName),
+        couch_config:set("couch_httpd_auth", "authentication_db",
+                         ?b2l(?tempdb()), false),
+        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe")),
+        true
+    end).
+
+should_restore_cache_on_auth_db_change(DbName) ->
+    ?_assert(begin
+        PasswordHash = hash_password("pass1"),
+        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+        Creds = couch_auth_cache:get_user_creds("joe"),
+        full_commit(DbName),
+
+        DbName1 = ?tempdb(),
+        couch_config:set("couch_httpd_auth", "authentication_db",
+                         ?b2l(DbName1), false),
+
+        {ok, _} = update_user_doc(DbName1, "joe", "pass5"),
+        full_commit(DbName1),
+
+        couch_config:set("couch_httpd_auth", "authentication_db",
+                         ?b2l(DbName), false),
+
+        Creds = couch_auth_cache:get_user_creds("joe"),
+        ?assertEqual(PasswordHash,
+                      couch_util:get_value(<<"password_sha">>, Creds)),
+        true
+    end).
+
+should_recover_cache_after_shutdown(DbName) ->
+    ?_assert(begin
+        PasswordHash = hash_password("pass2"),
+        {ok, Rev0} = update_user_doc(DbName, "joe", "pass1"),
+        {ok, Rev1} = update_user_doc(DbName, "joe", "pass2", Rev0),
+        full_commit(DbName),
+        shutdown_db(DbName),
+        {ok, Rev1} = get_doc_rev(DbName, "joe"),
+        ?assertEqual(PasswordHash, get_user_doc_password_sha(DbName, "joe")),
+        true
+    end).
+
+
+update_user_doc(DbName, UserName, Password) ->
+    update_user_doc(DbName, UserName, Password, nil).
+
+update_user_doc(DbName, UserName, Password, Rev) ->
+    User = iolist_to_binary(UserName),
+    Doc = couch_doc:from_json_obj({[
+        {<<"_id">>, <<"org.couchdb.user:", User/binary>>},
+        {<<"name">>, User},
+        {<<"type">>, <<"user">>},
+        {<<"salt">>, ?SALT},
+        {<<"password_sha">>, hash_password(Password)},
+        {<<"roles">>, []}
+    ] ++ case Rev of
+            nil -> [];
+            _ ->   [{<<"_rev">>, Rev}]
+         end
+    }),
+    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+    {ok, NewRev} = couch_db:update_doc(AuthDb, Doc, []),
+    ok = couch_db:close(AuthDb),
+    {ok, couch_doc:rev_to_str(NewRev)}.
+
+hash_password(Password) ->
+    ?l2b(couch_util:to_hex(crypto:sha(iolist_to_binary([Password, ?SALT])))).
+
+shutdown_db(DbName) ->
+    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+    ok = couch_db:close(AuthDb),
+    couch_util:shutdown_sync(AuthDb#db.main_pid),
+    ok = timer:sleep(1000).
+
+get_doc_rev(DbName, UserName) ->
+    DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
+    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+    UpdateRev =
+    case couch_db:open_doc(AuthDb, DocId, []) of
+    {ok, Doc} ->
+        {Props} = couch_doc:to_json_obj(Doc, []),
+        couch_util:get_value(<<"_rev">>, Props);
+    {not_found, missing} ->
+        nil
+    end,
+    ok = couch_db:close(AuthDb),
+    {ok, UpdateRev}.
+
+get_user_doc_password_sha(DbName, UserName) ->
+    DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
+    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+    {ok, Doc} = couch_db:open_doc(AuthDb, DocId, []),
+    ok = couch_db:close(AuthDb),
+    {Props} = couch_doc:to_json_obj(Doc, []),
+    couch_util:get_value(<<"password_sha">>, Props).
+
+delete_user_doc(DbName, UserName) ->
+    DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
+    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+    {ok, Doc} = couch_db:open_doc(AuthDb, DocId, []),
+    {Props} = couch_doc:to_json_obj(Doc, []),
+    DeletedDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, DocId},
+        {<<"_rev">>, couch_util:get_value(<<"_rev">>, Props)},
+        {<<"_deleted">>, true}
+    ]}),
+    {ok, _} = couch_db:update_doc(AuthDb, DeletedDoc, []),
+    ok = couch_db:close(AuthDb).
+
+full_commit(DbName) ->
+    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+    {ok, _} = couch_db:ensure_full_commit(AuthDb),
+    ok = couch_db:close(AuthDb).


[31/50] [abbrv] Move files out of test/couchdb into top level test/ folder

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb_update_conflicts_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_update_conflicts_tests.erl b/test/couchdb_update_conflicts_tests.erl
new file mode 100644
index 0000000..7226860
--- /dev/null
+++ b/test/couchdb_update_conflicts_tests.erl
@@ -0,0 +1,243 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_update_conflicts_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(i2l(I), integer_to_list(I)).
+-define(ADMIN_USER, {userctx, #user_ctx{roles=[<<"_admin">>]}}).
+-define(DOC_ID, <<"foobar">>).
+-define(NUM_CLIENTS, [100, 500, 1000, 2000, 5000, 10000]).
+-define(TIMEOUT, 10000).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    couch_config:set("couchdb", "delayed_commits", "true", false),
+    Pid.
+
+stop(Pid) ->
+    erlang:monitor(process, Pid),
+    couch_server_sup:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER, overwrite]),
+    Doc = couch_doc:from_json_obj({[{<<"_id">>, ?DOC_ID},
+                                    {<<"value">>, 0}]}),
+    {ok, Rev} = couch_db:update_doc(Db, Doc, []),
+    ok = couch_db:close(Db),
+    RevStr = couch_doc:rev_to_str(Rev),
+    {DbName, RevStr}.
+setup(_) ->
+    setup().
+
+teardown({DbName, _}) ->
+    ok = couch_server:delete(DbName, []),
+    ok.
+teardown(_, {DbName, _RevStr}) ->
+    teardown({DbName, _RevStr}).
+
+
+view_indexes_cleanup_test_() ->
+    {
+        "Update conflicts",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            [
+                concurrent_updates(),
+                couchdb_188()
+            ]
+        }
+    }.
+
+concurrent_updates()->
+    {
+        "Concurrent updates",
+        {
+            foreachx,
+            fun setup/1, fun teardown/2,
+            [{NumClients, fun should_concurrently_update_doc/2}
+             || NumClients <- ?NUM_CLIENTS]
+        }
+    }.
+
+couchdb_188()->
+    {
+        "COUCHDB-188",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [fun should_bulk_create_delete_doc/1]
+        }
+    }.
+
+
+should_concurrently_update_doc(NumClients, {DbName, InitRev})->
+     {?i2l(NumClients) ++ " clients",
+      {inorder,
+       [{"update doc",
+         {timeout, ?TIMEOUT div 1000,
+          ?_test(concurrent_doc_update(NumClients, DbName, InitRev))}},
+        {"ensure in single leaf",
+         ?_test(ensure_in_single_revision_leaf(DbName))}]}}.
+
+should_bulk_create_delete_doc({DbName, InitRev})->
+    ?_test(bulk_delete_create(DbName, InitRev)).
+
+
+concurrent_doc_update(NumClients, DbName, InitRev) ->
+    Clients = lists:map(
+        fun(Value) ->
+            ClientDoc = couch_doc:from_json_obj({[
+                {<<"_id">>, ?DOC_ID},
+                {<<"_rev">>, InitRev},
+                {<<"value">>, Value}
+            ]}),
+            Pid = spawn_client(DbName, ClientDoc),
+            {Value, Pid, erlang:monitor(process, Pid)}
+        end,
+        lists:seq(1, NumClients)),
+
+    lists:foreach(fun({_, Pid, _}) -> Pid ! go end, Clients),
+
+    {NumConflicts, SavedValue} = lists:foldl(
+        fun({Value, Pid, MonRef}, {AccConflicts, AccValue}) ->
+            receive
+                {'DOWN', MonRef, process, Pid, {ok, _NewRev}} ->
+                    {AccConflicts, Value};
+                {'DOWN', MonRef, process, Pid, conflict} ->
+                    {AccConflicts + 1, AccValue};
+                {'DOWN', MonRef, process, Pid, Error} ->
+                    erlang:error({assertion_failed,
+                         [{module, ?MODULE},
+                          {line, ?LINE},
+                          {reason, "Client " ++ ?i2l(Value)
+                                             ++ " got update error: "
+                                             ++ couch_util:to_list(Error)}]})
+            after ?TIMEOUT div 2 ->
+                 erlang:error({assertion_failed,
+                         [{module, ?MODULE},
+                          {line, ?LINE},
+                          {reason, "Timeout waiting for client "
+                                   ++ ?i2l(Value) ++ " to die"}]})
+            end
+        end, {0, nil}, Clients),
+    ?assertEqual(NumClients - 1, NumConflicts),
+
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, Leaves} = couch_db:open_doc_revs(Db, ?DOC_ID, all, []),
+    ok = couch_db:close(Db),
+    ?assertEqual(1, length(Leaves)),
+
+    [{ok, Doc2}] = Leaves,
+    {JsonDoc} = couch_doc:to_json_obj(Doc2, []),
+    ?assertEqual(SavedValue, couch_util:get_value(<<"value">>, JsonDoc)).
+
+ensure_in_single_revision_leaf(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, Leaves} = couch_db:open_doc_revs(Db, ?DOC_ID, all, []),
+    ok = couch_db:close(Db),
+    [{ok, Doc}] = Leaves,
+
+    %% FIXME: server restart won't work from test side
+    %% stop(ok),
+    %% start(),
+
+    {ok, Db2} = couch_db:open_int(DbName, []),
+    {ok, Leaves2} = couch_db:open_doc_revs(Db2, ?DOC_ID, all, []),
+    ok = couch_db:close(Db2),
+    ?assertEqual(1, length(Leaves2)),
+
+    [{ok, Doc2}] = Leaves,
+    ?assertEqual(Doc, Doc2).
+    
+bulk_delete_create(DbName, InitRev) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    
+    DeletedDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, ?DOC_ID},
+        {<<"_rev">>, InitRev},
+        {<<"_deleted">>, true}
+    ]}),
+    NewDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, ?DOC_ID},
+        {<<"value">>, 666}
+    ]}),
+
+    {ok, Results} = couch_db:update_docs(Db, [DeletedDoc, NewDoc], []),
+    ok = couch_db:close(Db),
+
+    ?assertEqual(2, length([ok || {ok, _} <- Results])),
+    [{ok, Rev1}, {ok, Rev2}] = Results,
+    
+    {ok, Db2} = couch_db:open_int(DbName, []),
+    {ok, [{ok, Doc1}]} = couch_db:open_doc_revs(
+        Db2, ?DOC_ID, [Rev1], [conflicts, deleted_conflicts]),
+    {ok, [{ok, Doc2}]} = couch_db:open_doc_revs(
+        Db2, ?DOC_ID, [Rev2], [conflicts, deleted_conflicts]),
+    ok = couch_db:close(Db2),
+
+    {Doc1Props} = couch_doc:to_json_obj(Doc1, []),
+    {Doc2Props} = couch_doc:to_json_obj(Doc2, []),
+
+    %% Document was deleted
+    ?assert(couch_util:get_value(<<"_deleted">>, Doc1Props)),
+    %% New document not flagged as deleted
+    ?assertEqual(undefined, couch_util:get_value(<<"_deleted">>,
+                                                 Doc2Props)),
+    %% New leaf revision has the right value
+    ?assertEqual(666, couch_util:get_value(<<"value">>,
+                                           Doc2Props)),
+    %% Deleted document has no conflicts
+    ?assertEqual(undefined, couch_util:get_value(<<"_conflicts">>,
+                                                 Doc1Props)),
+    %% Deleted document has no deleted conflicts
+    ?assertEqual(undefined, couch_util:get_value(<<"_deleted_conflicts">>,
+                                                 Doc1Props)),
+    %% New leaf revision doesn't have conflicts
+    ?assertEqual(undefined, couch_util:get_value(<<"_conflicts">>,
+                                                 Doc1Props)),
+    %% New leaf revision doesn't have deleted conflicts
+    ?assertEqual(undefined, couch_util:get_value(<<"_deleted_conflicts">>,
+                                                 Doc1Props)),
+
+    %% Deleted revision has position 2
+    ?assertEqual(2, element(1, Rev1)),
+    %% New leaf revision has position 1
+    ?assertEqual(1, element(1, Rev2)).
+
+
+spawn_client(DbName, Doc) ->
+    spawn(fun() ->
+        {ok, Db} = couch_db:open_int(DbName, []),
+        receive
+            go -> ok
+        end,
+        erlang:yield(),
+        Result = try
+            couch_db:update_doc(Db, Doc, [])
+        catch _:Error ->
+            Error
+        end,
+        ok = couch_db:close(Db),
+        exit(Result)
+    end).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb_vhosts_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_vhosts_tests.erl b/test/couchdb_vhosts_tests.erl
new file mode 100644
index 0000000..94b1957
--- /dev/null
+++ b/test/couchdb_vhosts_tests.erl
@@ -0,0 +1,441 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_vhosts_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
+-define(TIMEOUT, 1000).
+-define(iofmt(S, A), lists:flatten(io_lib:format(S, A))).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    Pid.
+
+stop(Pid) ->
+    erlang:monitor(process, Pid),
+    couch_server_sup:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+    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),
+    couch_db:close(Db),
+
+    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+    Url = "http://" ++ Addr ++ ":" ++ Port,
+    {Url, ?b2l(DbName)}.
+
+setup_oauth() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+
+    couch_config:set("couch_httpd_auth", "authentication_db",
+                     ?b2l(?tempdb()), false),
+    couch_config:set("oauth_token_users", "otoksec1", "joe", false),
+    couch_config:set("oauth_consumer_secrets", "consec1", "foo", false),
+    couch_config:set("oauth_token_secrets", "otoksec1", "foobar", false),
+    couch_config:set("couch_httpd_auth", "require_valid_user", "true", false),
+
+    ok = couch_config:set(
+        "vhosts", "oauth-example.com",
+        "/" ++ ?b2l(DbName) ++ "/_design/test/_rewrite/foobar", false),
+
+    DDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, <<"_design/test">>},
+        {<<"language">>, <<"javascript">>},
+        {<<"rewrites">>, [
+            {[
+                {<<"from">>, <<"foobar">>},
+                {<<"to">>, <<"_info">>}
+            ]}
+        ]}
+    ]}),
+    {ok, _} = couch_db:update_doc(Db, DDoc, []),
+
+    couch_db:ensure_full_commit(Db),
+    couch_db:close(Db),
+
+    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+    Url = "http://" ++ Addr ++ ":" ++ Port,
+    {Url, ?b2l(DbName)}.
+
+teardown({_, DbName}) ->
+    ok = couch_server:delete(?l2b(DbName), []),
+    ok.
+
+
+vhosts_test_() ->
+    {
+        "Virtual Hosts rewrite tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    fun should_return_database_info/1,
+                    fun should_return_revs_info/1,
+                    fun should_serve_utils_for_vhost/1,
+                    fun should_return_virtual_request_path_field_in_request/1,
+                    fun should_return_real_request_path_field_in_request/1,
+                    fun should_match_wildcard_vhost/1,
+                    fun should_return_db_info_for_wildcard_vhost_for_custom_db/1,
+                    fun should_replace_rewrite_variables_for_db_and_doc/1,
+                    fun should_return_db_info_for_vhost_with_resource/1,
+                    fun should_return_revs_info_for_vhost_with_resource/1,
+                    fun should_return_db_info_for_vhost_with_wildcard_resource/1,
+                    fun should_return_path_for_vhost_with_wildcard_host/1
+                ]
+            }
+        }
+    }.
+
+oauth_test_() ->
+    {
+        "Virtual Hosts OAuth tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup_oauth/0, fun teardown/1,
+                [
+                    fun should_require_auth/1,
+                    fun should_succeed_oauth/1,
+                    fun should_fail_oauth_with_wrong_credentials/1
+                ]
+            }
+        }
+    }.
+
+
+should_return_database_info({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "example.com", "/" ++ DbName, false),
+        case test_request:get(Url, [], [{host_header, "example.com"}]) of
+            {ok, _, _, Body} ->
+                {JsonBody} = ejson:decode(Body),
+                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_return_revs_info({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "example.com", "/" ++ DbName, false),
+        case test_request:get(Url ++ "/doc1?revs_info=true", [],
+                              [{host_header, "example.com"}]) of
+            {ok, _, _, Body} ->
+                {JsonBody} = ejson:decode(Body),
+                ?assert(proplists:is_defined(<<"_revs_info">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_serve_utils_for_vhost({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "example.com", "/" ++ DbName, false),
+        case test_request:get(Url ++ "/_utils/index.html", [],
+                              [{host_header, "example.com"}]) of
+            {ok, _, _, Body} ->
+                ?assertMatch(<<"<!DOCTYPE html>", _/binary>>, Body);
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_return_virtual_request_path_field_in_request({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "example1.com",
+                              "/" ++ DbName ++ "/_design/doc1/_rewrite/",
+                              false),
+        case test_request:get(Url, [], [{host_header, "example1.com"}]) of
+            {ok, _, _, Body} ->
+                {Json} = ejson:decode(Body),
+                ?assertEqual(<<"/">>,
+                             proplists:get_value(<<"requested_path">>, Json));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_return_real_request_path_field_in_request({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "example1.com",
+                              "/" ++ DbName ++ "/_design/doc1/_rewrite/",
+                              false),
+        case test_request:get(Url, [], [{host_header, "example1.com"}]) of
+            {ok, _, _, Body} ->
+                {Json} = ejson:decode(Body),
+                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
+                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_match_wildcard_vhost({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "*.example.com",
+                              "/" ++ DbName ++ "/_design/doc1/_rewrite", false),
+        case test_request:get(Url, [], [{host_header, "test.example.com"}]) of
+            {ok, _, _, Body} ->
+                {Json} = ejson:decode(Body),
+                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
+                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_return_db_info_for_wildcard_vhost_for_custom_db({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", ":dbname.example1.com",
+                              "/:dbname", false),
+        Host = DbName ++ ".example1.com",
+        case test_request:get(Url, [], [{host_header, Host}]) of
+            {ok, _, _, Body} ->
+                {JsonBody} = ejson:decode(Body),
+                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_replace_rewrite_variables_for_db_and_doc({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts",":appname.:dbname.example1.com",
+                              "/:dbname/_design/:appname/_rewrite/", false),
+        Host = "doc1." ++ DbName ++ ".example1.com",
+        case test_request:get(Url, [], [{host_header, Host}]) of
+            {ok, _, _, Body} ->
+                {Json} = ejson:decode(Body),
+                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
+                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_return_db_info_for_vhost_with_resource({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts",
+                              "example.com/test", "/" ++ DbName, false),
+        ReqUrl = Url ++ "/test",
+        case test_request:get(ReqUrl, [], [{host_header, "example.com"}]) of
+            {ok, _, _, Body} ->
+                {JsonBody} = ejson:decode(Body),
+                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+
+should_return_revs_info_for_vhost_with_resource({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts",
+                              "example.com/test", "/" ++ DbName, false),
+        ReqUrl = Url ++ "/test/doc1?revs_info=true",
+        case test_request:get(ReqUrl, [], [{host_header, "example.com"}]) of
+            {ok, _, _, Body} ->
+                {JsonBody} = ejson:decode(Body),
+                ?assert(proplists:is_defined(<<"_revs_info">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_return_db_info_for_vhost_with_wildcard_resource({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "*.example2.com/test", "/*", false),
+        ReqUrl = Url ++ "/test",
+        Host = DbName ++ ".example2.com",
+        case test_request:get(ReqUrl, [], [{host_header, Host}]) of
+            {ok, _, _, Body} ->
+                {JsonBody} = ejson:decode(Body),
+                ?assert(proplists:is_defined(<<"db_name">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_return_path_for_vhost_with_wildcard_host({Url, DbName}) ->
+    ?_test(begin
+        ok = couch_config:set("vhosts", "*/test1",
+                              "/" ++ DbName ++ "/_design/doc1/_show/test",
+                              false),
+        case test_request:get(Url ++ "/test1") of
+            {ok, _, _, Body} ->
+                {Json} = ejson:decode(Body),
+                Path = ?l2b("/" ++ DbName ++ "/_design/doc1/_show/test"),
+                ?assertEqual(Path, proplists:get_value(<<"path">>, Json));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_require_auth({Url, _}) ->
+    ?_test(begin
+        case test_request:get(Url, [], [{host_header, "oauth-example.com"}]) of
+            {ok, Code, _, Body} ->
+                ?assertEqual(401, Code),
+                {JsonBody} = ejson:decode(Body),
+                ?assertEqual(<<"unauthorized">>,
+                             couch_util:get_value(<<"error">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_succeed_oauth({Url, _}) ->
+    ?_test(begin
+        AuthDbName = couch_config:get("couch_httpd_auth", "authentication_db"),
+        JoeDoc = couch_doc:from_json_obj({[
+            {<<"_id">>, <<"org.couchdb.user:joe">>},
+            {<<"type">>, <<"user">>},
+            {<<"name">>, <<"joe">>},
+            {<<"roles">>, []},
+            {<<"password_sha">>, <<"fe95df1ca59a9b567bdca5cbaf8412abd6e06121">>},
+            {<<"salt">>, <<"4e170ffeb6f34daecfd814dfb4001a73">>}
+        ]}),
+        {ok, AuthDb} = couch_db:open_int(?l2b(AuthDbName), [?ADMIN_USER]),
+        {ok, _} = couch_db:update_doc(AuthDb, JoeDoc, [?ADMIN_USER]),
+
+        Host = "oauth-example.com",
+        Consumer = {"consec1", "foo", hmac_sha1},
+        SignedParams = oauth:sign(
+            "GET", "http://" ++ Host ++ "/", [], Consumer, "otoksec1", "foobar"),
+        OAuthUrl = oauth:uri(Url, SignedParams),
+
+        case test_request:get(OAuthUrl, [], [{host_header, Host}]) of
+            {ok, Code, _, Body} ->
+                ?assertEqual(200, Code),
+                {JsonBody} = ejson:decode(Body),
+                ?assertEqual(<<"test">>,
+                             couch_util:get_value(<<"name">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).
+
+should_fail_oauth_with_wrong_credentials({Url, _}) ->
+    ?_test(begin
+        AuthDbName = couch_config:get("couch_httpd_auth", "authentication_db"),
+        JoeDoc = couch_doc:from_json_obj({[
+            {<<"_id">>, <<"org.couchdb.user:joe">>},
+            {<<"type">>, <<"user">>},
+            {<<"name">>, <<"joe">>},
+            {<<"roles">>, []},
+            {<<"password_sha">>, <<"fe95df1ca59a9b567bdca5cbaf8412abd6e06121">>},
+            {<<"salt">>, <<"4e170ffeb6f34daecfd814dfb4001a73">>}
+        ]}),
+        {ok, AuthDb} = couch_db:open_int(?l2b(AuthDbName), [?ADMIN_USER]),
+        {ok, _} = couch_db:update_doc(AuthDb, JoeDoc, [?ADMIN_USER]),
+
+        Host = "oauth-example.com",
+        Consumer = {"consec1", "bad_secret", hmac_sha1},
+        SignedParams = oauth:sign(
+            "GET", "http://" ++ Host ++ "/", [], Consumer, "otoksec1", "foobar"),
+        OAuthUrl = oauth:uri(Url, SignedParams),
+
+        case test_request:get(OAuthUrl, [], [{host_header, Host}]) of
+            {ok, Code, _, Body} ->
+                ?assertEqual(401, Code),
+                {JsonBody} = ejson:decode(Body),
+                ?assertEqual(<<"unauthorized">>,
+                             couch_util:get_value(<<"error">>, JsonBody));
+            Else ->
+                erlang:error({assertion_failed,
+                             [{module, ?MODULE},
+                              {line, ?LINE},
+                              {reason, ?iofmt("Request failed: ~p", [Else])}]})
+        end
+    end).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb_views_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_views_tests.erl b/test/couchdb_views_tests.erl
new file mode 100644
index 0000000..6d81f32
--- /dev/null
+++ b/test/couchdb_views_tests.erl
@@ -0,0 +1,669 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_views_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+-include_lib("couch_mrview/include/couch_mrview.hrl").
+
+-define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
+-define(DELAY, 100).
+-define(TIMEOUT, 1000).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    Pid.
+
+stop(Pid) ->
+    erlang:monitor(process, Pid),
+    couch_server_sup:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+    ok = couch_db:close(Db),
+    FooRev = create_design_doc(DbName, <<"_design/foo">>, <<"bar">>),
+    query_view(DbName, "foo", "bar"),
+    BooRev = create_design_doc(DbName, <<"_design/boo">>, <<"baz">>),
+    query_view(DbName, "boo", "baz"),
+    {DbName, {FooRev, BooRev}}.
+
+setup_with_docs() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+    ok = couch_db:close(Db),
+    create_docs(DbName),
+    create_design_doc(DbName, <<"_design/foo">>, <<"bar">>),
+    DbName.
+
+teardown({DbName, _}) ->
+    teardown(DbName);
+teardown(DbName) when is_binary(DbName) ->
+    couch_server:delete(DbName, [?ADMIN_USER]),
+    ok.
+
+
+view_indexes_cleanup_test_() ->
+    {
+        "View indexes cleanup",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    fun should_have_two_indexes_alive_before_deletion/1,
+                    fun should_cleanup_index_file_after_ddoc_deletion/1,
+                    fun should_cleanup_all_index_files/1
+                ]
+            }
+        }
+    }.
+
+view_group_db_leaks_test_() ->
+    {
+        "View group db leaks",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup_with_docs/0, fun teardown/1,
+                [
+                    fun couchdb_1138/1,
+                    fun couchdb_1309/1
+                ]
+            }
+        }
+    }.
+
+view_group_shutdown_test_() ->
+    {
+        "View group shutdown",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            [couchdb_1283()]
+        }
+    }.
+
+
+should_not_remember_docs_in_index_after_backup_restore_test() ->
+    %% COUCHDB-640
+    start(),
+    DbName = setup_with_docs(),
+
+    ok = backup_db_file(DbName),
+    create_doc(DbName, "doc666"),
+
+    Rows0 = query_view(DbName, "foo", "bar"),
+    ?assert(has_doc("doc1", Rows0)),
+    ?assert(has_doc("doc2", Rows0)),
+    ?assert(has_doc("doc3", Rows0)),
+    ?assert(has_doc("doc666", Rows0)),
+
+    restore_backup_db_file(DbName),
+
+    Rows1 = query_view(DbName, "foo", "bar"),
+    ?assert(has_doc("doc1", Rows1)),
+    ?assert(has_doc("doc2", Rows1)),
+    ?assert(has_doc("doc3", Rows1)),
+    ?assertNot(has_doc("doc666", Rows1)),
+
+    teardown(DbName),
+    stop(whereis(couch_server_sup)).
+
+
+should_upgrade_legacy_view_files_test() ->
+    start(),
+
+    ok = couch_config:set("query_server_config", "commit_freq", "0", false),
+
+    DbName = <<"test">>,
+    DbFileName = "test.couch",
+    DbFilePath = filename:join([?FIXTURESDIR, DbFileName]),
+    OldViewName = "3b835456c235b1827e012e25666152f3.view",
+    FixtureViewFilePath = filename:join([?FIXTURESDIR, OldViewName]),
+    NewViewName = "a1c5929f912aca32f13446122cc6ce50.view",
+
+    DbDir = couch_config:get("couchdb", "database_dir"),
+    ViewDir = couch_config:get("couchdb", "view_index_dir"),
+    OldViewFilePath = filename:join([ViewDir, ".test_design", OldViewName]),
+    NewViewFilePath = filename:join([ViewDir, ".test_design", "mrview",
+                                     NewViewName]),
+
+    % cleanup
+    Files = [
+        filename:join([DbDir, DbFileName]),
+        OldViewFilePath,
+        NewViewFilePath
+    ],
+    lists:foreach(fun(File) -> file:delete(File) end, Files),
+
+    % copy old db file into db dir
+    {ok, _} = file:copy(DbFilePath, filename:join([DbDir, DbFileName])),
+
+    % copy old view file into view dir
+    ok = filelib:ensure_dir(filename:join([ViewDir, ".test_design"])),
+    {ok, _} = file:copy(FixtureViewFilePath, OldViewFilePath),
+
+    % ensure old header
+    OldHeader = read_header(OldViewFilePath),
+    ?assertMatch(#index_header{}, OldHeader),
+
+    % query view for expected results
+    Rows0 = query_view(DbName, "test", "test"),
+    ?assertEqual(2, length(Rows0)),
+
+    % ensure old file gone
+    ?assertNot(filelib:is_regular(OldViewFilePath)),
+
+    % add doc to trigger update
+    DocUrl = db_url(DbName) ++ "/boo",
+    {ok, _, _, _} = test_request:put(
+        DocUrl, [{"Content-Type", "application/json"}], <<"{\"a\":3}">>),
+
+    % query view for expected results
+    Rows1 = query_view(DbName, "test", "test"),
+    ?assertEqual(3, length(Rows1)),
+
+    % ensure new header
+    timer:sleep(2000),  % have to wait for awhile to upgrade the index
+    NewHeader = read_header(NewViewFilePath),
+    ?assertMatch(#mrheader{}, NewHeader),
+
+    teardown(DbName),
+    stop(whereis(couch_server_sup)).
+
+
+should_have_two_indexes_alive_before_deletion({DbName, _}) ->
+    view_cleanup(DbName),
+    ?_assertEqual(2, count_index_files(DbName)).
+
+should_cleanup_index_file_after_ddoc_deletion({DbName, {FooRev, _}}) ->
+    delete_design_doc(DbName, <<"_design/foo">>, FooRev),
+    view_cleanup(DbName),
+    ?_assertEqual(1, count_index_files(DbName)).
+
+should_cleanup_all_index_files({DbName, {FooRev, BooRev}})->
+    delete_design_doc(DbName, <<"_design/foo">>, FooRev),
+    delete_design_doc(DbName, <<"_design/boo">>, BooRev),
+    view_cleanup(DbName),
+    ?_assertEqual(0, count_index_files(DbName)).
+
+couchdb_1138(DbName) ->
+    ?_test(begin
+        {ok, IndexerPid} = couch_index_server:get_index(
+            couch_mrview_index, DbName, <<"_design/foo">>),
+        ?assert(is_pid(IndexerPid)),
+        ?assert(is_process_alive(IndexerPid)),
+        ?assertEqual(2, count_db_refs(DbName)),
+
+        Rows0 = query_view(DbName, "foo", "bar"),
+        ?assertEqual(3, length(Rows0)),
+        ?assertEqual(2, count_db_refs(DbName)),
+        ?assert(is_process_alive(IndexerPid)),
+
+        create_doc(DbName, "doc1000"),
+        Rows1 = query_view(DbName, "foo", "bar"),
+        ?assertEqual(4, length(Rows1)),
+        ?assertEqual(2, count_db_refs(DbName)),
+        ?assert(is_process_alive(IndexerPid)),
+
+        Ref1 = get_db_ref_counter(DbName),
+        compact_db(DbName),
+        Ref2 = get_db_ref_counter(DbName),
+        ?assertEqual(2, couch_ref_counter:count(Ref2)),
+        ?assertNotEqual(Ref2, Ref1),
+        ?assertNot(is_process_alive(Ref1)),
+        ?assert(is_process_alive(IndexerPid)),
+
+        compact_view_group(DbName, "foo"),
+        ?assertEqual(2, count_db_refs(DbName)),
+        Ref3 = get_db_ref_counter(DbName),
+        ?assertEqual(Ref3, Ref2),
+        ?assert(is_process_alive(IndexerPid)),
+
+        create_doc(DbName, "doc1001"),
+        Rows2 = query_view(DbName, "foo", "bar"),
+        ?assertEqual(5, length(Rows2)),
+        ?assertEqual(2, count_db_refs(DbName)),
+        ?assert(is_process_alive(IndexerPid))
+    end).
+
+couchdb_1309(DbName) ->
+    ?_test(begin
+        {ok, IndexerPid} = couch_index_server:get_index(
+            couch_mrview_index, DbName, <<"_design/foo">>),
+        ?assert(is_pid(IndexerPid)),
+        ?assert(is_process_alive(IndexerPid)),
+        ?assertEqual(2, count_db_refs(DbName)),
+
+        create_doc(DbName, "doc1001"),
+        Rows0 = query_view(DbName, "foo", "bar"),
+        check_rows_value(Rows0, null),
+        ?assertEqual(4, length(Rows0)),
+        ?assertEqual(2, count_db_refs(DbName)),
+        ?assert(is_process_alive(IndexerPid)),
+
+        update_design_doc(DbName,  <<"_design/foo">>, <<"bar">>),
+        {ok, NewIndexerPid} = couch_index_server:get_index(
+            couch_mrview_index, DbName, <<"_design/foo">>),
+        ?assert(is_pid(NewIndexerPid)),
+        ?assert(is_process_alive(NewIndexerPid)),
+        ?assertNotEqual(IndexerPid, NewIndexerPid),
+        ?assertEqual(2, count_db_refs(DbName)),
+
+        Rows1 = query_view(DbName, "foo", "bar", ok),
+        ?assertEqual(0, length(Rows1)),
+        Rows2 = query_view(DbName, "foo", "bar"),
+        check_rows_value(Rows2, 1),
+        ?assertEqual(4, length(Rows2)),
+
+        MonRef0 = erlang:monitor(process, IndexerPid),
+        receive
+            {'DOWN', MonRef0, _, _, _} ->
+                ok
+        after ?TIMEOUT ->
+            erlang:error(
+                {assertion_failed,
+                 [{module, ?MODULE}, {line, ?LINE},
+                  {reason, "old view group is not dead after ddoc update"}]})
+        end,
+
+        MonRef1 = erlang:monitor(process, NewIndexerPid),
+        ok = couch_server:delete(DbName, [?ADMIN_USER]),
+        receive
+            {'DOWN', MonRef1, _, _, _} ->
+                ok
+        after ?TIMEOUT ->
+            erlang:error(
+                {assertion_failed,
+                 [{module, ?MODULE}, {line, ?LINE},
+                  {reason, "new view group did not die after DB deletion"}]})
+        end
+    end).
+
+couchdb_1283() ->
+    ?_test(begin
+        ok = couch_config:set("couchdb", "max_dbs_open", "3", false),
+        ok = couch_config:set("couchdb", "delayed_commits", "false", false),
+
+        {ok, MDb1} = couch_db:create(?tempdb(), [?ADMIN_USER]),
+        DDoc = couch_doc:from_json_obj({[
+            {<<"_id">>, <<"_design/foo">>},
+            {<<"language">>, <<"javascript">>},
+            {<<"views">>, {[
+                {<<"foo">>, {[
+                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
+                ]}},
+                {<<"foo2">>, {[
+                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
+                ]}},
+                {<<"foo3">>, {[
+                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
+                ]}},
+                {<<"foo4">>, {[
+                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
+                ]}},
+                {<<"foo5">>, {[
+                    {<<"map">>, <<"function(doc) { emit(doc._id, null); }">>}
+                ]}}
+            ]}}
+        ]}),
+        {ok, _} = couch_db:update_doc(MDb1, DDoc, []),
+        ok = populate_db(MDb1, 100, 100),
+        query_view(MDb1#db.name, "foo", "foo"),
+        ok = couch_db:close(MDb1),
+
+        {ok, Db1} = couch_db:create(?tempdb(), [?ADMIN_USER]),
+        ok = couch_db:close(Db1),
+        {ok, Db2} = couch_db:create(?tempdb(), [?ADMIN_USER]),
+        ok = couch_db:close(Db2),
+        {ok, Db3} = couch_db:create(?tempdb(), [?ADMIN_USER]),
+        ok = couch_db:close(Db3),
+
+        Writer1 = spawn_writer(Db1#db.name),
+        Writer2 = spawn_writer(Db2#db.name),
+
+        ?assert(is_process_alive(Writer1)),
+        ?assert(is_process_alive(Writer2)),
+
+        ?assertEqual(ok, get_writer_status(Writer1)),
+        ?assertEqual(ok, get_writer_status(Writer2)),
+
+        {ok, MonRef} = couch_mrview:compact(MDb1#db.name, <<"_design/foo">>,
+                                            [monitor]),
+
+        Writer3 = spawn_writer(Db3#db.name),
+        ?assert(is_process_alive(Writer3)),
+        ?assertEqual({error, all_dbs_active}, get_writer_status(Writer3)),
+
+        ?assert(is_process_alive(Writer1)),
+        ?assert(is_process_alive(Writer2)),
+        ?assert(is_process_alive(Writer3)),
+
+        receive
+            {'DOWN', MonRef, process, _, Reason} ->
+                ?assertEqual(normal, Reason)
+        after ?TIMEOUT ->
+            erlang:error(
+                {assertion_failed,
+                 [{module, ?MODULE}, {line, ?LINE},
+                  {reason, "Failure compacting view group"}]})
+        end,
+
+        ?assertEqual(ok, writer_try_again(Writer3)),
+        ?assertEqual(ok, get_writer_status(Writer3)),
+
+        ?assert(is_process_alive(Writer1)),
+        ?assert(is_process_alive(Writer2)),
+        ?assert(is_process_alive(Writer3)),
+
+        ?assertEqual(ok, stop_writer(Writer1)),
+        ?assertEqual(ok, stop_writer(Writer2)),
+        ?assertEqual(ok, stop_writer(Writer3))
+    end).
+
+create_doc(DbName, DocId) when is_list(DocId) ->
+    create_doc(DbName, ?l2b(DocId));
+create_doc(DbName, DocId) when is_binary(DocId) ->
+    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
+    Doc666 = couch_doc:from_json_obj({[
+        {<<"_id">>, DocId},
+        {<<"value">>, 999}
+    ]}),
+    {ok, _} = couch_db:update_docs(Db, [Doc666]),
+    couch_db:ensure_full_commit(Db),
+    couch_db:close(Db).
+
+create_docs(DbName) ->
+    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
+    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).
+
+populate_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_db(Db, BatchSize, N - length(Docs));
+populate_db(_Db, _, _) ->
+    ok.
+
+create_design_doc(DbName, DDName, ViewName) ->
+    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
+    DDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, DDName},
+        {<<"language">>, <<"javascript">>},
+        {<<"views">>, {[
+            {ViewName, {[
+                {<<"map">>, <<"function(doc) { emit(doc.value, null); }">>}
+            ]}}
+        ]}}
+    ]}),
+    {ok, Rev} = couch_db:update_doc(Db, DDoc, []),
+    couch_db:ensure_full_commit(Db),
+    couch_db:close(Db),
+    Rev.
+
+update_design_doc(DbName, DDName, ViewName) ->
+    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
+    {ok, Doc} = couch_db:open_doc(Db, DDName, [?ADMIN_USER]),
+    {Props} = couch_doc:to_json_obj(Doc, []),
+    Rev = couch_util:get_value(<<"_rev">>, Props),
+    DDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, DDName},
+        {<<"_rev">>, Rev},
+        {<<"language">>, <<"javascript">>},
+        {<<"views">>, {[
+            {ViewName, {[
+                {<<"map">>, <<"function(doc) { emit(doc.value, 1); }">>}
+            ]}}
+        ]}}
+    ]}),
+    {ok, NewRev} = couch_db:update_doc(Db, DDoc, [?ADMIN_USER]),
+    couch_db:ensure_full_commit(Db),
+    couch_db:close(Db),
+    NewRev.
+
+delete_design_doc(DbName, DDName, Rev) ->
+    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
+    DDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, DDName},
+        {<<"_rev">>, couch_doc:rev_to_str(Rev)},
+        {<<"_deleted">>, true}
+    ]}),
+    {ok, _} = couch_db:update_doc(Db, DDoc, [Rev]),
+    couch_db:close(Db).
+
+db_url(DbName) ->
+    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
+    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
+    "http://" ++ Addr ++ ":" ++ Port ++ "/" ++ ?b2l(DbName).
+
+query_view(DbName, DDoc, View) ->
+    query_view(DbName, DDoc, View, false).
+
+query_view(DbName, DDoc, View, Stale) ->
+    {ok, Code, _Headers, Body} = test_request:get(
+        db_url(DbName) ++ "/_design/" ++ DDoc ++ "/_view/" ++ View
+        ++ case Stale of
+               false -> [];
+               _ -> "?stale=" ++ atom_to_list(Stale)
+           end),
+    ?assertEqual(200, Code),
+    {Props} = ejson:decode(Body),
+    couch_util:get_value(<<"rows">>, Props, []).
+
+check_rows_value(Rows, Value) ->
+    lists:foreach(
+        fun({Row}) ->
+            ?assertEqual(Value, couch_util:get_value(<<"value">>, Row))
+        end, Rows).
+
+view_cleanup(DbName) ->
+    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
+    couch_mrview:cleanup(Db),
+    couch_db:close(Db).
+
+get_db_ref_counter(DbName) ->
+    {ok, #db{fd_ref_counter = Ref} = Db} = couch_db:open_int(DbName, []),
+    ok = couch_db:close(Db),
+    Ref.
+
+count_db_refs(DbName) ->
+    Ref = get_db_ref_counter(DbName),
+    % have to sleep a bit to let couchdb cleanup all refs and leave only
+    % active ones. otherwise the related tests will randomly fail due to
+    % count number mismatch
+    timer:sleep(200),
+    couch_ref_counter:count(Ref).
+
+count_index_files(DbName) ->
+    % call server to fetch the index files
+    RootDir = couch_config:get("couchdb", "view_index_dir"),
+    length(filelib:wildcard(RootDir ++ "/." ++
+        binary_to_list(DbName) ++ "_design"++"/mrview/*")).
+
+has_doc(DocId1, Rows) ->
+    DocId = iolist_to_binary(DocId1),
+    lists:any(fun({R}) -> lists:member({<<"id">>, DocId}, R) end, Rows).
+
+backup_db_file(DbName) ->
+    DbDir = couch_config:get("couchdb", "database_dir"),
+    DbFile = filename:join([DbDir, ?b2l(DbName) ++ ".couch"]),
+    {ok, _} = file:copy(DbFile, DbFile ++ ".backup"),
+    ok.
+
+restore_backup_db_file(DbName) ->
+    DbDir = couch_config:get("couchdb", "database_dir"),
+    stop(whereis(couch_server_sup)),
+    DbFile = filename:join([DbDir, ?b2l(DbName) ++ ".couch"]),
+    ok = file:delete(DbFile),
+    ok = file:rename(DbFile ++ ".backup", DbFile),
+    start(),
+    ok.
+
+compact_db(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, _} = couch_db:start_compact(Db),
+    ok = couch_db:close(Db),
+    wait_db_compact_done(DbName, 10).
+
+wait_db_compact_done(_DbName, 0) ->
+    erlang:error({assertion_failed,
+                  [{module, ?MODULE},
+                   {line, ?LINE},
+                   {reason, "DB compaction failed to finish"}]});
+wait_db_compact_done(DbName, N) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    ok = couch_db:close(Db),
+    case is_pid(Db#db.compactor_pid) of
+    false ->
+        ok;
+    true ->
+        ok = timer:sleep(?DELAY),
+        wait_db_compact_done(DbName, N - 1)
+    end.
+
+compact_view_group(DbName, DDocId) when is_list(DDocId) ->
+    compact_view_group(DbName, ?l2b("_design/" ++ DDocId));
+compact_view_group(DbName, DDocId) when is_binary(DDocId) ->
+    ok = couch_mrview:compact(DbName, DDocId),
+    wait_view_compact_done(DbName, DDocId, 10).
+
+wait_view_compact_done(_DbName, _DDocId, 0) ->
+    erlang:error({assertion_failed,
+                  [{module, ?MODULE},
+                   {line, ?LINE},
+                   {reason, "DB compaction failed to finish"}]});
+wait_view_compact_done(DbName, DDocId, N) ->
+    {ok, Code, _Headers, Body} = test_request:get(
+        db_url(DbName) ++ "/" ++ ?b2l(DDocId) ++ "/_info"),
+    ?assertEqual(200, Code),
+    {Info} = ejson: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(?DELAY),
+            wait_view_compact_done(DbName, DDocId, N - 1)
+    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 ?TIMEOUT ->
+        timeout
+    end.
+
+writer_try_again(Writer) ->
+    Ref = make_ref(),
+    Writer ! {try_again, Ref},
+    receive
+        {ok, Ref} ->
+            ok
+    after ?TIMEOUT ->
+        timeout
+    end.
+
+stop_writer(Writer) ->
+    Ref = make_ref(),
+    Writer ! {stop, Ref},
+    receive
+        {ok, Ref} ->
+            ok
+    after ?TIMEOUT ->
+        erlang:error({assertion_failed,
+                      [{module, ?MODULE},
+                       {line, ?LINE},
+                       {reason, "Timeout on stopping process"}]})
+    end.
+
+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.
+
+read_header(File) ->
+    {ok, Fd} = couch_file:open(File),
+    {ok, {_Sig, Header}} = couch_file:read_header(Fd),
+    couch_file:close(Fd),
+    Header.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/fixtures/3b835456c235b1827e012e25666152f3.view
----------------------------------------------------------------------
diff --git a/test/fixtures/3b835456c235b1827e012e25666152f3.view b/test/fixtures/3b835456c235b1827e012e25666152f3.view
new file mode 100644
index 0000000..9c67648
Binary files /dev/null and b/test/fixtures/3b835456c235b1827e012e25666152f3.view differ

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/fixtures/couch_config_tests_1.ini
----------------------------------------------------------------------
diff --git a/test/fixtures/couch_config_tests_1.ini b/test/fixtures/couch_config_tests_1.ini
new file mode 100644
index 0000000..55451da
--- /dev/null
+++ b/test/fixtures/couch_config_tests_1.ini
@@ -0,0 +1,22 @@
+; 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

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/fixtures/couch_config_tests_2.ini
----------------------------------------------------------------------
diff --git a/test/fixtures/couch_config_tests_2.ini b/test/fixtures/couch_config_tests_2.ini
new file mode 100644
index 0000000..5f46357
--- /dev/null
+++ b/test/fixtures/couch_config_tests_2.ini
@@ -0,0 +1,22 @@
+; 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

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/fixtures/couch_stats_aggregates.cfg
----------------------------------------------------------------------
diff --git a/test/fixtures/couch_stats_aggregates.cfg b/test/fixtures/couch_stats_aggregates.cfg
new file mode 100644
index 0000000..30e475d
--- /dev/null
+++ b/test/fixtures/couch_stats_aggregates.cfg
@@ -0,0 +1,19 @@
+% 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"}.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/fixtures/couch_stats_aggregates.ini
----------------------------------------------------------------------
diff --git a/test/fixtures/couch_stats_aggregates.ini b/test/fixtures/couch_stats_aggregates.ini
new file mode 100644
index 0000000..cc5cd21
--- /dev/null
+++ b/test/fixtures/couch_stats_aggregates.ini
@@ -0,0 +1,20 @@
+; 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]

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/fixtures/logo.png
----------------------------------------------------------------------
diff --git a/test/fixtures/logo.png b/test/fixtures/logo.png
new file mode 100644
index 0000000..d21ac02
Binary files /dev/null and b/test/fixtures/logo.png differ

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/fixtures/os_daemon_bad_perm.sh
----------------------------------------------------------------------
diff --git a/test/fixtures/os_daemon_bad_perm.sh b/test/fixtures/os_daemon_bad_perm.sh
new file mode 100644
index 0000000..345c8b4
--- /dev/null
+++ b/test/fixtures/os_daemon_bad_perm.sh
@@ -0,0 +1,17 @@
+#!/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

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/fixtures/os_daemon_can_reboot.sh
----------------------------------------------------------------------
diff --git a/test/fixtures/os_daemon_can_reboot.sh b/test/fixtures/os_daemon_can_reboot.sh
new file mode 100755
index 0000000..5bc10e8
--- /dev/null
+++ b/test/fixtures/os_daemon_can_reboot.sh
@@ -0,0 +1,15 @@
+#!/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-couch/blob/dfad673e/test/fixtures/os_daemon_configer.escript
----------------------------------------------------------------------
diff --git a/test/fixtures/os_daemon_configer.escript b/test/fixtures/os_daemon_configer.escript
new file mode 100755
index 0000000..d437423
--- /dev/null
+++ b/test/fixtures/os_daemon_configer.escript
@@ -0,0 +1,101 @@
+#! /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.
+
+-include("../couch_eunit.hrl").
+
+
+read() ->
+    case io:get_line('') of
+        eof ->
+            stop;
+        Data ->
+            ejson:decode(Data)
+    end.
+
+write(Mesg) ->
+    Data = iolist_to_binary(ejson: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() ->
+    Path = list_to_binary(?FILE),
+    FileName = list_to_binary(filename:basename(?FILE)),
+    {[{FileName, Path}]} = get_cfg(<<"os_daemons">>).
+
+test_get_cfg2() ->
+    Path = list_to_binary(?FILE),
+    FileName = list_to_binary(filename:basename(?FILE)),
+    Path = get_cfg(<<"os_daemons">>, FileName),
+    <<"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([]) ->
+    init_code_path(),
+    couch_config:start_link(?CONFIG_CHAIN),
+    couch_drv:start_link(),
+    do_tests().
+
+init_code_path() ->
+    Paths = [
+        "couchdb",
+        "ejson",
+        "erlang-oauth",
+        "ibrowse",
+        "mochiweb",
+        "snappy"
+    ],
+    lists:foreach(fun(Name) ->
+        code:add_patha(filename:join([?BUILDDIR, "src", Name]))
+    end, Paths).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/fixtures/os_daemon_die_on_boot.sh
----------------------------------------------------------------------
diff --git a/test/fixtures/os_daemon_die_on_boot.sh b/test/fixtures/os_daemon_die_on_boot.sh
new file mode 100755
index 0000000..256ee79
--- /dev/null
+++ b/test/fixtures/os_daemon_die_on_boot.sh
@@ -0,0 +1,15 @@
+#!/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

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/fixtures/os_daemon_die_quickly.sh
----------------------------------------------------------------------
diff --git a/test/fixtures/os_daemon_die_quickly.sh b/test/fixtures/os_daemon_die_quickly.sh
new file mode 100755
index 0000000..f5a1368
--- /dev/null
+++ b/test/fixtures/os_daemon_die_quickly.sh
@@ -0,0 +1,15 @@
+#!/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-couch/blob/dfad673e/test/fixtures/os_daemon_looper.escript
----------------------------------------------------------------------
diff --git a/test/fixtures/os_daemon_looper.escript b/test/fixtures/os_daemon_looper.escript
new file mode 100755
index 0000000..73974e9
--- /dev/null
+++ b/test/fixtures/os_daemon_looper.escript
@@ -0,0 +1,26 @@
+#! /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().

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/fixtures/test.couch
----------------------------------------------------------------------
diff --git a/test/fixtures/test.couch b/test/fixtures/test.couch
new file mode 100644
index 0000000..32c79af
Binary files /dev/null and b/test/fixtures/test.couch differ

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/json_stream_parse_tests.erl
----------------------------------------------------------------------
diff --git a/test/json_stream_parse_tests.erl b/test/json_stream_parse_tests.erl
new file mode 100644
index 0000000..92303b6
--- /dev/null
+++ b/test/json_stream_parse_tests.erl
@@ -0,0 +1,151 @@
+% 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(json_stream_parse_tests).
+
+-include("couch_eunit.hrl").
+
+-define(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"}
+    ]
+).
+
+
+raw_json_input_test_() ->
+    Tests = lists:map(
+        fun({EJson, JsonString, Desc}) ->
+            {Desc,
+             ?_assert(equiv(EJson, json_stream_parse:to_ejson(JsonString)))}
+        end, ?CASES),
+    {"Tests with raw JSON string as the input", Tests}.
+
+one_byte_data_fun_test_() ->
+    Tests = lists:map(
+        fun({EJson, JsonString, Desc}) ->
+            DataFun = fun() -> single_byte_data_fun(JsonString) end,
+            {Desc,
+             ?_assert(equiv(EJson, json_stream_parse:to_ejson(DataFun)))}
+        end, ?CASES),
+    {"Tests with a 1 byte output data function as the input", Tests}.
+
+test_multiple_bytes_data_fun_test_() ->
+    Tests = lists:map(
+        fun({EJson, JsonString, Desc}) ->
+            DataFun = fun() -> multiple_bytes_data_fun(JsonString) end,
+            {Desc,
+             ?_assert(equiv(EJson, json_stream_parse:to_ejson(DataFun)))}
+        end, ?CASES),
+    {"Tests with a multiple bytes output data function as the input", Tests}.
+
+
+%% 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-couch/blob/dfad673e/test/test_request.erl
----------------------------------------------------------------------
diff --git a/test/test_request.erl b/test/test_request.erl
new file mode 100644
index 0000000..68e4956
--- /dev/null
+++ b/test/test_request.erl
@@ -0,0 +1,75 @@
+% 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_request).
+
+-export([get/1, get/2, get/3]).
+-export([put/2, put/3]).
+-export([options/1, options/2, options/3]).
+-export([request/3, request/4]).
+
+get(Url) ->
+    request(get, Url, []).
+
+get(Url, Headers) ->
+    request(get, Url, Headers).
+get(Url, Headers, Opts) ->
+    request(get, Url, Headers, [], Opts).
+
+
+put(Url, Body) ->
+    request(put, Url, [], Body).
+
+put(Url, Headers, Body) ->
+    request(put, Url, Headers, Body).
+
+
+options(Url) ->
+    request(options, Url, []).
+
+options(Url, Headers) ->
+    request(options, Url, Headers).
+
+options(Url, Headers, Opts) ->
+    request(options, Url, Headers, [], Opts).
+
+
+request(Method, Url, Headers) ->
+    request(Method, Url, Headers, []).
+
+request(Method, Url, Headers, Body) ->
+    request(Method, Url, Headers, Body, [], 3).
+
+request(Method, Url, Headers, Body, Opts) ->
+    request(Method, Url, Headers, Body, Opts, 3).
+
+request(_Method, _Url, _Headers, _Body, _Opts, 0) ->
+    {error, request_failed};
+request(Method, Url, Headers, Body, Opts, N) ->
+    case code:is_loaded(ibrowse) of
+        false ->
+            {ok, _} = ibrowse:start();
+        _ ->
+            ok
+    end,
+    case ibrowse:send_req(Url, Headers, Method, Body, Opts) of
+        {ok, Code0, RespHeaders, RespBody0} ->
+            Code = list_to_integer(Code0),
+            RespBody = iolist_to_binary(RespBody0),
+            {ok, Code, RespHeaders, RespBody};
+        {error, {'EXIT', {normal, _}}} ->
+            % Connection closed right after a successful request that
+            % used the same connection.
+            request(Method, Url, Headers, Body, N - 1);
+        Error ->
+            Error
+    end.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/test_web.erl
----------------------------------------------------------------------
diff --git a/test/test_web.erl b/test/test_web.erl
new file mode 100644
index 0000000..1de2cd1
--- /dev/null
+++ b/test/test_web.erl
@@ -0,0 +1,112 @@
+% 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).
+
+-include("couch_eunit.hrl").
+
+-export([start_link/0, stop/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).
+-define(DELAY, 500).
+
+start_link() ->
+    gen_server:start({local, ?HANDLER}, ?MODULE, [], []),
+    mochiweb_http:start([
+        {name, ?SERVER},
+        {loop, {?MODULE, loop}},
+        {port, 0}
+    ]).
+
+loop(Req) ->
+    %?debugFmt("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(?DELAY),
+            lists:foreach(fun(C) -> Resp:write_chunk(C) end, BodyChunks),
+            Resp:write_chunk([]),
+            {ok, Resp};
+        {error, Reason} ->
+            ?debugFmt("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) ->
+    ?assertEqual(ok, gen_server:call(?HANDLER, {set_assert, Fun})).
+
+check_last() ->
+    gen_server:call(?HANDLER, last_status).
+
+init(_) ->
+    {ok, nil}.
+
+terminate(_Reason, _State) ->
+    ok.
+
+stop() ->
+    gen_server:cast(?SERVER, stop).
+
+
+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(stop, State) ->
+    {stop, normal, State};
+handle_cast(Msg, State) ->
+    ?debugFmt("Ignoring cast message: ~p", [Msg]),
+    {noreply, State}.
+
+handle_info(Msg, State) ->
+    ?debugFmt("Ignoring info message: ~p", [Msg]),
+    {noreply, State}.
+
+code_change(_OldVsn, State, _Extra) ->
+    {ok, State}.


[40/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Update include paths


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/71f3dbef
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/71f3dbef
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/71f3dbef

Branch: refs/heads/1963-eunit-bigcouch
Commit: 71f3dbef8a57b5256c0b6dcb7193344732404a8c
Parents: dfad673
Author: Russell Branca <ch...@apache.org>
Authored: Mon Aug 11 14:50:15 2014 -0700
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:24:05 2014 -0700

----------------------------------------------------------------------
 test/couch_auth_cache_tests.erl         | 18 ++----------------
 test/couch_btree_tests.erl              |  4 ++--
 test/couch_changes_tests.erl            |  4 ++--
 test/couch_config_tests.erl             |  4 ++--
 test/couch_db_tests.erl                 |  2 +-
 test/couch_doc_json_tests.erl           |  4 ++--
 test/couch_file_tests.erl               |  2 +-
 test/couch_key_tree_tests.erl           |  2 +-
 test/couch_passwords_tests.erl          |  2 +-
 test/couch_ref_counter_tests.erl        |  4 ++--
 test/couch_stats_tests.erl              |  4 ++--
 test/couch_stream_tests.erl             |  2 +-
 test/couch_task_status_tests.erl        |  4 ++--
 test/couch_util_tests.erl               |  2 +-
 test/couch_uuids_tests.erl              |  2 +-
 test/couch_work_queue_tests.erl         |  2 +-
 test/couchdb_attachments_tests.erl      |  4 ++--
 test/couchdb_compaction_daemon.erl      |  4 ++--
 test/couchdb_cors_tests.erl             |  4 ++--
 test/couchdb_csp_tests.erl              |  2 +-
 test/couchdb_file_compression_tests.erl |  4 ++--
 test/couchdb_http_proxy_tests.erl       |  2 +-
 test/couchdb_os_daemons_tests.erl       |  2 +-
 test/couchdb_os_proc_pool.erl           |  4 ++--
 test/couchdb_update_conflicts_tests.erl |  4 ++--
 test/couchdb_vhosts_tests.erl           |  4 ++--
 test/couchdb_views_tests.erl            |  4 ++--
 test/json_stream_parse_tests.erl        |  2 +-
 test/test_web.erl                       |  2 +-
 29 files changed, 45 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_auth_cache_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_auth_cache_tests.erl b/test/couch_auth_cache_tests.erl
index 3b2321c..b2c43c3 100644
--- a/test/couch_auth_cache_tests.erl
+++ b/test/couch_auth_cache_tests.erl
@@ -12,28 +12,14 @@
 
 -module(couch_auth_cache_tests).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 -define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
 -define(SALT, <<"SALT">>).
 -define(TIMEOUT, 1000).
 
 
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
 setup() ->
     DbName = ?tempdb(),
     couch_config:set("couch_httpd_auth", "authentication_db",

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_btree_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_btree_tests.erl b/test/couch_btree_tests.erl
index 911640f..60469cf 100644
--- a/test/couch_btree_tests.erl
+++ b/test/couch_btree_tests.erl
@@ -12,8 +12,8 @@
 
 -module(couch_btree_tests).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 -define(ROWS, 1000).
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_changes_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_changes_tests.erl b/test/couch_changes_tests.erl
index a129ba2..7fd4c55 100644
--- a/test/couch_changes_tests.erl
+++ b/test/couch_changes_tests.erl
@@ -12,8 +12,8 @@
 
 -module(couch_changes_tests).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 -define(ADMIN_USER, {user_ctx, #user_ctx{roles = [<<"_admin">>]}}).
 -define(TIMEOUT, 3000).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_config_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_config_tests.erl b/test/couch_config_tests.erl
index 9e9dfe7..91ec5e6 100644
--- a/test/couch_config_tests.erl
+++ b/test/couch_config_tests.erl
@@ -12,8 +12,8 @@
 
 -module(couch_config_tests).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 -define(SHORT_TIMEOUT, 100).
 -define(TIMEOUT, 1000).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_db_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_db_tests.erl b/test/couch_db_tests.erl
index 3089714..d1fdf06 100644
--- a/test/couch_db_tests.erl
+++ b/test/couch_db_tests.erl
@@ -12,7 +12,7 @@
 
 -module(couch_db_tests).
 
--include("couch_eunit.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
 
 -define(TIMEOUT, 120).
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_doc_json_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_doc_json_tests.erl b/test/couch_doc_json_tests.erl
index 1592b6b..23fc961 100644
--- a/test/couch_doc_json_tests.erl
+++ b/test/couch_doc_json_tests.erl
@@ -12,8 +12,8 @@
 
 -module(couch_doc_json_tests).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 
 setup() ->

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_file_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_file_tests.erl b/test/couch_file_tests.erl
index ad13383..9b167ca 100644
--- a/test/couch_file_tests.erl
+++ b/test/couch_file_tests.erl
@@ -12,7 +12,7 @@
 
 -module(couch_file_tests).
 
--include("couch_eunit.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
 
 -define(BLOCK_SIZE, 4096).
 -define(setup(F), {setup, fun setup/0, fun teardown/1, F}).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_key_tree_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_key_tree_tests.erl b/test/couch_key_tree_tests.erl
index 753ecc4..7d68902 100644
--- a/test/couch_key_tree_tests.erl
+++ b/test/couch_key_tree_tests.erl
@@ -12,7 +12,7 @@
 
 -module(couch_key_tree_tests).
 
--include("couch_eunit.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
 
 -define(DEPTH, 10).
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_passwords_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_passwords_tests.erl b/test/couch_passwords_tests.erl
index 116265c..dea6d6b 100644
--- a/test/couch_passwords_tests.erl
+++ b/test/couch_passwords_tests.erl
@@ -12,7 +12,7 @@
 
 -module(couch_passwords_tests).
 
--include("couch_eunit.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
 
 
 pbkdf2_test_()->

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_ref_counter_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_ref_counter_tests.erl b/test/couch_ref_counter_tests.erl
index b7e97b4..0217623 100644
--- a/test/couch_ref_counter_tests.erl
+++ b/test/couch_ref_counter_tests.erl
@@ -12,8 +12,8 @@
 
 -module(couch_ref_counter_tests).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 -define(TIMEOUT, 1000).
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_stats_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_stats_tests.erl b/test/couch_stats_tests.erl
index d156449..6dbbb6a 100644
--- a/test/couch_stats_tests.erl
+++ b/test/couch_stats_tests.erl
@@ -12,8 +12,8 @@
 
 -module(couch_stats_tests).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 -define(STATS_CFG_FIXTURE,
     filename:join([?FIXTURESDIR, "couch_stats_aggregates.cfg"])).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_stream_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_stream_tests.erl b/test/couch_stream_tests.erl
index 335a2fe..3e84ca0 100644
--- a/test/couch_stream_tests.erl
+++ b/test/couch_stream_tests.erl
@@ -12,7 +12,7 @@
 
 -module(couch_stream_tests).
 
--include("couch_eunit.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
 
 
 setup() ->

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_task_status_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_task_status_tests.erl b/test/couch_task_status_tests.erl
index f71ad2b..200cee1 100644
--- a/test/couch_task_status_tests.erl
+++ b/test/couch_task_status_tests.erl
@@ -12,8 +12,8 @@
 
 -module(couch_task_status_tests).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 -define(TIMEOUT, 1000).
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_util_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_util_tests.erl b/test/couch_util_tests.erl
index 8e24e72..17e6942 100644
--- a/test/couch_util_tests.erl
+++ b/test/couch_util_tests.erl
@@ -12,7 +12,7 @@
 
 -module(couch_util_tests).
 
--include("couch_eunit.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
 
 
 setup() ->

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_uuids_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_uuids_tests.erl b/test/couch_uuids_tests.erl
index ea1d034..754a49b 100644
--- a/test/couch_uuids_tests.erl
+++ b/test/couch_uuids_tests.erl
@@ -12,7 +12,7 @@
 
 -module(couch_uuids_tests).
 
--include("couch_eunit.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
 
 -define(TIMEOUT_S, 20).
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couch_work_queue_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_work_queue_tests.erl b/test/couch_work_queue_tests.erl
index 8a463b5..c94dc00 100644
--- a/test/couch_work_queue_tests.erl
+++ b/test/couch_work_queue_tests.erl
@@ -12,7 +12,7 @@
 
 -module(couch_work_queue_tests).
 
--include("couch_eunit.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
 
 -define(TIMEOUT, 100).
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couchdb_attachments_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_attachments_tests.erl b/test/couchdb_attachments_tests.erl
index cf59785..70587f8 100644
--- a/test/couchdb_attachments_tests.erl
+++ b/test/couchdb_attachments_tests.erl
@@ -12,8 +12,8 @@
 
 -module(couchdb_attachments_tests).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 -define(COMPRESSION_LEVEL, 8).
 -define(ATT_BIN_NAME, <<"logo.png">>).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couchdb_compaction_daemon.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_compaction_daemon.erl b/test/couchdb_compaction_daemon.erl
index 725a97b..39e6118 100644
--- a/test/couchdb_compaction_daemon.erl
+++ b/test/couchdb_compaction_daemon.erl
@@ -12,8 +12,8 @@
 
 -module(couchdb_compaction_daemon).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 -define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
 -define(DELAY, 100).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couchdb_cors_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_cors_tests.erl b/test/couchdb_cors_tests.erl
index 4e88ae7..9f927c4 100644
--- a/test/couchdb_cors_tests.erl
+++ b/test/couchdb_cors_tests.erl
@@ -12,8 +12,8 @@
 
 -module(couchdb_cors_tests).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 
 -define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couchdb_csp_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_csp_tests.erl b/test/couchdb_csp_tests.erl
index adb0e6d..9733ad4 100644
--- a/test/couchdb_csp_tests.erl
+++ b/test/couchdb_csp_tests.erl
@@ -12,7 +12,7 @@
 
 -module(couchdb_csp_tests).
 
--include("couch_eunit.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
 
 -define(TIMEOUT, 1000).
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couchdb_file_compression_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_file_compression_tests.erl b/test/couchdb_file_compression_tests.erl
index fd3f513..dc3f939 100644
--- a/test/couchdb_file_compression_tests.erl
+++ b/test/couchdb_file_compression_tests.erl
@@ -12,8 +12,8 @@
 
 -module(couchdb_file_compression_tests).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 -define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
 -define(DDOC_ID, <<"_design/test">>).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couchdb_http_proxy_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_http_proxy_tests.erl b/test/couchdb_http_proxy_tests.erl
index acb1974..262eb15 100644
--- a/test/couchdb_http_proxy_tests.erl
+++ b/test/couchdb_http_proxy_tests.erl
@@ -12,7 +12,7 @@
 
 -module(couchdb_http_proxy_tests).
 
--include("couch_eunit.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
 
 -record(req, {method=get, path="", headers=[], body="", opts=[]}).
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couchdb_os_daemons_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_os_daemons_tests.erl b/test/couchdb_os_daemons_tests.erl
index aa949c9..ef21f58 100644
--- a/test/couchdb_os_daemons_tests.erl
+++ b/test/couchdb_os_daemons_tests.erl
@@ -12,7 +12,7 @@
 
 -module(couchdb_os_daemons_tests).
 
--include("couch_eunit.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
 
 %% keep in sync with couchdb/couch_os_daemons.erl
 -record(daemon, {

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couchdb_os_proc_pool.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_os_proc_pool.erl b/test/couchdb_os_proc_pool.erl
index 1bb266e..1a37bd6 100644
--- a/test/couchdb_os_proc_pool.erl
+++ b/test/couchdb_os_proc_pool.erl
@@ -12,8 +12,8 @@
 
 -module(couchdb_os_proc_pool).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 -define(TIMEOUT, 3000).
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couchdb_update_conflicts_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_update_conflicts_tests.erl b/test/couchdb_update_conflicts_tests.erl
index 7226860..adf1e5c 100644
--- a/test/couchdb_update_conflicts_tests.erl
+++ b/test/couchdb_update_conflicts_tests.erl
@@ -12,8 +12,8 @@
 
 -module(couchdb_update_conflicts_tests).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 -define(i2l(I), integer_to_list(I)).
 -define(ADMIN_USER, {userctx, #user_ctx{roles=[<<"_admin">>]}}).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couchdb_vhosts_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_vhosts_tests.erl b/test/couchdb_vhosts_tests.erl
index 94b1957..fc55c1c 100644
--- a/test/couchdb_vhosts_tests.erl
+++ b/test/couchdb_vhosts_tests.erl
@@ -12,8 +12,8 @@
 
 -module(couchdb_vhosts_tests).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 -define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
 -define(TIMEOUT, 1000).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/couchdb_views_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_views_tests.erl b/test/couchdb_views_tests.erl
index 6d81f32..24b5e5b 100644
--- a/test/couchdb_views_tests.erl
+++ b/test/couchdb_views_tests.erl
@@ -12,8 +12,8 @@
 
 -module(couchdb_views_tests).
 
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
 -include_lib("couch_mrview/include/couch_mrview.hrl").
 
 -define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/json_stream_parse_tests.erl
----------------------------------------------------------------------
diff --git a/test/json_stream_parse_tests.erl b/test/json_stream_parse_tests.erl
index 92303b6..ffcf918 100644
--- a/test/json_stream_parse_tests.erl
+++ b/test/json_stream_parse_tests.erl
@@ -12,7 +12,7 @@
 
 -module(json_stream_parse_tests).
 
--include("couch_eunit.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
 
 -define(CASES,
     [

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/71f3dbef/test/test_web.erl
----------------------------------------------------------------------
diff --git a/test/test_web.erl b/test/test_web.erl
index 1de2cd1..98172d0 100644
--- a/test/test_web.erl
+++ b/test/test_web.erl
@@ -13,7 +13,7 @@
 -module(test_web).
 -behaviour(gen_server).
 
--include("couch_eunit.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
 
 -export([start_link/0, stop/0, loop/1, get_port/0, set_assert/1, check_last/0]).
 -export([init/1, terminate/2, code_change/3]).


[34/50] [abbrv] Move files out of test/couchdb into top level test/ folder

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couchdb_attachments_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_attachments_tests.erl b/test/couchdb/couchdb_attachments_tests.erl
deleted file mode 100644
index cf59785..0000000
--- a/test/couchdb/couchdb_attachments_tests.erl
+++ /dev/null
@@ -1,638 +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(couchdb_attachments_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(COMPRESSION_LEVEL, 8).
--define(ATT_BIN_NAME, <<"logo.png">>).
--define(ATT_TXT_NAME, <<"file.erl">>).
--define(FIXTURE_PNG, filename:join([?FIXTURESDIR, "logo.png"])).
--define(FIXTURE_TXT, ?FILE).
--define(TIMEOUT, 1000).
--define(TIMEOUT_EUNIT, 10).
--define(TIMEWAIT, 100).
--define(i2l(I), integer_to_list(I)).
-
-
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    % ensure in default compression settings for attachments_compression_tests
-    couch_config:set("attachments", "compression_level",
-                     ?i2l(?COMPRESSION_LEVEL), false),
-    couch_config:set("attachments", "compressible_types", "text/*", false),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
-setup() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, []),
-    ok = couch_db:close(Db),
-    Addr = couch_config:get("httpd", "bind_address", any),
-    Port = mochiweb_socket_server:get(couch_httpd, port),
-    Host = Addr ++ ":" ++ ?i2l(Port),
-    {Host, ?b2l(DbName)}.
-
-setup({binary, standalone}) ->
-    {Host, DbName} = setup(),
-        setup_att(fun create_standalone_png_att/2, Host, DbName, ?FIXTURE_PNG);
-setup({text, standalone}) ->
-    {Host, DbName} = setup(),
-    setup_att(fun create_standalone_text_att/2, Host, DbName, ?FIXTURE_TXT);
-setup({binary, inline}) ->
-    {Host, DbName} = setup(),
-    setup_att(fun create_inline_png_att/2, Host, DbName, ?FIXTURE_PNG);
-setup({text, inline}) ->
-    {Host, DbName} = setup(),
-    setup_att(fun create_inline_text_att/2, Host, DbName, ?FIXTURE_TXT);
-setup(compressed) ->
-    {Host, DbName} = setup(),
-    setup_att(fun create_already_compressed_att/2, Host, DbName, ?FIXTURE_TXT).
-setup_att(Fun, Host, DbName, File) ->
-    HttpHost = "http://" ++ Host,
-    AttUrl = Fun(HttpHost, DbName),
-    {ok, Data} = file:read_file(File),
-    DocUrl = string:join([HttpHost, DbName, "doc"], "/"),
-    Helpers = {DbName, DocUrl, AttUrl},
-    {Data, Helpers}.
-
-teardown(_, {_, {DbName, _, _}}) ->
-    teardown(DbName).
-
-teardown({_, DbName}) ->
-    teardown(DbName);
-teardown(DbName) ->
-    ok = couch_server:delete(?l2b(DbName), []),
-    ok.
-
-
-attachments_test_() ->
-    {
-        "Attachments tests",
-        {
-            setup,
-            fun start/0, fun stop/1,
-            [
-                attachments_md5_tests(),
-                attachments_compression_tests()
-            ]
-        }
-    }.
-
-attachments_md5_tests() ->
-    {
-        "Attachments MD5 tests",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                fun should_upload_attachment_without_md5/1,
-                fun should_upload_attachment_by_chunks_without_md5/1,
-                fun should_upload_attachment_with_valid_md5_header/1,
-                fun should_upload_attachment_by_chunks_with_valid_md5_header/1,
-                fun should_upload_attachment_by_chunks_with_valid_md5_trailer/1,
-                fun should_reject_attachment_with_invalid_md5/1,
-                fun should_reject_chunked_attachment_with_invalid_md5/1,
-                fun should_reject_chunked_attachment_with_invalid_md5_trailer/1
-            ]
-        }
-    }.
-
-attachments_compression_tests() ->
-    Funs = [
-         fun should_get_att_without_accept_gzip_encoding/2,
-         fun should_get_att_with_accept_gzip_encoding/2,
-         fun should_get_att_with_accept_deflate_encoding/2,
-         fun should_return_406_response_on_unsupported_encoding/2,
-         fun should_get_doc_with_att_data/2,
-         fun should_get_doc_with_att_data_stub/2
-    ],
-    {
-        "Attachments compression tests",
-        [
-            {
-                "Created via Attachments API",
-                created_attachments_compression_tests(standalone, Funs)
-            },
-            {
-                "Created inline via Document API",
-                created_attachments_compression_tests(inline, Funs)
-            },
-            {
-                "Created already been compressed via Attachments API",
-                {
-                    foreachx,
-                    fun setup/1, fun teardown/2,
-                    [{compressed, Fun} || Fun <- Funs]
-                }
-            },
-            {
-                foreach,
-                fun setup/0, fun teardown/1,
-                [
-                    fun should_not_create_compressed_att_with_deflate_encoding/1,
-                    fun should_not_create_compressed_att_with_compress_encoding/1,
-                    fun should_create_compressible_att_with_ctype_params/1
-                ]
-            }
-        ]
-    }.
-
-created_attachments_compression_tests(Mod, Funs) ->
-    [
-        {
-            "Compressiable attachments",
-            {
-                foreachx,
-                fun setup/1, fun teardown/2,
-                [{{text, Mod}, Fun} || Fun <- Funs]
-            }
-        },
-        {
-            "Uncompressiable attachments",
-            {
-                foreachx,
-                fun setup/1, fun teardown/2,
-                [{{binary, Mod}, Fun} || Fun <- Funs]
-            }
-        }
-    ].
-
-
-
-should_upload_attachment_without_md5({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        Body = "We all live in a yellow submarine!",
-        Headers = [
-            {"Content-Length", "34"},
-            {"Content-Type", "text/plain"},
-            {"Host", Host}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(201, Code),
-        ?assertEqual(true, get_json(Json, [<<"ok">>]))
-    end).
-
-should_upload_attachment_by_chunks_without_md5({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        AttData = <<"We all live in a yellow submarine!">>,
-        <<Part1:21/binary, Part2:13/binary>> = AttData,
-        Body = chunked_body([Part1, Part2]),
-        Headers = [
-            {"Content-Type", "text/plain"},
-            {"Transfer-Encoding", "chunked"},
-            {"Host", Host}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(201, Code),
-        ?assertEqual(true, get_json(Json, [<<"ok">>]))
-    end).
-
-should_upload_attachment_with_valid_md5_header({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        Body = "We all live in a yellow submarine!",
-        Headers = [
-            {"Content-Length", "34"},
-            {"Content-Type", "text/plain"},
-            {"Content-MD5", ?b2l(base64:encode(couch_util:md5(Body)))},
-            {"Host", Host}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(201, Code),
-        ?assertEqual(true, get_json(Json, [<<"ok">>]))
-    end).
-
-should_upload_attachment_by_chunks_with_valid_md5_header({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        AttData = <<"We all live in a yellow submarine!">>,
-        <<Part1:21/binary, Part2:13/binary>> = AttData,
-        Body = chunked_body([Part1, Part2]),
-        Headers = [
-            {"Content-Type", "text/plain"},
-            {"Content-MD5", ?b2l(base64:encode(couch_util:md5(AttData)))},
-            {"Host", Host},
-            {"Transfer-Encoding", "chunked"}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(201, Code),
-        ?assertEqual(true, get_json(Json, [<<"ok">>]))
-    end).
-
-should_upload_attachment_by_chunks_with_valid_md5_trailer({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        AttData = <<"We all live in a yellow submarine!">>,
-        <<Part1:21/binary, Part2:13/binary>> = AttData,
-        Body = [chunked_body([Part1, Part2]),
-                "Content-MD5: ", base64:encode(couch_util:md5(AttData)),
-                "\r\n"],
-        Headers = [
-            {"Content-Type", "text/plain"},
-            {"Host", Host},
-            {"Trailer", "Content-MD5"},
-            {"Transfer-Encoding", "chunked"}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(201, Code),
-        ?assertEqual(true, get_json(Json, [<<"ok">>]))
-    end).
-
-should_reject_attachment_with_invalid_md5({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        Body = "We all live in a yellow submarine!",
-        Headers = [
-            {"Content-Length", "34"},
-            {"Content-Type", "text/plain"},
-            {"Content-MD5", ?b2l(base64:encode(<<"foobar!">>))},
-            {"Host", Host}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(400, Code),
-        ?assertEqual(<<"content_md5_mismatch">>,
-                     get_json(Json, [<<"error">>]))
-    end).
-
-
-should_reject_chunked_attachment_with_invalid_md5({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        AttData = <<"We all live in a yellow submarine!">>,
-        <<Part1:21/binary, Part2:13/binary>> = AttData,
-        Body = chunked_body([Part1, Part2]),
-        Headers = [
-            {"Content-Type", "text/plain"},
-            {"Content-MD5", ?b2l(base64:encode(<<"foobar!">>))},
-            {"Host", Host},
-            {"Transfer-Encoding", "chunked"}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(400, Code),
-        ?assertEqual(<<"content_md5_mismatch">>,
-                     get_json(Json, [<<"error">>]))
-    end).
-
-should_reject_chunked_attachment_with_invalid_md5_trailer({Host, DbName}) ->
-    ?_test(begin
-        AttUrl = string:join(["", DbName, ?docid(), "readme.txt"], "/"),
-        AttData = <<"We all live in a yellow submarine!">>,
-        <<Part1:21/binary, Part2:13/binary>> = AttData,
-        Body = [chunked_body([Part1, Part2]),
-                "Content-MD5: ", base64:encode(<<"foobar!">>),
-                "\r\n"],
-        Headers = [
-            {"Content-Type", "text/plain"},
-            {"Host", Host},
-            {"Trailer", "Content-MD5"},
-            {"Transfer-Encoding", "chunked"}
-        ],
-        {ok, Code, Json} = request("PUT", AttUrl, Headers, Body),
-        ?assertEqual(400, Code),
-        ?assertEqual(<<"content_md5_mismatch">>, get_json(Json, [<<"error">>]))
-    end).
-
-should_get_att_without_accept_gzip_encoding(_, {Data, {_, _, AttUrl}}) ->
-    ?_test(begin
-        {ok, Code, Headers, Body} = test_request:get(AttUrl),
-        ?assertEqual(200, Code),
-        ?assertNot(lists:member({"Content-Encoding", "gzip"}, Headers)),
-        ?assertEqual(Data, iolist_to_binary(Body))
-    end).
-
-should_get_att_with_accept_gzip_encoding(compressed, {Data, {_, _, AttUrl}}) ->
-    ?_test(begin
-        {ok, Code, Headers, Body} = test_request:get(
-            AttUrl, [{"Accept-Encoding", "gzip"}]),
-        ?assertEqual(200, Code),
-        ?assert(lists:member({"Content-Encoding", "gzip"}, Headers)),
-        ?assertEqual(Data, zlib:gunzip(iolist_to_binary(Body)))
-    end);
-should_get_att_with_accept_gzip_encoding({text, _}, {Data, {_, _, AttUrl}}) ->
-    ?_test(begin
-        {ok, Code, Headers, Body} = test_request:get(
-            AttUrl, [{"Accept-Encoding", "gzip"}]),
-        ?assertEqual(200, Code),
-        ?assert(lists:member({"Content-Encoding", "gzip"}, Headers)),
-        ?assertEqual(Data, zlib:gunzip(iolist_to_binary(Body)))
-    end);
-should_get_att_with_accept_gzip_encoding({binary, _}, {Data, {_, _, AttUrl}}) ->
-    ?_test(begin
-        {ok, Code, Headers, Body} = test_request:get(
-            AttUrl, [{"Accept-Encoding", "gzip"}]),
-        ?assertEqual(200, Code),
-        ?assertEqual(undefined,
-                     couch_util:get_value("Content-Encoding", Headers)),
-        ?assertEqual(Data, iolist_to_binary(Body))
-    end).
-
-should_get_att_with_accept_deflate_encoding(_, {Data, {_, _, AttUrl}}) ->
-    ?_test(begin
-        {ok, Code, Headers, Body} = test_request:get(
-            AttUrl, [{"Accept-Encoding", "deflate"}]),
-        ?assertEqual(200, Code),
-        ?assertEqual(undefined,
-                     couch_util:get_value("Content-Encoding", Headers)),
-        ?assertEqual(Data, iolist_to_binary(Body))
-    end).
-
-should_return_406_response_on_unsupported_encoding(_, {_, {_, _, AttUrl}}) ->
-    ?_assertEqual(406,
-        begin
-            {ok, Code, _, _} = test_request:get(
-                AttUrl, [{"Accept-Encoding", "deflate, *;q=0"}]),
-            Code
-        end).
-
-should_get_doc_with_att_data(compressed, {Data, {_, DocUrl, _}}) ->
-    ?_test(begin
-        Url = DocUrl ++ "?attachments=true",
-        {ok, Code, _, Body} = test_request:get(
-            Url, [{"Accept", "application/json"}]),
-        ?assertEqual(200, Code),
-        Json = ejson:decode(Body),
-        AttJson = couch_util:get_nested_json_value(
-            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
-        AttData = couch_util:get_nested_json_value(
-            AttJson, [<<"data">>]),
-        ?assertEqual(
-            <<"text/plain">>,
-            couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
-        ?assertEqual(Data, base64:decode(AttData))
-    end);
-should_get_doc_with_att_data({text, _}, {Data, {_, DocUrl, _}}) ->
-    ?_test(begin
-        Url = DocUrl ++ "?attachments=true",
-        {ok, Code, _, Body} = test_request:get(
-            Url, [{"Accept", "application/json"}]),
-        ?assertEqual(200, Code),
-        Json = ejson:decode(Body),
-        AttJson = couch_util:get_nested_json_value(
-            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
-        AttData = couch_util:get_nested_json_value(
-            AttJson, [<<"data">>]),
-        ?assertEqual(
-            <<"text/plain">>,
-            couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
-        ?assertEqual(Data, base64:decode(AttData))
-    end);
-should_get_doc_with_att_data({binary, _}, {Data, {_, DocUrl, _}}) ->
-    ?_test(begin
-        Url = DocUrl ++ "?attachments=true",
-        {ok, Code, _, Body} = test_request:get(
-            Url, [{"Accept", "application/json"}]),
-        ?assertEqual(200, Code),
-        Json = ejson:decode(Body),
-        AttJson = couch_util:get_nested_json_value(
-            Json, [<<"_attachments">>, ?ATT_BIN_NAME]),
-        AttData = couch_util:get_nested_json_value(
-            AttJson, [<<"data">>]),
-        ?assertEqual(
-            <<"image/png">>,
-            couch_util:get_nested_json_value(AttJson,[<<"content_type">>])),
-        ?assertEqual(Data, base64:decode(AttData))
-    end).
-
-should_get_doc_with_att_data_stub(compressed, {Data, {_, DocUrl, _}}) ->
-    ?_test(begin
-        Url = DocUrl ++ "?att_encoding_info=true",
-        {ok, Code, _, Body} = test_request:get(
-            Url, [{"Accept", "application/json"}]),
-        ?assertEqual(200, Code),
-        Json = ejson:decode(Body),
-        {AttJson} = couch_util:get_nested_json_value(
-            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
-        ?assertEqual(<<"gzip">>,
-                     couch_util:get_value(<<"encoding">>, AttJson)),
-        AttLength = couch_util:get_value(<<"length">>, AttJson),
-        EncLength = couch_util:get_value(<<"encoded_length">>, AttJson),
-        ?assertEqual(AttLength, EncLength),
-        ?assertEqual(iolist_size(zlib:gzip(Data)), AttLength)
-    end);
-should_get_doc_with_att_data_stub({text, _}, {Data, {_, DocUrl, _}}) ->
-    ?_test(begin
-        Url = DocUrl ++ "?att_encoding_info=true",
-        {ok, Code, _, Body} = test_request:get(
-            Url, [{"Accept", "application/json"}]),
-        ?assertEqual(200, Code),
-        Json = ejson:decode(Body),
-        {AttJson} = couch_util:get_nested_json_value(
-            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
-        ?assertEqual(<<"gzip">>,
-                     couch_util:get_value(<<"encoding">>, AttJson)),
-        AttEncLength = iolist_size(gzip(Data)),
-        ?assertEqual(AttEncLength,
-                     couch_util:get_value(<<"encoded_length">>, AttJson)),
-        ?assertEqual(byte_size(Data),
-                     couch_util:get_value(<<"length">>, AttJson))
-    end);
-should_get_doc_with_att_data_stub({binary, _}, {Data, {_, DocUrl, _}}) ->
-    ?_test(begin
-        Url = DocUrl ++ "?att_encoding_info=true",
-        {ok, Code, _, Body} = test_request:get(
-            Url, [{"Accept", "application/json"}]),
-        ?assertEqual(200, Code),
-        Json = ejson:decode(Body),
-        {AttJson} = couch_util:get_nested_json_value(
-            Json, [<<"_attachments">>, ?ATT_BIN_NAME]),
-        ?assertEqual(undefined,
-                     couch_util:get_value(<<"encoding">>, AttJson)),
-        ?assertEqual(undefined,
-                     couch_util:get_value(<<"encoded_length">>, AttJson)),
-        ?assertEqual(byte_size(Data),
-                     couch_util:get_value(<<"length">>, AttJson))
-    end).
-
-should_not_create_compressed_att_with_deflate_encoding({Host, DbName}) ->
-    ?_assertEqual(415,
-        begin
-            HttpHost = "http://" ++ Host,
-            AttUrl = string:join([HttpHost, DbName, ?docid(), "file.txt"], "/"),
-            {ok, Data} = file:read_file(?FIXTURE_TXT),
-            Body = zlib:compress(Data),
-            Headers = [
-                {"Content-Encoding", "deflate"},
-                {"Content-Type", "text/plain"}
-            ],
-            {ok, Code, _, _} = test_request:put(AttUrl, Headers, Body),
-            Code
-        end).
-
-should_not_create_compressed_att_with_compress_encoding({Host, DbName}) ->
-    % 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
-    ?_assertEqual(415,
-        begin
-            HttpHost = "http://" ++ Host,
-            AttUrl = string:join([HttpHost, DbName, ?docid(), "file.txt"], "/"),
-            {ok, Data} = file:read_file(?FIXTURE_TXT),
-            Headers = [
-                {"Content-Encoding", "compress"},
-                {"Content-Type", "text/plain"}
-            ],
-            {ok, Code, _, _} = test_request:put(AttUrl, Headers, Data),
-            Code
-        end).
-
-should_create_compressible_att_with_ctype_params({Host, DbName}) ->
-    {timeout, ?TIMEOUT_EUNIT, ?_test(begin
-        HttpHost = "http://" ++ Host,
-        DocUrl = string:join([HttpHost, DbName, ?docid()], "/"),
-        AttUrl = string:join([DocUrl, ?b2l(?ATT_TXT_NAME)], "/"),
-        {ok, Data} = file:read_file(?FIXTURE_TXT),
-        Headers = [{"Content-Type", "text/plain; charset=UTF-8"}],
-        {ok, Code0, _, _} = test_request:put(AttUrl, Headers, Data),
-        ?assertEqual(201, Code0),
-
-        {ok, Code1, _, Body} = test_request:get(
-            DocUrl ++ "?att_encoding_info=true"),
-        ?assertEqual(200, Code1),
-        Json = ejson:decode(Body),
-        {AttJson} = couch_util:get_nested_json_value(
-            Json, [<<"_attachments">>, ?ATT_TXT_NAME]),
-        ?assertEqual(<<"gzip">>,
-                     couch_util:get_value(<<"encoding">>, AttJson)),
-        AttEncLength = iolist_size(gzip(Data)),
-        ?assertEqual(AttEncLength,
-                     couch_util:get_value(<<"encoded_length">>, AttJson)),
-        ?assertEqual(byte_size(Data),
-                     couch_util:get_value(<<"length">>, AttJson))
-    end)}.
-
-
-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.
-
-chunked_body(Chunks) ->
-    chunked_body(Chunks, []).
-
-chunked_body([], Acc) ->
-    iolist_to_binary(lists:reverse(Acc, "0\r\n"));
-chunked_body([Chunk | Rest], Acc) ->
-    Size = to_hex(size(Chunk)),
-    chunked_body(Rest, ["\r\n", Chunk, "\r\n", Size | Acc]).
-
-get_socket() ->
-    Options = [binary, {packet, 0}, {active, false}],
-    Addr = couch_config:get("httpd", "bind_address", any),
-    Port = mochiweb_socket_server:get(couch_httpd, port),
-    {ok, Sock} = gen_tcp:connect(Addr, Port, Options),
-    Sock.
-
-request(Method, Url, Headers, Body) ->
-    RequestHead = [Method, " ", Url, " HTTP/1.1"],
-    RequestHeaders = [[string:join([Key, Value], ": "), "\r\n"]
-                      || {Key, Value} <- Headers],
-    Request = [RequestHead, "\r\n", RequestHeaders, "\r\n", Body, "\r\n"],
-    Sock = get_socket(),
-    gen_tcp:send(Sock, list_to_binary(lists:flatten(Request))),
-    timer:sleep(?TIMEWAIT),  % must wait to receive complete response
-    {ok, R} = gen_tcp:recv(Sock, 0),
-    gen_tcp:close(Sock),
-    [Header, Body1] = re:split(R, "\r\n\r\n", [{return, binary}]),
-    {ok, {http_response, _, Code, _}, _} =
-        erlang:decode_packet(http, Header, []),
-    Json = ejson:decode(Body1),
-    {ok, Code, Json}.
-
-create_standalone_text_att(Host, DbName) ->
-    {ok, Data} = file:read_file(?FIXTURE_TXT),
-    Url = string:join([Host, DbName, "doc", ?b2l(?ATT_TXT_NAME)], "/"),
-    {ok, Code, _Headers, _Body} = test_request:put(
-        Url, [{"Content-Type", "text/plain"}], Data),
-    ?assertEqual(201, Code),
-    Url.
-
-create_standalone_png_att(Host, DbName) ->
-    {ok, Data} = file:read_file(?FIXTURE_PNG),
-    Url = string:join([Host, DbName, "doc", ?b2l(?ATT_BIN_NAME)], "/"),
-    {ok, Code, _Headers, _Body} = test_request:put(
-        Url, [{"Content-Type", "image/png"}], Data),
-    ?assertEqual(201, Code),
-    Url.
-
-create_inline_text_att(Host, DbName) ->
-    {ok, Data} = file:read_file(?FIXTURE_TXT),
-    Url = string:join([Host, DbName, "doc"], "/"),
-    Doc = {[
-        {<<"_attachments">>, {[
-            {?ATT_TXT_NAME, {[
-                {<<"content_type">>, <<"text/plain">>},
-                {<<"data">>, base64:encode(Data)}
-            ]}
-        }]}}
-    ]},
-    {ok, Code, _Headers, _Body} = test_request:put(
-        Url, [{"Content-Type", "application/json"}], ejson:encode(Doc)),
-    ?assertEqual(201, Code),
-    string:join([Url, ?b2l(?ATT_TXT_NAME)], "/").
-
-create_inline_png_att(Host, DbName) ->
-    {ok, Data} = file:read_file(?FIXTURE_PNG),
-    Url = string:join([Host, DbName, "doc"], "/"),
-    Doc = {[
-        {<<"_attachments">>, {[
-            {?ATT_BIN_NAME, {[
-                {<<"content_type">>, <<"image/png">>},
-                {<<"data">>, base64:encode(Data)}
-            ]}
-        }]}}
-    ]},
-    {ok, Code, _Headers, _Body} = test_request:put(
-        Url, [{"Content-Type", "application/json"}], ejson:encode(Doc)),
-    ?assertEqual(201, Code),
-    string:join([Url, ?b2l(?ATT_BIN_NAME)], "/").
-
-create_already_compressed_att(Host, DbName) ->
-    {ok, Data} = file:read_file(?FIXTURE_TXT),
-    Url = string:join([Host, DbName, "doc", ?b2l(?ATT_TXT_NAME)], "/"),
-    {ok, Code, _Headers, _Body} = test_request:put(
-        Url, [{"Content-Type", "text/plain"}, {"Content-Encoding", "gzip"}],
-        zlib:gzip(Data)),
-    ?assertEqual(201, Code),
-    Url.
-
-gzip(Data) ->
-    Z = zlib:open(),
-    ok = zlib:deflateInit(Z, ?COMPRESSION_LEVEL, deflated, 16 + 15, 8, default),
-    zlib:deflate(Z, Data),
-    Last = zlib:deflate(Z, [], finish),
-    ok = zlib:deflateEnd(Z),
-    ok = zlib:close(Z),
-    Last.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couchdb_compaction_daemon.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_compaction_daemon.erl b/test/couchdb/couchdb_compaction_daemon.erl
deleted file mode 100644
index 725a97b..0000000
--- a/test/couchdb/couchdb_compaction_daemon.erl
+++ /dev/null
@@ -1,231 +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(couchdb_compaction_daemon).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
--define(DELAY, 100).
--define(TIMEOUT, 30000).
--define(TIMEOUT_S, ?TIMEOUT div 1000).
-
-
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    couch_config:set("compaction_daemon", "check_interval", "3", false),
-    couch_config:set("compaction_daemon", "min_file_size", "100000", false),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
-setup() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
-    create_design_doc(Db),
-    ok = couch_db:close(Db),
-    DbName.
-
-teardown(DbName) ->
-    Configs = couch_config:get("compactions"),
-    lists:foreach(
-        fun({Key, _}) ->
-            ok = couch_config:delete("compactions", Key, false)
-        end,
-        Configs),
-    couch_server:delete(DbName, [?ADMIN_USER]),
-    ok.
-
-
-compaction_daemon_test_() ->
-    {
-        "Compaction daemon tests",
-        {
-            setup,
-            fun start/0, fun stop/1,
-            {
-                foreach,
-                fun setup/0, fun teardown/1,
-                [
-                    fun should_compact_by_default_rule/1,
-                    fun should_compact_by_dbname_rule/1
-                ]
-            }
-        }
-    }.
-
-
-should_compact_by_default_rule(DbName) ->
-    {timeout, ?TIMEOUT_S, ?_test(begin
-        {ok, Db} = couch_db:open_int(DbName, []),
-        populate(DbName, 70, 70, 200 * 1024),
-
-        {_, DbFileSize} = get_db_frag(DbName),
-        {_, ViewFileSize} = get_view_frag(DbName),
-
-        ok = couch_config:set("compactions", "_default",
-            "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]",
-            false),
-
-        ok = timer:sleep(4000), % something >= check_interval
-        wait_compaction_finished(DbName),
-        ok = couch_config:delete("compactions", "_default", false),
-
-        {DbFrag2, DbFileSize2} = get_db_frag(DbName),
-        {ViewFrag2, ViewFileSize2} = get_view_frag(DbName),
-
-        ?assert(DbFrag2 < 70),
-        ?assert(ViewFrag2 < 70),
-
-        ?assert(DbFileSize > DbFileSize2),
-        ?assert(ViewFileSize > ViewFileSize2),
-
-        ?assert(couch_db:is_idle(Db)),
-        ok = couch_db:close(Db)
-    end)}.
-
-should_compact_by_dbname_rule(DbName) ->
-    {timeout, ?TIMEOUT_S, ?_test(begin
-        {ok, Db} = couch_db:open_int(DbName, []),
-        populate(DbName, 70, 70, 200 * 1024),
-
-        {_, DbFileSize} = get_db_frag(DbName),
-        {_, ViewFileSize} = get_view_frag(DbName),
-
-        ok = couch_config:set("compactions", ?b2l(DbName),
-            "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"70%\"}]",
-            false),
-
-        ok = timer:sleep(4000), % something >= check_interval
-        wait_compaction_finished(DbName),
-        ok = couch_config:delete("compactions", ?b2l(DbName), false),
-
-        {DbFrag2, DbFileSize2} = get_db_frag(DbName),
-        {ViewFrag2, ViewFileSize2} = get_view_frag(DbName),
-
-        ?assert(DbFrag2 < 70),
-        ?assert(ViewFrag2 < 70),
-
-        ?assert(DbFileSize > DbFileSize2),
-        ?assert(ViewFileSize > ViewFileSize2),
-
-        ?assert(couch_db:is_idle(Db)),
-        ok = couch_db:close(Db)
-    end)}.
-
-
-create_design_doc(Db) ->
-    DDoc = couch_doc:from_json_obj({[
-        {<<"_id">>, <<"_design/foo">>},
-        {<<"language">>, <<"javascript">>},
-        {<<"views">>, {[
-            {<<"foo">>, {[
-                {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>}
-            ]}},
-            {<<"foo2">>, {[
-                {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>}
-            ]}},
-            {<<"foo3">>, {[
-                {<<"map">>, <<"function(doc) { emit(doc._id, doc); }">>}
-            ]}}
-        ]}}
-    ]}),
-    {ok, _} = couch_db:update_docs(Db, [DDoc]),
-    {ok, _} = couch_db:ensure_full_commit(Db),
-    ok.
-
-populate(DbName, DbFrag, ViewFrag, MinFileSize) ->
-    {CurDbFrag, DbFileSize} = get_db_frag(DbName),
-    {CurViewFrag, ViewFileSize} = get_view_frag(DbName),
-    populate(DbName, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag,
-             lists:min([DbFileSize, ViewFileSize])).
-
-populate(_Db, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag, FileSize)
-    when CurDbFrag >= DbFrag, CurViewFrag >= ViewFrag, FileSize >= MinFileSize ->
-    ok;
-populate(DbName, DbFrag, ViewFrag, MinFileSize, _, _, _) ->
-    update(DbName),
-    {CurDbFrag, DbFileSize} = get_db_frag(DbName),
-    {CurViewFrag, ViewFileSize} = get_view_frag(DbName),
-    populate(DbName, DbFrag, ViewFrag, MinFileSize, CurDbFrag, CurViewFrag,
-             lists:min([DbFileSize, ViewFileSize])).
-
-update(DbName) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    lists:foreach(fun(_) ->
-        Doc = couch_doc:from_json_obj({[{<<"_id">>, couch_uuids:new()}]}),
-        {ok, _} = couch_db:update_docs(Db, [Doc]),
-        query_view(Db#db.name)
-    end, lists:seq(1, 200)),
-    couch_db:close(Db).
-
-db_url(DbName) ->
-    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
-    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
-    "http://" ++ Addr ++ ":" ++ Port ++ "/" ++ ?b2l(DbName).
-
-query_view(DbName) ->
-    {ok, Code, _Headers, _Body} = test_request:get(
-        db_url(DbName) ++ "/_design/foo/_view/foo"),
-    ?assertEqual(200, Code).
-
-get_db_frag(DbName) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    {ok, Info} = couch_db:get_db_info(Db),
-    couch_db:close(Db),
-    FileSize = couch_util:get_value(disk_size, Info),
-    DataSize = couch_util:get_value(data_size, Info),
-    {round((FileSize - DataSize) / FileSize * 100), FileSize}.
-
-get_view_frag(DbName) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    {ok, Info} = couch_mrview:get_info(Db, <<"_design/foo">>),
-    couch_db:close(Db),
-    FileSize = couch_util:get_value(disk_size, Info),
-    DataSize = couch_util:get_value(data_size, Info),
-    {round((FileSize - DataSize) / FileSize * 100), FileSize}.
-
-wait_compaction_finished(DbName) ->
-    Parent = self(),
-    Loop = spawn_link(fun() -> wait_loop(DbName, Parent) end),
-    receive
-        {done, Loop} ->
-            ok
-    after ?TIMEOUT ->
-        erlang:error(
-            {assertion_failed,
-             [{module, ?MODULE}, {line, ?LINE},
-              {reason, "Compaction timeout"}]})
-    end.
-
-wait_loop(DbName, Parent) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    {ok, DbInfo} = couch_db:get_db_info(Db),
-    {ok, ViewInfo} = couch_mrview:get_info(Db, <<"_design/foo">>),
-    couch_db:close(Db),
-    case (couch_util:get_value(compact_running, ViewInfo) =:= true) orelse
-        (couch_util:get_value(compact_running, DbInfo) =:= true) of
-        false ->
-            Parent ! {done, self()};
-        true ->
-            ok = timer:sleep(?DELAY),
-            wait_loop(DbName, Parent)
-    end.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couchdb_cors_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_cors_tests.erl b/test/couchdb/couchdb_cors_tests.erl
deleted file mode 100644
index 4e88ae7..0000000
--- a/test/couchdb/couchdb_cors_tests.erl
+++ /dev/null
@@ -1,344 +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(couchdb_cors_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
-
--define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
--define(SUPPORTED_METHODS,
-        "GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, COPY, OPTIONS").
--define(TIMEOUT, 1000).
-
-
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    ok = couch_config:set("httpd", "enable_cors", "true", false),
-    ok = couch_config:set("vhosts", "example.com", "/", false),
-    Pid.
-
-stop(Pid) ->
-    couch_server_sup:stop(),
-    erlang:monitor(process, Pid),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
-setup() ->
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
-    couch_db:close(Db),
-
-    couch_config:set("cors", "credentials", "false", false),
-    couch_config:set("cors", "origins", "http://example.com", false),
-
-    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
-    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
-    Host = "http://" ++ Addr ++ ":" ++ Port,
-    {Host, ?b2l(DbName)}.
-
-setup({Mod, VHost}) ->
-    {Host, DbName} = setup(),
-    Url = case Mod of
-        server ->
-            Host;
-        db ->
-            Host ++ "/" ++ DbName
-    end,
-    DefaultHeaders = [{"Origin", "http://example.com"}]
-                     ++ maybe_append_vhost(VHost),
-    {Host, DbName, Url, DefaultHeaders}.
-
-teardown(DbName) when is_list(DbName) ->
-    ok = couch_server:delete(?l2b(DbName), [?ADMIN_USER]),
-    ok;
-teardown({_, DbName}) ->
-    teardown(DbName).
-
-teardown(_, {_, DbName, _, _}) ->
-    teardown(DbName).
-
-
-cors_test_() ->
-    Funs = [
-        fun should_not_allow_origin/2,
-        fun should_not_allow_origin_with_port_mismatch/2,
-        fun should_not_allow_origin_with_scheme_mismatch/2,
-        fun should_not_all_origin_due_case_mismatch/2,
-        fun should_make_simple_request/2,
-        fun should_make_preflight_request/2,
-        fun should_make_prefligh_request_with_port/2,
-        fun should_make_prefligh_request_with_scheme/2,
-        fun should_make_prefligh_request_with_wildcard_origin/2,
-        fun should_make_request_with_credentials/2,
-        fun should_make_origin_request_with_auth/2,
-        fun should_make_preflight_request_with_auth/2
-    ],
-    {
-        "CORS (COUCHDB-431)",
-        {
-            setup,
-            fun start/0, fun stop/1,
-            [
-                cors_tests(Funs),
-                vhost_cors_tests(Funs),
-                headers_tests()
-            ]
-        }
-    }.
-
-headers_tests() ->
-    {
-        "Various headers tests",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                fun should_not_return_cors_headers_for_invalid_origin/1,
-                fun should_not_return_cors_headers_for_invalid_origin_preflight/1,
-                fun should_make_request_against_attachment/1,
-                fun should_make_range_request_against_attachment/1,
-                fun should_make_request_with_if_none_match_header/1
-            ]
-        }
-    }.
-
-cors_tests(Funs) ->
-    {
-        "CORS tests",
-        [
-            make_test_case(server, false, Funs),
-            make_test_case(db, false, Funs)
-        ]
-    }.
-
-vhost_cors_tests(Funs) ->
-    {
-        "Virtual Host CORS",
-        [
-            make_test_case(server, true, Funs),
-            make_test_case(db, true, Funs)
-        ]
-    }.
-
-make_test_case(Mod, UseVhost, Funs) ->
-    {
-        case Mod of server -> "Server"; db -> "Database" end,
-        {foreachx, fun setup/1, fun teardown/2, [{{Mod, UseVhost}, Fun}
-                                                 || Fun <- Funs]}
-    }.
-
-
-should_not_allow_origin(_, {_, _, Url, Headers0}) ->
-    ?_assertEqual(undefined,
-        begin
-            couch_config:delete("cors", "origins", false),
-            Headers1 = proplists:delete("Origin", Headers0),
-            Headers = [{"Origin", "http://127.0.0.1"}]
-                      ++ Headers1,
-            {ok, _, Resp, _} = test_request:get(Url, Headers),
-            proplists:get_value("Access-Control-Allow-Origin", Resp)
-        end).
-
-should_not_allow_origin_with_port_mismatch({_, VHost}, {_, _, Url, _}) ->
-    ?_assertEqual(undefined,
-        begin
-            Headers = [{"Origin", "http://example.com:5984"},
-                       {"Access-Control-Request-Method", "GET"}]
-                      ++ maybe_append_vhost(VHost),
-            {ok, _, Resp, _} = test_request:options(Url, Headers),
-            proplists:get_value("Access-Control-Allow-Origin", Resp)
-        end).
-
-should_not_allow_origin_with_scheme_mismatch({_, VHost}, {_, _, Url, _}) ->
-    ?_assertEqual(undefined,
-        begin
-            Headers = [{"Origin", "http://example.com:5984"},
-                       {"Access-Control-Request-Method", "GET"}]
-                      ++ maybe_append_vhost(VHost),
-            {ok, _, Resp, _} = test_request:options(Url, Headers),
-            proplists:get_value("Access-Control-Allow-Origin", Resp)
-        end).
-
-should_not_all_origin_due_case_mismatch({_, VHost}, {_, _, Url, _}) ->
-    ?_assertEqual(undefined,
-        begin
-            Headers = [{"Origin", "http://ExAmPlE.CoM"},
-                       {"Access-Control-Request-Method", "GET"}]
-                      ++ maybe_append_vhost(VHost),
-            {ok, _, Resp, _} = test_request:options(Url, Headers),
-            proplists:get_value("Access-Control-Allow-Origin", Resp)
-        end).
-
-should_make_simple_request(_, {_, _, Url, DefaultHeaders}) ->
-    ?_test(begin
-        {ok, _, Resp, _} = test_request:get(Url, DefaultHeaders),
-        ?assertEqual(
-            undefined,
-            proplists:get_value("Access-Control-Allow-Credentials", Resp)),
-        ?assertEqual(
-            "http://example.com",
-            proplists:get_value("Access-Control-Allow-Origin", Resp)),
-        ?assertEqual(
-            "Cache-Control, Content-Type, Server",
-            proplists:get_value("Access-Control-Expose-Headers", Resp))
-    end).
-
-should_make_preflight_request(_, {_, _, Url, DefaultHeaders}) ->
-    ?_assertEqual(?SUPPORTED_METHODS,
-        begin
-            Headers = DefaultHeaders
-                      ++ [{"Access-Control-Request-Method", "GET"}],
-            {ok, _, Resp, _} = test_request:options(Url, Headers),
-            proplists:get_value("Access-Control-Allow-Methods", Resp)
-        end).
-
-should_make_prefligh_request_with_port({_, VHost}, {_, _, Url, _}) ->
-    ?_assertEqual("http://example.com:5984",
-        begin
-            couch_config:set("cors", "origins", "http://example.com:5984",
-                             false),
-            Headers = [{"Origin", "http://example.com:5984"},
-                       {"Access-Control-Request-Method", "GET"}]
-                      ++ maybe_append_vhost(VHost),
-            {ok, _, Resp, _} = test_request:options(Url, Headers),
-            proplists:get_value("Access-Control-Allow-Origin", Resp)
-        end).
-
-should_make_prefligh_request_with_scheme({_, VHost}, {_, _, Url, _}) ->
-    ?_assertEqual("https://example.com:5984",
-        begin
-            couch_config:set("cors", "origins", "https://example.com:5984",
-                             false),
-            Headers = [{"Origin", "https://example.com:5984"},
-                       {"Access-Control-Request-Method", "GET"}]
-                      ++ maybe_append_vhost(VHost),
-            {ok, _, Resp, _} = test_request:options(Url, Headers),
-            proplists:get_value("Access-Control-Allow-Origin", Resp)
-        end).
-
-should_make_prefligh_request_with_wildcard_origin({_, VHost}, {_, _, Url, _}) ->
-    ?_assertEqual("https://example.com:5984",
-        begin
-            couch_config:set("cors", "origins", "*", false),
-            Headers = [{"Origin", "https://example.com:5984"},
-                       {"Access-Control-Request-Method", "GET"}]
-                      ++ maybe_append_vhost(VHost),
-            {ok, _, Resp, _} = test_request:options(Url, Headers),
-            proplists:get_value("Access-Control-Allow-Origin", Resp)
-        end).
-
-should_make_request_with_credentials(_, {_, _, Url, DefaultHeaders}) ->
-    ?_assertEqual("true",
-        begin
-            ok = couch_config:set("cors", "credentials", "true", false),
-            {ok, _, Resp, _} = test_request:options(Url, DefaultHeaders),
-            proplists:get_value("Access-Control-Allow-Credentials", Resp)
-        end).
-
-should_make_origin_request_with_auth(_, {_, _, Url, DefaultHeaders}) ->
-    ?_assertEqual("http://example.com",
-        begin
-            Hashed = couch_passwords:hash_admin_password(<<"test">>),
-            couch_config:set("admins", "test", Hashed, false),
-            {ok, _, Resp, _} = test_request:get(
-                Url, DefaultHeaders, [{basic_auth, {"test", "test"}}]),
-            couch_config:delete("admins", "test", false),
-            proplists:get_value("Access-Control-Allow-Origin", Resp)
-        end).
-
-should_make_preflight_request_with_auth(_, {_, _, Url, DefaultHeaders}) ->
-    ?_assertEqual(?SUPPORTED_METHODS,
-        begin
-            Hashed = couch_passwords:hash_admin_password(<<"test">>),
-            couch_config:set("admins", "test", Hashed, false),
-            Headers = DefaultHeaders
-                      ++ [{"Access-Control-Request-Method", "GET"}],
-            {ok, _, Resp, _} = test_request:options(
-                Url, Headers, [{basic_auth, {"test", "test"}}]),
-            couch_config:delete("admins", "test", false),
-            proplists:get_value("Access-Control-Allow-Methods", Resp)
-        end).
-
-should_not_return_cors_headers_for_invalid_origin({Host, _}) ->
-    ?_assertEqual(undefined,
-        begin
-            Headers = [{"Origin", "http://127.0.0.1"}],
-            {ok, _, Resp, _} = test_request:get(Host, Headers),
-            proplists:get_value("Access-Control-Allow-Origin", Resp)
-        end).
-
-should_not_return_cors_headers_for_invalid_origin_preflight({Host, _}) ->
-    ?_assertEqual(undefined,
-        begin
-            Headers = [{"Origin", "http://127.0.0.1"},
-                       {"Access-Control-Request-Method", "GET"}],
-            {ok, _, Resp, _} = test_request:options(Host, Headers),
-            proplists:get_value("Access-Control-Allow-Origin", Resp)
-        end).
-
-should_make_request_against_attachment({Host, DbName}) ->
-    {"COUCHDB-1689",
-     ?_assertEqual(200,
-         begin
-             Url = Host ++ "/" ++ DbName,
-             {ok, Code0, _, _} = test_request:put(
-                 Url ++ "/doc/file.txt", [{"Content-Type", "text/plain"}],
-                 "hello, couch!"),
-             ?assert(Code0 =:= 201),
-             {ok, Code, _, _} = test_request:get(
-                 Url ++ "/doc?attachments=true",
-                 [{"Origin", "http://example.com"}]),
-             Code
-         end)}.
-
-should_make_range_request_against_attachment({Host, DbName}) ->
-    {"COUCHDB-1689",
-     ?_assertEqual(206,
-         begin
-             Url = Host ++ "/" ++ DbName,
-             {ok, Code0, _, _} = test_request:put(
-                 Url ++ "/doc/file.txt",
-                 [{"Content-Type", "application/octet-stream"}],
-                 "hello, couch!"),
-             ?assert(Code0 =:= 201),
-             {ok, Code, _, _} = test_request:get(
-                 Url ++ "/doc/file.txt", [{"Origin", "http://example.com"},
-                                          {"Range", "bytes=0-6"}]),
-             Code
-         end)}.
-
-should_make_request_with_if_none_match_header({Host, DbName}) ->
-    {"COUCHDB-1697",
-     ?_assertEqual(304,
-         begin
-             Url = Host ++ "/" ++ DbName,
-             {ok, Code0, Headers0, _} = test_request:put(
-                 Url ++ "/doc", [{"Content-Type", "application/json"}], "{}"),
-             ?assert(Code0 =:= 201),
-             ETag = proplists:get_value("ETag", Headers0),
-             {ok, Code, _, _} = test_request:get(
-                 Url ++ "/doc", [{"Origin", "http://example.com"},
-                                 {"If-None-Match", ETag}]),
-             Code
-        end)}.
-
-
-maybe_append_vhost(true) ->
-    [{"Host", "http://example.com"}];
-maybe_append_vhost(false) ->
-    [].

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couchdb_csp_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_csp_tests.erl b/test/couchdb/couchdb_csp_tests.erl
deleted file mode 100644
index adb0e6d..0000000
--- a/test/couchdb/couchdb_csp_tests.erl
+++ /dev/null
@@ -1,96 +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(couchdb_csp_tests).
-
--include("couch_eunit.hrl").
-
--define(TIMEOUT, 1000).
-
-
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    Pid.
-
-stop(Pid) ->
-    couch_server_sup:stop(),
-    erlang:monitor(process, Pid),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
-setup() ->
-    ok = couch_config:set("csp", "enable", "true", false),
-    Addr = couch_config:get("httpd", "bind_address", "127.0.0.1"),
-    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
-    lists:concat(["http://", Addr, ":", Port, "/_utils/"]).
-
-teardown(_) ->
-    ok.
-
-
-csp_test_() ->
-    {
-        "Content Security Policy tests",
-        {
-            setup,
-            fun start/0, fun stop/1,
-            {
-                foreach,
-                fun setup/0, fun teardown/1,
-                [
-                    fun should_not_return_any_csp_headers_when_disabled/1,
-                    fun should_apply_default_policy/1,
-                    fun should_return_custom_policy/1,
-                    fun should_only_enable_csp_when_true/1
-                ]
-            }
-        }
-    }.
-
-
-should_not_return_any_csp_headers_when_disabled(Url) ->
-    ?_assertEqual(undefined,
-        begin
-            ok = couch_config:set("csp", "enable", "false", false),
-            {ok, _, Headers, _} = test_request:get(Url),
-            proplists:get_value("Content-Security-Policy", Headers)
-        end).
-
-should_apply_default_policy(Url) ->
-    ?_assertEqual(
-        "default-src 'self'; img-src 'self'; font-src 'self'; "
-        "script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline';",
-        begin
-            {ok, _, Headers, _} = test_request:get(Url),
-            proplists:get_value("Content-Security-Policy", Headers)
-        end).
-
-should_return_custom_policy(Url) ->
-    ?_assertEqual("default-src 'http://example.com';",
-        begin
-            ok = couch_config:set("csp", "header_value",
-                                  "default-src 'http://example.com';", false),
-            {ok, _, Headers, _} = test_request:get(Url),
-            proplists:get_value("Content-Security-Policy", Headers)
-        end).
-
-should_only_enable_csp_when_true(Url) ->
-    ?_assertEqual(undefined,
-        begin
-            ok = couch_config:set("csp", "enable", "tru", false),
-            {ok, _, Headers, _} = test_request:get(Url),
-            proplists:get_value("Content-Security-Policy", Headers)
-        end).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couchdb_file_compression_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_file_compression_tests.erl b/test/couchdb/couchdb_file_compression_tests.erl
deleted file mode 100644
index fd3f513..0000000
--- a/test/couchdb/couchdb_file_compression_tests.erl
+++ /dev/null
@@ -1,239 +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(couchdb_file_compression_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
--define(DDOC_ID, <<"_design/test">>).
--define(DOCS_COUNT, 5000).
--define(TIMEOUT, 30000).
-
-
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    Pid.
-
-stop(Pid) ->
-    erlang:monitor(process, Pid),
-    couch_server_sup:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
-setup() ->
-    couch_config:set("couchdb", "file_compression", "none", false),
-    DbName = ?tempdb(),
-    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
-    ok = populate_db(Db, ?DOCS_COUNT),
-    DDoc = couch_doc:from_json_obj({[
-        {<<"_id">>, ?DDOC_ID},
-        {<<"language">>, <<"javascript">>},
-        {<<"views">>, {[
-                {<<"by_id">>, {[
-                    {<<"map">>, <<"function(doc){emit(doc._id, doc.string);}">>}
-                ]}}
-            ]}
-        }
-    ]}),
-    {ok, _} = couch_db:update_doc(Db, DDoc, []),
-    refresh_index(DbName),
-    ok = couch_db:close(Db),
-    DbName.
-
-teardown(DbName) ->
-    ok = couch_server:delete(DbName, [?ADMIN_USER]),
-    ok.
-
-
-couch_auth_cache_test_() ->
-    {
-        "CouchDB file compression tests",
-        {
-            setup,
-            fun start/0, fun stop/1,
-            {
-                foreach,
-                fun setup/0, fun teardown/1,
-                [
-                    fun should_use_none/1,
-                    fun should_use_deflate_1/1,
-                    fun should_use_deflate_9/1,
-                    fun should_use_snappy/1,
-                    fun should_compare_compression_methods/1
-                ]
-            }
-        }
-    }.
-
-
-should_use_none(DbName) ->
-    couch_config:set("couchdb", "file_compression", "none", false),
-    {
-        "Use no compression",
-        [
-            {"compact database", ?_test(compact_db(DbName))},
-            {"compact view", ?_test(compact_view(DbName))}
-        ]
-    }.
-
-should_use_deflate_1(DbName) ->
-    couch_config:set("couchdb", "file_compression", "deflate_1", false),
-    {
-        "Use deflate compression at level 1",
-        [
-            {"compact database", ?_test(compact_db(DbName))},
-            {"compact view", ?_test(compact_view(DbName))}
-        ]
-    }.
-
-should_use_deflate_9(DbName) ->
-    couch_config:set("couchdb", "file_compression", "deflate_9", false),
-    {
-        "Use deflate compression at level 9",
-        [
-            {"compact database", ?_test(compact_db(DbName))},
-            {"compact view", ?_test(compact_view(DbName))}
-        ]
-    }.
-
-should_use_snappy(DbName) ->
-    couch_config:set("couchdb", "file_compression", "snappy", false),
-    {
-        "Use snappy compression",
-        [
-            {"compact database", ?_test(compact_db(DbName))},
-            {"compact view", ?_test(compact_view(DbName))}
-        ]
-    }.
-
-should_compare_compression_methods(DbName) ->
-    {"none > snappy > deflate_1 > deflate_9",
-     {timeout, ?TIMEOUT div 1000, ?_test(compare_compression_methods(DbName))}}.
-
-compare_compression_methods(DbName) ->
-    couch_config:set("couchdb", "file_compression", "none", false),
-    compact_db(DbName),
-    compact_view(DbName),
-    DbSizeNone = db_disk_size(DbName),
-    ViewSizeNone = view_disk_size(DbName),
-
-    couch_config:set("couchdb", "file_compression", "snappy", false),
-    compact_db(DbName),
-    compact_view(DbName),
-    DbSizeSnappy = db_disk_size(DbName),
-    ViewSizeSnappy = view_disk_size(DbName),
-
-    ?assert(DbSizeNone > DbSizeSnappy),
-    ?assert(ViewSizeNone > ViewSizeSnappy),
-
-    couch_config:set("couchdb", "file_compression", "deflate_1", false),
-    compact_db(DbName),
-    compact_view(DbName),
-    DbSizeDeflate1 = db_disk_size(DbName),
-    ViewSizeDeflate1 = view_disk_size(DbName),
-
-    ?assert(DbSizeSnappy > DbSizeDeflate1),
-    ?assert(ViewSizeSnappy > ViewSizeDeflate1),
-
-    couch_config:set("couchdb", "file_compression", "deflate_9", false),
-    compact_db(DbName),
-    compact_view(DbName),
-    DbSizeDeflate9 = db_disk_size(DbName),
-    ViewSizeDeflate9 = view_disk_size(DbName),
-
-    ?assert(DbSizeDeflate1 > DbSizeDeflate9),
-    ?assert(ViewSizeDeflate1 > ViewSizeDeflate9).
-
-
-populate_db(_Db, NumDocs) when NumDocs =< 0 ->
-    ok;
-populate_db(Db, NumDocs) ->
-    Docs = lists:map(
-        fun(_) ->
-            couch_doc:from_json_obj({[
-                {<<"_id">>, couch_uuids:random()},
-                {<<"string">>, ?l2b(lists:duplicate(1000, $X))}
-            ]})
-        end,
-        lists:seq(1, 500)),
-    {ok, _} = couch_db:update_docs(Db, Docs, []),
-    populate_db(Db, NumDocs - 500).
-
-refresh_index(DbName) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    {ok, DDoc} = couch_db:open_doc(Db, ?DDOC_ID, [ejson_body]),
-    couch_mrview:query_view(Db, DDoc, <<"by_id">>, [{stale, false}]),
-    ok = couch_db:close(Db).
-
-compact_db(DbName) ->
-    DiskSizeBefore = db_disk_size(DbName),
-    {ok, Db} = couch_db:open_int(DbName, []),
-    {ok, CompactPid} = couch_db:start_compact(Db),
-    MonRef = erlang:monitor(process, CompactPid),
-    receive
-        {'DOWN', MonRef, process, CompactPid, normal} ->
-            ok;
-        {'DOWN', MonRef, process, CompactPid, Reason} ->
-            erlang:error({assertion_failed,
-                          [{module, ?MODULE},
-                           {line, ?LINE},
-                           {reason, "Error compacting database: "
-                                    ++ couch_util:to_list(Reason)}]})
-    after ?TIMEOUT ->
-        erlang:error({assertion_failed,
-                      [{module, ?MODULE},
-                       {line, ?LINE},
-                       {reason, "Timeout waiting for database compaction"}]})
-    end,
-    ok = couch_db:close(Db),
-    DiskSizeAfter = db_disk_size(DbName),
-    ?assert(DiskSizeBefore > DiskSizeAfter).
-
-compact_view(DbName) ->
-    DiskSizeBefore = view_disk_size(DbName),
-    {ok, MonRef} = couch_mrview:compact(DbName, ?DDOC_ID, [monitor]),
-    receive
-        {'DOWN', MonRef, process, _CompactPid, normal} ->
-            ok;
-        {'DOWN', MonRef, process, _CompactPid, Reason} ->
-            erlang:error({assertion_failed,
-                          [{module, ?MODULE},
-                           {line, ?LINE},
-                           {reason, "Error compacting view group: "
-                                    ++ couch_util:to_list(Reason)}]})
-    after ?TIMEOUT ->
-        erlang:error({assertion_failed,
-                      [{module, ?MODULE},
-                       {line, ?LINE},
-                       {reason, "Timeout waiting for view group compaction"}]})
-    end,
-    DiskSizeAfter = view_disk_size(DbName),
-    ?assert(DiskSizeBefore > DiskSizeAfter).
-
-db_disk_size(DbName) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    {ok, Info} = couch_db:get_db_info(Db),
-    ok = couch_db:close(Db),
-    couch_util:get_value(disk_size, Info).
-
-view_disk_size(DbName) ->
-    {ok, Db} = couch_db:open_int(DbName, []),
-    {ok, DDoc} = couch_db:open_doc(Db, ?DDOC_ID, [ejson_body]),
-    {ok, Info} = couch_mrview:get_info(Db, DDoc),
-    ok = couch_db:close(Db),
-    couch_util:get_value(disk_size, Info).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couchdb_http_proxy_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_http_proxy_tests.erl b/test/couchdb/couchdb_http_proxy_tests.erl
deleted file mode 100644
index acb1974..0000000
--- a/test/couchdb/couchdb_http_proxy_tests.erl
+++ /dev/null
@@ -1,462 +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(couchdb_http_proxy_tests).
-
--include("couch_eunit.hrl").
-
--record(req, {method=get, path="", headers=[], body="", opts=[]}).
-
--define(CONFIG_FIXTURE_TEMP,
-    begin
-        FileName = filename:join([?TEMPDIR, ?tempfile() ++ ".ini"]),
-        {ok, Fd} = file:open(FileName, write),
-        ok = file:truncate(Fd),
-        ok = file:close(Fd),
-        FileName
-    end).
--define(TIMEOUT, 5000).
-
-
-start() ->
-    % we have to write any config changes to temp ini file to not loose them
-    % when supervisor will kill all children due to reaching restart threshold
-    % (each httpd_global_handlers changes causes couch_httpd restart)
-    couch_server_sup:start_link(?CONFIG_CHAIN ++ [?CONFIG_FIXTURE_TEMP]),
-    % 49151 is IANA Reserved, let's assume no one is listening there
-    couch_config:set("httpd_global_handlers", "_error",
-        "{couch_httpd_proxy, handle_proxy_req, <<\"http://127.0.0.1:49151/\">>}"
-    ),
-    ok.
-
-stop(_) ->
-    couch_server_sup:stop(),
-    ok.
-
-setup() ->
-    {ok, Pid} = test_web:start_link(),
-    Value = lists:flatten(io_lib:format(
-        "{couch_httpd_proxy, handle_proxy_req, ~p}",
-        [list_to_binary(proxy_url())])),
-    couch_config:set("httpd_global_handlers", "_test", Value),
-    % let couch_httpd restart
-    timer:sleep(100),
-    Pid.
-
-teardown(Pid) ->
-    erlang:monitor(process, Pid),
-    test_web:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, test_web_stop})
-    end.
-
-
-http_proxy_test_() ->
-    {
-        "HTTP Proxy handler tests",
-        {
-            setup,
-            fun start/0, fun stop/1,
-            {
-                foreach,
-                fun setup/0, fun teardown/1,
-                [
-                    fun should_proxy_basic_request/1,
-                    fun should_return_alternative_status/1,
-                    fun should_respect_trailing_slash/1,
-                    fun should_proxy_headers/1,
-                    fun should_proxy_host_header/1,
-                    fun should_pass_headers_back/1,
-                    fun should_use_same_protocol_version/1,
-                    fun should_proxy_body/1,
-                    fun should_proxy_body_back/1,
-                    fun should_proxy_chunked_body/1,
-                    fun should_proxy_chunked_body_back/1,
-                    fun should_rewrite_location_header/1,
-                    fun should_not_rewrite_external_locations/1,
-                    fun should_rewrite_relative_location/1,
-                    fun should_refuse_connection_to_backend/1
-                ]
-            }
-
-        }
-    }.
-
-
-should_proxy_basic_request(_) ->
-    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,
-    ?_test(check_request(#req{}, Remote, Local)).
-
-should_return_alternative_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"},
-    ?_test(check_request(Req, Remote, Local)).
-
-should_respect_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/"},
-    ?_test(check_request(Req, Remote, Local)).
-
-should_proxy_headers(_) ->
-    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"}]
-    },
-    ?_test(check_request(Req, Remote, Local)).
-
-should_proxy_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"}]
-    },
-    ?_test(check_request(Req, Remote, Local)).
-
-should_pass_headers_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"},
-    ?_test(check_request(Req, Remote, Local)).
-
-should_use_same_protocol_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}}]
-    },
-    ?_test(check_request(Req, Remote, Local)).
-
-should_proxy_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!"
-    },
-    ?_test(check_request(Req, Remote, Local)).
-
-should_proxy_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"},
-    ?_test(check_request(Req, Remote, Local)).
-
-should_proxy_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=chunked_body(BodyChunks)
-    },
-    ?_test(check_request(Req, Remote, Local)).
-
-should_proxy_chunked_body_back(_) ->
-    ?_test(begin
-        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(Req, Remote, no_local),
-        ?assertMatch({ibrowse_req_id, _}, Resp),
-        {_, ReqId} = Resp,
-
-        % Grab headers from response
-        receive
-            {ibrowse_async_headers, ReqId, "200", Headers} ->
-                ?assertEqual("chunked",
-                             proplists:get_value("Transfer-Encoding", Headers)),
-            ibrowse:stream_next(ReqId)
-        after 1000 ->
-            throw({error, timeout})
-        end,
-
-        ?assertEqual(<<"foobarbazinga">>, recv_body(ReqId, [])),
-        ?assertEqual(was_ok, test_web:check_last())
-    end).
-
-should_refuse_connection_to_backend(_) ->
-    Local = fun
-        ({ok, "500", _, _}) ->
-            true;
-        (_) ->
-            false
-    end,
-    Req = #req{opts=[{url, server_url("/_error")}]},
-    ?_test(check_request(Req, no_remote, Local)).
-
-should_rewrite_location_header(_) ->
-    {
-        "Testing location header rewrites",
-        do_rewrite_tests([
-            {"Location", proxy_url() ++ "/foo/bar",
-                         server_url() ++ "/foo/bar"},
-            {"Content-Location", proxy_url() ++ "/bing?q=2",
-                                 server_url() ++ "/bing?q=2"},
-            {"Uri", proxy_url() ++ "/zip#frag",
-                    server_url() ++ "/zip#frag"},
-            {"Destination", proxy_url(),
-                            server_url() ++ "/"}
-        ])
-    }.
-
-should_not_rewrite_external_locations(_) ->
-    {
-        "Testing no rewrite of external locations",
-        do_rewrite_tests([
-            {"Location", external_url() ++ "/search",
-                         external_url() ++ "/search"},
-            {"Content-Location", external_url() ++ "/s?q=2",
-                                 external_url() ++ "/s?q=2"},
-            {"Uri", external_url() ++ "/f#f",
-                    external_url() ++ "/f#f"},
-            {"Destination", external_url() ++ "/f?q=2#f",
-                            external_url() ++ "/f?q=2#f"}
-        ])
-    }.
-
-should_rewrite_relative_location(_) ->
-    {
-        "Testing relative rewrites",
-        do_rewrite_tests([
-            {"Location", "/foo",
-                         server_url() ++ "/foo"},
-            {"Content-Location", "bar",
-                                 server_url() ++ "/bar"},
-            {"Uri", "/zing?q=3",
-                    server_url() ++ "/zing?q=3"},
-            {"Destination", "bing?q=stuff#yay",
-                            server_url() ++ "/bing?q=stuff#yay"}
-        ])
-    }.
-
-
-do_rewrite_tests(Tests) ->
-    lists:map(fun({Header, Location, Url}) ->
-        should_rewrite_header(Header, Location, Url)
-    end, Tests).
-
-should_rewrite_header(Header, Location, Url) ->
-    Remote = fun(Req) ->
-        "/rewrite_test" = Req:get(path),
-        {ok, {302, [{Header, Location}], "ok"}}
-    end,
-    Local = fun
-        ({ok, "302", Headers, "ok"}) ->
-            ?assertEqual(Url, couch_util:get_value(Header, Headers)),
-            true;
-        (E) ->
-            ?debugFmt("~p", [E]),
-            false
-    end,
-    Req = #req{path="/rewrite_test"},
-    {Header, ?_test(check_request(Req, Remote, Local))}.
-
-
-server_url() ->
-    server_url("/_test").
-
-server_url(Resource) ->
-    Addr = couch_config:get("httpd", "bind_address"),
-    Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
-    lists:concat(["http://", Addr, ":", Port, Resource]).
-
-proxy_url() ->
-    "http://127.0.0.1:" ++ integer_to_list(test_web:get_port()).
-
-external_url() ->
-    "https://google.com".
-
-check_request(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_url() ++ 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
-    ),
-    %?debugFmt("ibrowse response: ~p", [Resp]),
-    case Local of
-        no_local ->
-            ok;
-        _ ->
-            ?assert(Local(Resp))
-    end,
-    case {Remote, Local} of
-        {no_remote, _} ->
-            ok;
-        {_, no_local} ->
-            ok;
-        _ ->
-            ?assertEqual(was_ok, test_web:check_last())
-    end,
-    Resp.
-
-chunked_body(Chunks) ->
-    chunked_body(Chunks, []).
-
-chunked_body([], Acc) ->
-    iolist_to_binary(lists:reverse(Acc, "0\r\n\r\n"));
-chunked_body([Chunk | Rest], Acc) ->
-    Size = to_hex(size(Chunk)),
-    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 ?TIMEOUT ->
-        throw({error, timeout})
-    end.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couchdb_modules_load_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_modules_load_tests.erl b/test/couchdb/couchdb_modules_load_tests.erl
deleted file mode 100644
index 4eaa42b..0000000
--- a/test/couchdb/couchdb_modules_load_tests.erl
+++ /dev/null
@@ -1,68 +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(couchdb_modules_load_tests).
-
--include("couch_eunit.hrl").
-
-
-modules_load_test_() ->
-    {
-        "Verify that all modules loads",
-        should_load_modules()
-    }.
-
-
-should_load_modules() ->
-    Modules = [
-        couch_auth_cache,
-        couch_btree,
-        couch_changes,
-        couch_compress,
-        couch_config,
-        couch_config_writer,
-        couch_db,
-        couch_db_update_notifier,
-        couch_db_update_notifier_sup,
-        couch_db_updater,
-        couch_doc,
-        % Fails unless couch_config gen_server is started.
-        % couch_ejson_compare,
-        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_rewrite,
-        couch_httpd_stats_handlers,
-        couch_key_tree,
-        couch_log,
-        couch_os_process,
-        couch_query_servers,
-        couch_ref_counter,
-        couch_server,
-        couch_server_sup,
-        couch_stats_aggregator,
-        couch_stats_collector,
-        couch_stream,
-        couch_task_status,
-        couch_util,
-        couch_work_queue,
-        json_stream_parse
-    ],
-    [should_load_module(Mod) || Mod <- Modules].
-
-should_load_module(Mod) ->
-    {atom_to_list(Mod), ?_assertMatch({module, _}, code:load_file(Mod))}.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couchdb_os_daemons_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_os_daemons_tests.erl b/test/couchdb/couchdb_os_daemons_tests.erl
deleted file mode 100644
index aa949c9..0000000
--- a/test/couchdb/couchdb_os_daemons_tests.erl
+++ /dev/null
@@ -1,228 +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(couchdb_os_daemons_tests).
-
--include("couch_eunit.hrl").
-
-%% keep in sync with couchdb/couch_os_daemons.erl
--record(daemon, {
-    port,
-    name,
-    cmd,
-    kill,
-    status=running,
-    cfg_patterns=[],
-    errors=[],
-    buf=[]
-}).
-
--define(DAEMON_CONFIGER, "os_daemon_configer.escript").
--define(DAEMON_LOOPER, "os_daemon_looper.escript").
--define(DAEMON_BAD_PERM, "os_daemon_bad_perm.sh").
--define(DAEMON_CAN_REBOOT, "os_daemon_can_reboot.sh").
--define(DAEMON_DIE_ON_BOOT, "os_daemon_die_on_boot.sh").
--define(DAEMON_DIE_QUICKLY, "os_daemon_die_quickly.sh").
--define(DELAY, 100).
--define(TIMEOUT, 1000).
-
-
-setup(DName) ->
-    {ok, CfgPid} = couch_config:start_link(?CONFIG_CHAIN),
-    {ok, OsDPid} = couch_os_daemons:start_link(),
-    couch_config:set("os_daemons", DName,
-                     filename:join([?FIXTURESDIR, DName]), false),
-    timer:sleep(?DELAY),  % sleep a bit to let daemon set kill flag
-    {CfgPid, OsDPid}.
-
-teardown(_, {CfgPid, OsDPid}) ->
-    erlang:monitor(process, CfgPid),
-    couch_config:stop(),
-    receive
-        {'DOWN', _, _, CfgPid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, config_stop})
-    end,
-
-    erlang:monitor(process, OsDPid),
-    exit(OsDPid, normal),
-    receive
-        {'DOWN', _, _, OsDPid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, os_daemon_stop})
-    end.
-
-
-os_daemons_test_() ->
-    {
-        "OS Daemons tests",
-        {
-            foreachx,
-            fun setup/1, fun teardown/2,
-            [{?DAEMON_LOOPER, Fun} || Fun <- [
-                fun should_check_daemon/2,
-                fun should_check_daemon_table_form/2,
-                fun should_clean_tables_on_daemon_remove/2,
-                fun should_spawn_multiple_daemons/2,
-                fun should_keep_alive_one_daemon_on_killing_other/2
-            ]]
-        }
-    }.
-
-configuration_reader_test_() ->
-    {
-        "OS Daemon requests CouchDB configuration",
-        {
-            foreachx,
-            fun setup/1, fun teardown/2,
-            [{?DAEMON_CONFIGER,
-              fun should_read_write_config_settings_by_daemon/2}]
-
-        }
-    }.
-
-error_test_() ->
-    {
-        "OS Daemon process error tests",
-        {
-            foreachx,
-            fun setup/1, fun teardown/2,
-            [{?DAEMON_BAD_PERM, fun should_fail_due_to_lack_of_permissions/2},
-             {?DAEMON_DIE_ON_BOOT, fun should_die_on_boot/2},
-             {?DAEMON_DIE_QUICKLY, fun should_die_quickly/2},
-             {?DAEMON_CAN_REBOOT, fun should_not_being_halted/2}]
-        }
-    }.
-
-
-should_check_daemon(DName, _) ->
-    ?_test(begin
-        {ok, [D]} = couch_os_daemons:info([table]),
-        check_daemon(D, DName)
-    end).
-
-should_check_daemon_table_form(DName, _) ->
-    ?_test(begin
-        {ok, Tab} = couch_os_daemons:info(),
-        [D] = ets:tab2list(Tab),
-        check_daemon(D, DName)
-    end).
-
-should_clean_tables_on_daemon_remove(DName, _) ->
-    ?_test(begin
-        couch_config:delete("os_daemons", DName, false),
-        {ok, Tab2} = couch_os_daemons:info(),
-        ?_assertEqual([], ets:tab2list(Tab2))
-    end).
-
-should_spawn_multiple_daemons(DName, _) ->
-    ?_test(begin
-        couch_config:set("os_daemons", "bar",
-                         filename:join([?FIXTURESDIR, DName]), false),
-        couch_config:set("os_daemons", "baz",
-                         filename:join([?FIXTURESDIR, DName]), false),
-        timer:sleep(?DELAY),
-        {ok, Daemons} = couch_os_daemons:info([table]),
-        lists:foreach(fun(D) ->
-            check_daemon(D)
-        end, Daemons),
-        {ok, Tab} = couch_os_daemons:info(),
-        lists:foreach(fun(D) ->
-            check_daemon(D)
-        end, ets:tab2list(Tab))
-    end).
-
-should_keep_alive_one_daemon_on_killing_other(DName, _) ->
-    ?_test(begin
-        couch_config:set("os_daemons", "bar",
-                         filename:join([?FIXTURESDIR, DName]), false),
-        timer:sleep(?DELAY),
-        {ok, Daemons} = couch_os_daemons:info([table]),
-        lists:foreach(fun(D) ->
-            check_daemon(D)
-        end, Daemons),
-
-        couch_config:delete("os_daemons", "bar", false),
-        timer:sleep(?DELAY),
-        {ok, [D2]} = couch_os_daemons:info([table]),
-        check_daemon(D2, DName),
-
-        {ok, Tab} = couch_os_daemons:info(),
-        [T] = ets:tab2list(Tab),
-        check_daemon(T, DName)
-    end).
-
-should_read_write_config_settings_by_daemon(DName, _) ->
-    ?_test(begin
-        % have to wait till daemon run all his tests
-        % see daemon's script for more info
-        timer:sleep(?TIMEOUT),
-        {ok, [D]} = couch_os_daemons:info([table]),
-        check_daemon(D, DName)
-    end).
-
-should_fail_due_to_lack_of_permissions(DName, _) ->
-    ?_test(should_halts(DName, 1000)).
-
-should_die_on_boot(DName, _) ->
-    ?_test(should_halts(DName, 1000)).
-
-should_die_quickly(DName, _) ->
-    ?_test(should_halts(DName, 4000)).
-
-should_not_being_halted(DName, _) ->
-    ?_test(begin
-        timer:sleep(1000),
-        {ok, [D1]} = couch_os_daemons:info([table]),
-        check_daemon(D1, DName, 0),
-
-        % Should reboot every two seconds. We're at 1s, so wait
-        % until 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, DName, 1),
-
-        % If the kill command changed, that means we rebooted the process.
-        ?assertNotEqual(D1#daemon.kill, D2#daemon.kill)
-    end).
-
-should_halts(DName, Time) ->
-    timer:sleep(Time),
-    {ok, [D]} = couch_os_daemons:info([table]),
-    check_dead(D, DName),
-    couch_config:delete("os_daemons", DName, false).
-
-check_daemon(D) ->
-    check_daemon(D, D#daemon.name).
-
-check_daemon(D, Name) ->
-    check_daemon(D, Name, 0).
-
-check_daemon(D, Name, Errs) ->
-    ?assert(is_port(D#daemon.port)),
-    ?assertEqual(Name, D#daemon.name),
-    ?assertNotEqual(undefined, D#daemon.kill),
-    ?assertEqual(running, D#daemon.status),
-    ?assertEqual(Errs, length(D#daemon.errors)),
-    ?assertEqual([], D#daemon.buf).
-
-check_dead(D, Name) ->
-    ?assert(is_port(D#daemon.port)),
-    ?assertEqual(Name, D#daemon.name),
-    ?assertNotEqual(undefined, D#daemon.kill),
-    ?assertEqual(halted, D#daemon.status),
-    ?assertEqual(nil, D#daemon.errors),
-    ?assertEqual(nil, D#daemon.buf).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couchdb_os_proc_pool.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_os_proc_pool.erl b/test/couchdb/couchdb_os_proc_pool.erl
deleted file mode 100644
index 1bb266e..0000000
--- a/test/couchdb/couchdb_os_proc_pool.erl
+++ /dev/null
@@ -1,179 +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(couchdb_os_proc_pool).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(TIMEOUT, 3000).
-
-
-start() ->
-    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
-    couch_config:set("query_server_config", "os_process_limit", "3", false),
-    Pid.
-
-stop(Pid) ->
-    couch_server_sup:stop(),
-    erlang:monitor(process, Pid),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, server_stop})
-    end.
-
-
-os_proc_pool_test_() ->
-    {
-        "OS processes pool tests",
-        {
-            setup,
-            fun start/0, fun stop/1,
-            [
-                should_block_new_proc_on_full_pool(),
-                should_free_slot_on_proc_unexpected_exit()
-            ]
-        }
-    }.
-
-
-should_block_new_proc_on_full_pool() ->
-    ?_test(begin
-        Client1 = spawn_client(),
-        Client2 = spawn_client(),
-        Client3 = spawn_client(),
-
-        ?assertEqual(ok, ping_client(Client1)),
-        ?assertEqual(ok, ping_client(Client2)),
-        ?assertEqual(ok, ping_client(Client3)),
-
-        Proc1 = get_client_proc(Client1, "1"),
-        Proc2 = get_client_proc(Client2, "2"),
-        Proc3 = get_client_proc(Client3, "3"),
-
-        ?assertNotEqual(Proc1, Proc2),
-        ?assertNotEqual(Proc2, Proc3),
-        ?assertNotEqual(Proc3, Proc1),
-
-        Client4 = spawn_client(),
-        ?assertEqual(timeout, ping_client(Client4)),
-
-        ?assertEqual(ok, stop_client(Client1)),
-        ?assertEqual(ok, ping_client(Client4)),
-
-        Proc4 = get_client_proc(Client4, "4"),
-        ?assertEqual(Proc1, Proc4),
-
-        lists:map(fun(C) ->
-            ?assertEqual(ok, stop_client(C))
-        end, [Client2, Client3, Client4])
-    end).
-
-should_free_slot_on_proc_unexpected_exit() ->
-    ?_test(begin
-        Client1 = spawn_client(),
-        Client2 = spawn_client(),
-        Client3 = spawn_client(),
-
-        ?assertEqual(ok, ping_client(Client1)),
-        ?assertEqual(ok, ping_client(Client2)),
-        ?assertEqual(ok, ping_client(Client3)),
-
-        Proc1 = get_client_proc(Client1, "1"),
-        Proc2 = get_client_proc(Client2, "2"),
-        Proc3 = get_client_proc(Client3, "3"),
-
-        ?assertNotEqual(Proc1, Proc2),
-        ?assertNotEqual(Proc2, Proc3),
-        ?assertNotEqual(Proc3, Proc1),
-
-        ?assertEqual(ok, kill_client(Client1)),
-
-        Client4 = spawn_client(),
-        ?assertEqual(ok, ping_client(Client4)),
-
-        Proc4 = get_client_proc(Client4, "4"),
-        ?assertNotEqual(Proc4, Proc1),
-        ?assertNotEqual(Proc2, Proc4),
-        ?assertNotEqual(Proc3, Proc4),
-
-        lists:map(fun(C) ->
-            ?assertEqual(ok, stop_client(C))
-        end, [Client2, Client3, Client4])
-    end).
-
-
-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 ?TIMEOUT ->
-        timeout
-    end.
-
-get_client_proc({Pid, Ref}, ClientName) ->
-    Pid ! get_proc,
-    receive
-        {proc, Ref, Proc} -> Proc
-    after ?TIMEOUT ->
-        erlang:error({assertion_failed,
-                     [{module, ?MODULE},
-                      {line, ?LINE},
-                      {reason, "Timeout getting client "
-                               ++ ClientName ++ " proc"}]})
-    end.
-
-stop_client({Pid, Ref}) ->
-    Pid ! stop,
-    receive
-        {stop, Ref} ->
-            ok
-    after ?TIMEOUT ->
-        timeout
-    end.
-
-kill_client({Pid, Ref}) ->
-    Pid ! die,
-    receive
-        {die, Ref} ->
-            ok
-    after ?TIMEOUT ->
-        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.


[13/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 081-config-override.t etap test suite to eunit

Merged into couch_config_tests suite.
Setup fixtures.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/fc45cdd9
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/fc45cdd9
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/fc45cdd9

Branch: refs/heads/1963-eunit-bigcouch
Commit: fc45cdd9513f4609930c551d933728203e4d8520
Parents: a77cdf5
Author: Alexander Shorin <kx...@apache.org>
Authored: Sun May 25 22:02:19 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:43 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couch_config_tests.erl            | 130 +++++++++++++++++++-
 test/couchdb/fixtures/couch_config_tests_1.ini |  22 ++++
 test/couchdb/fixtures/couch_config_tests_2.ini |  22 ++++
 3 files changed, 168 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/fc45cdd9/test/couchdb/couch_config_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_config_tests.erl b/test/couchdb/couch_config_tests.erl
index ecff590..4bdc333 100644
--- a/test/couchdb/couch_config_tests.erl
+++ b/test/couchdb/couch_config_tests.erl
@@ -17,9 +17,30 @@
 
 -define(TIMEOUT, 1000).
 
+-define(CONFIG_DEFAULT,
+        filename:join([?BUILDDIR, "etc", "couchdb", "default_dev.ini"])).
+-define(CONFIG_FIXTURE_1,
+        filename:join([?FIXTURESDIR, "couch_config_tests_1.ini"])).
+-define(CONFIG_FIXTURE_2,
+        filename:join([?FIXTURESDIR, "couch_config_tests_2.ini"])).
+-define(CONFIG_FIXTURE_TEMP,
+    begin
+        FileName = filename:join([?TEMPDIR, "couch_config_temp.ini"]),
+        {ok, Fd} = file:open(FileName, write),
+        ok = file:truncate(Fd),
+        ok = file:close(Fd),
+        FileName
+    end).
+
 
 setup() ->
-    {ok, Pid} = couch_config:start_link(?CONFIG_CHAIN),
+    setup(?CONFIG_CHAIN).
+setup({temporary, Chain}) ->
+    setup(Chain);
+setup({persistent, Chain}) ->
+    setup(lists:append(Chain, [?CONFIG_FIXTURE_TEMP]));
+setup(Chain) ->
+    {ok, Pid} = couch_config:start_link(Chain),
     Pid.
 
 teardown(Pid) ->
@@ -31,6 +52,8 @@ teardown(Pid) ->
     after ?TIMEOUT ->
         throw({timeout_error, config_stop})
     end.
+teardown(_, Pid) ->
+    teardown(Pid).
 
 
 couch_config_test_() ->
@@ -39,7 +62,9 @@ couch_config_test_() ->
         [
             couch_config_get_tests(),
             couch_config_set_tests(),
-            couch_config_del_tests()
+            couch_config_del_tests(),
+            config_override_tests(),
+            config_persistent_changes_tests()
         ]
     }.
 
@@ -90,6 +115,43 @@ couch_config_del_tests() ->
         }
     }.
 
+config_override_tests() ->
+    {
+        "Configs overide tests",
+        {
+            foreachx,
+            fun setup/1, fun teardown/2,
+            [
+                {{temporary, [?CONFIG_DEFAULT]},
+                 fun should_ensure_in_defaults/2},
+                {{temporary, [?CONFIG_DEFAULT, ?CONFIG_FIXTURE_1]},
+                 fun should_override_options/2},
+                {{temporary, [?CONFIG_DEFAULT, ?CONFIG_FIXTURE_2]},
+                 fun should_create_new_sections_on_override/2},
+                {{temporary, [?CONFIG_DEFAULT, ?CONFIG_FIXTURE_1,
+                              ?CONFIG_FIXTURE_2]},
+                 fun should_win_last_in_chain/2}
+            ]
+        }
+    }.
+
+config_persistent_changes_tests() ->
+    {
+        "Config persistent changes",
+        {
+            foreachx,
+            fun setup/1, fun teardown/2,
+            [
+                {{persistent, [?CONFIG_DEFAULT]},
+                 fun should_write_changes/2},
+                {{temporary, [?CONFIG_DEFAULT]},
+                 fun should_ensure_that_default_wasnt_modified/2},
+                {{temporary, [?CONFIG_FIXTURE_TEMP]},
+                 fun should_ensure_that_written_to_last_config_in_chain/2}
+            ]
+        }
+    }.
+
 
 should_load_all_configs() ->
     ?_assert(length(couch_config:all()) > 0).
@@ -151,10 +213,7 @@ should_return_undefined_atom_after_option_deletion() ->
         end).
 
 should_be_ok_on_deleting_unknown_options() ->
-    ?_assertEqual(ok,
-        begin
-            couch_config:delete("zoo", "boo", false)
-        end).
+    ?_assertEqual(ok, couch_config:delete("zoo", "boo", false)).
 
 should_delete_binary_option() ->
     ?_assertEqual(undefined,
@@ -163,3 +222,62 @@ should_delete_binary_option() ->
             ok = couch_config:delete(<<"foo">>, <<"bar">>, false),
             couch_config:get(<<"foo">>, <<"bar">>)
         end).
+
+should_ensure_in_defaults(_, _) ->
+    ?_test(begin
+        ?assertEqual("100",
+                     couch_config:get("couchdb", "max_dbs_open")),
+        ?assertEqual("5984",
+                     couch_config:get("httpd", "port")),
+        ?assertEqual(undefined,
+                     couch_config:get("fizbang", "unicode"))
+    end).
+
+should_override_options(_, _) ->
+    ?_test(begin
+        ?assertEqual("10",
+                     couch_config:get("couchdb", "max_dbs_open")),
+        ?assertEqual("4895",
+                     couch_config:get("httpd", "port"))
+    end).
+
+should_create_new_sections_on_override(_, _) ->
+    ?_test(begin
+        ?assertEqual("80",
+                     couch_config:get("httpd", "port")),
+        ?assertEqual("normalized",
+                     couch_config:get("fizbang", "unicode"))
+    end).
+
+should_win_last_in_chain(_, _) ->
+    ?_assertEqual("80", couch_config:get("httpd", "port")).
+
+should_write_changes(_, _) ->
+    ?_test(begin
+        ?assertEqual("5984",
+                     couch_config:get("httpd", "port")),
+        ?assertEqual(ok,
+                     couch_config:set("httpd", "port", "8080")),
+        ?assertEqual("8080",
+                     couch_config:get("httpd", "port")),
+        ?assertEqual(ok,
+                     couch_config:delete("httpd", "bind_address", "8080")),
+        ?assertEqual(undefined,
+                     couch_config:get("httpd", "bind_address"))
+    end).
+
+should_ensure_that_default_wasnt_modified(_, _) ->
+    ?_test(begin
+        ?assertEqual("5984",
+                     couch_config:get("httpd", "port")),
+        ?assertEqual("127.0.0.1",
+                     couch_config:get("httpd", "bind_address"))
+    end).
+
+should_ensure_that_written_to_last_config_in_chain(_, _) ->
+    ?_test(begin
+        ?assertEqual("8080",
+                     couch_config:get("httpd", "port")),
+        ?assertEqual(undefined,
+                     couch_config:get("httpd", "bind_address"))
+    end).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/fc45cdd9/test/couchdb/fixtures/couch_config_tests_1.ini
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/couch_config_tests_1.ini b/test/couchdb/fixtures/couch_config_tests_1.ini
new file mode 100644
index 0000000..55451da
--- /dev/null
+++ b/test/couchdb/fixtures/couch_config_tests_1.ini
@@ -0,0 +1,22 @@
+; 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

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/fc45cdd9/test/couchdb/fixtures/couch_config_tests_2.ini
----------------------------------------------------------------------
diff --git a/test/couchdb/fixtures/couch_config_tests_2.ini b/test/couchdb/fixtures/couch_config_tests_2.ini
new file mode 100644
index 0000000..5f46357
--- /dev/null
+++ b/test/couchdb/fixtures/couch_config_tests_2.ini
@@ -0,0 +1,22 @@
+; 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


[08/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 083-config-no-files.t etap test suite to eunit

Merged into couch_config_tests suite.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/6f7a3e3f
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/6f7a3e3f
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/6f7a3e3f

Branch: refs/heads/1963-eunit-bigcouch
Commit: 6f7a3e3f1ca284f5d53ed64e4466987e8a151879
Parents: 5331d80
Author: Alexander Shorin <kx...@apache.org>
Authored: Mon May 26 09:46:06 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:43 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couch_config_tests.erl | 37 +++++++++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/6f7a3e3f/test/couchdb/couch_config_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_config_tests.erl b/test/couchdb/couch_config_tests.erl
index fdd2479..9e9dfe7 100644
--- a/test/couchdb/couch_config_tests.erl
+++ b/test/couchdb/couch_config_tests.erl
@@ -44,6 +44,9 @@ setup(Chain) ->
     {ok, Pid} = couch_config:start_link(Chain),
     Pid.
 
+setup_empty() ->
+    setup([]).
+
 setup_register() ->
     ConfigPid = setup(),
     SentinelFunc = fun() ->
@@ -92,7 +95,8 @@ couch_config_test_() ->
             couch_config_del_tests(),
             config_override_tests(),
             config_persistent_changes_tests(),
-            config_register_tests()
+            config_register_tests(),
+            config_no_files_tests()
         ]
     }.
 
@@ -195,6 +199,20 @@ config_register_tests() ->
         }
     }.
 
+config_no_files_tests() ->
+    {
+        "Test couch_config with no files",
+        {
+            foreach,
+            fun setup_empty/0, fun teardown/1,
+            [
+                should_ensure_that_no_ini_files_loaded(),
+                should_create_non_persistent_option(),
+                should_create_persistent_option()
+            ]
+        }
+    }.
+
 
 should_load_all_configs() ->
     ?_assert(length(couch_config:all()) > 0).
@@ -426,3 +444,20 @@ should_not_trigger_handler_after_related_process_death({_, SentinelPid}) ->
             true
         end
     end).
+
+should_ensure_that_no_ini_files_loaded() ->
+    ?_assertEqual(0, length(couch_config:all())).
+
+should_create_non_persistent_option() ->
+    ?_assertEqual("80",
+        begin
+            ok = couch_config:set("httpd", "port", "80", false),
+            couch_config:get("httpd", "port")
+        end).
+
+should_create_persistent_option() ->
+    ?_assertEqual("127.0.0.1",
+        begin
+            ok = couch_config:set("httpd", "bind_address", "127.0.0.1"),
+            couch_config:get("httpd", "bind_address")
+        end).


[23/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 200-view-group-no-db-leaks.t etap test suite to eunit

Merged into couchdb_views_tests suite. Apply minor refactor changes.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/dee39e73
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/dee39e73
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/dee39e73

Branch: refs/heads/1963-eunit-bigcouch
Commit: dee39e736f6895a255d96381fa70dbd0e3f87860
Parents: bdc3e8b
Author: Alexander Shorin <kx...@apache.org>
Authored: Thu Jun 5 23:03:31 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:44 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_views_tests.erl | 240 +++++++++++++++++++++++++++---
 1 file changed, 223 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dee39e73/test/couchdb/couchdb_views_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_views_tests.erl b/test/couchdb/couchdb_views_tests.erl
index d10b567..77ee4f5 100644
--- a/test/couchdb/couchdb_views_tests.erl
+++ b/test/couchdb/couchdb_views_tests.erl
@@ -16,8 +16,10 @@
 -include_lib("couchdb/couch_db.hrl").
 
 -define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
+-define(DELAY, 100).
 -define(TIMEOUT, 1000).
 
+
 start() ->
     {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
     Pid.
@@ -34,7 +36,8 @@ stop(Pid) ->
 
 setup() ->
     DbName = ?tempdb(),
-    {ok, _} = couch_db:create(DbName, [?ADMIN_USER]),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+    ok = couch_db:close(Db),
     FooRev = create_design_doc(DbName, <<"_design/foo">>, <<"bar">>),
     query_view(DbName, "foo", "bar"),
     BooRev = create_design_doc(DbName, <<"_design/boo">>, <<"baz">>),
@@ -43,7 +46,8 @@ setup() ->
 
 setup_with_docs() ->
     DbName = ?tempdb(),
-    {ok, _} = couch_db:create(DbName, [?ADMIN_USER]),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER]),
+    ok = couch_db:close(Db),
     create_docs(DbName),
     create_design_doc(DbName, <<"_design/foo">>, <<"bar">>),
     DbName.
@@ -51,7 +55,7 @@ setup_with_docs() ->
 teardown({DbName, _}) ->
     teardown(DbName);
 teardown(DbName) when is_binary(DbName) ->
-    ok = couch_server:delete(DbName, [?ADMIN_USER]),
+    couch_server:delete(DbName, [?ADMIN_USER]),
     ok.
 
 
@@ -73,17 +77,33 @@ view_indexes_cleanup_test_() ->
         }
     }.
 
+view_group_db_leaks_test_() ->
+    {
+        "View group db leaks",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup_with_docs/0, fun teardown/1,
+                [
+                    fun couchdb_1138/1,
+                    fun couchdb_1309/1
+                ]
+            }
+        }
+    }.
+
+
 should_not_remember_docs_in_index_after_backup_restore_test() ->
     %% COUCHDB-640
     start(),
     DbName = setup_with_docs(),
 
     ok = backup_db_file(DbName),
-    create_doc(DbName),
+    create_doc(DbName, "doc666"),
 
-    Body0 = query_view(DbName, "foo", "bar"),
-    ViewJson0 = ejson:decode(Body0),
-    Rows0 = couch_util:get_nested_json_value(ViewJson0, [<<"rows">>]),
+    Rows0 = query_view(DbName, "foo", "bar"),
     ?assert(has_doc("doc1", Rows0)),
     ?assert(has_doc("doc2", Rows0)),
     ?assert(has_doc("doc3", Rows0)),
@@ -91,9 +111,7 @@ should_not_remember_docs_in_index_after_backup_restore_test() ->
 
     restore_backup_db_file(DbName),
 
-    Body1 = query_view(DbName, "foo", "bar"),
-    ViewJson1 = ejson:decode(Body1),
-    Rows1 = couch_util:get_nested_json_value(ViewJson1, [<<"rows">>]),
+    Rows1 = query_view(DbName, "foo", "bar"),
     ?assert(has_doc("doc1", Rows1)),
     ?assert(has_doc("doc2", Rows1)),
     ?assert(has_doc("doc3", Rows1)),
@@ -118,13 +136,106 @@ should_cleanup_all_index_files({DbName, {FooRev, BooRev}})->
     view_cleanup(DbName),
     ?_assertEqual(0, count_index_files(DbName)).
 
-
-create_doc(DbName) ->
+couchdb_1138(DbName) ->
+    ?_test(begin
+        {ok, IndexerPid} = couch_index_server:get_index(
+            couch_mrview_index, DbName, <<"_design/foo">>),
+        ?assert(is_pid(IndexerPid)),
+        ?assert(is_process_alive(IndexerPid)),
+        ?assertEqual(2, count_db_refs(DbName)),
+
+        Rows0 = query_view(DbName, "foo", "bar"),
+        ?assertEqual(3, length(Rows0)),
+        ?assertEqual(2, count_db_refs(DbName)),
+        ?assert(is_process_alive(IndexerPid)),
+
+        create_doc(DbName, "doc1000"),
+        Rows1 = query_view(DbName, "foo", "bar"),
+        ?assertEqual(4, length(Rows1)),
+        ?assertEqual(2, count_db_refs(DbName)),
+        ?assert(is_process_alive(IndexerPid)),
+
+        Ref1 = get_db_ref_counter(DbName),
+        compact_db(DbName),
+        Ref2 = get_db_ref_counter(DbName),
+        ?assertEqual(2, couch_ref_counter:count(Ref2)),
+        ?assertNotEqual(Ref2, Ref1),
+        ?assertNot(is_process_alive(Ref1)),
+        ?assert(is_process_alive(IndexerPid)),
+
+        compact_view_group(DbName, "foo"),
+        ?assertEqual(2, count_db_refs(DbName)),
+        Ref3 = get_db_ref_counter(DbName),
+        ?assertEqual(Ref3, Ref2),
+        ?assert(is_process_alive(IndexerPid)),
+
+        create_doc(DbName, "doc1001"),
+        Rows2 = query_view(DbName, "foo", "bar"),
+        ?assertEqual(5, length(Rows2)),
+        ?assertEqual(2, count_db_refs(DbName)),
+        ?assert(is_process_alive(IndexerPid))
+    end).
+
+couchdb_1309(DbName) ->
+    ?_test(begin
+        {ok, IndexerPid} = couch_index_server:get_index(
+            couch_mrview_index, DbName, <<"_design/foo">>),
+        ?assert(is_pid(IndexerPid)),
+        ?assert(is_process_alive(IndexerPid)),
+        ?assertEqual(2, count_db_refs(DbName)),
+
+        create_doc(DbName, "doc1001"),
+        Rows0 = query_view(DbName, "foo", "bar"),
+        check_rows_value(Rows0, null),
+        ?assertEqual(4, length(Rows0)),
+        ?assertEqual(2, count_db_refs(DbName)),
+        ?assert(is_process_alive(IndexerPid)),
+
+        update_design_doc(DbName,  <<"_design/foo">>, <<"bar">>),
+        {ok, NewIndexerPid} = couch_index_server:get_index(
+            couch_mrview_index, DbName, <<"_design/foo">>),
+        ?assert(is_pid(NewIndexerPid)),
+        ?assert(is_process_alive(NewIndexerPid)),
+        ?assertNotEqual(IndexerPid, NewIndexerPid),
+        ?assertEqual(2, count_db_refs(DbName)),
+
+        Rows1 = query_view(DbName, "foo", "bar", ok),
+        ?assertEqual(0, length(Rows1)),
+        Rows2 = query_view(DbName, "foo", "bar"),
+        check_rows_value(Rows2, 1),
+        ?assertEqual(4, length(Rows2)),
+
+        MonRef0 = erlang:monitor(process, IndexerPid),
+        receive
+            {'DOWN', MonRef0, _, _, _} ->
+                ok
+        after ?TIMEOUT ->
+            erlang:error(
+                {assertion_failed,
+                 [{module, ?MODULE}, {line, ?LINE},
+                  {reason, "old view group is not dead after ddoc update"}]})
+        end,
+
+        MonRef1 = erlang:monitor(process, NewIndexerPid),
+        ok = couch_server:delete(DbName, [?ADMIN_USER]),
+        receive
+            {'DOWN', MonRef1, _, _, _} ->
+                ok
+        after ?TIMEOUT ->
+            erlang:error(
+                {assertion_failed,
+                 [{module, ?MODULE}, {line, ?LINE},
+                  {reason, "new view group did not die after DB deletion"}]})
+        end
+    end).
+
+create_doc(DbName, DocId) when is_list(DocId) ->
+    create_doc(DbName, ?l2b(DocId));
+create_doc(DbName, DocId) when is_binary(DocId) ->
     {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
     Doc666 = couch_doc:from_json_obj({[
-        {<<"_id">>, <<"doc666">>},
+        {<<"_id">>, DocId},
         {<<"value">>, 999}
-
     ]}),
     {ok, _} = couch_db:update_docs(Db, [Doc666]),
     couch_db:ensure_full_commit(Db),
@@ -158,7 +269,7 @@ create_design_doc(DbName, DDName, ViewName) ->
         {<<"language">>, <<"javascript">>},
         {<<"views">>, {[
             {ViewName, {[
-                {<<"map">>, <<"function(doc) { emit(doc.value, 1); }">>}
+                {<<"map">>, <<"function(doc) { emit(doc.value, null); }">>}
             ]}}
         ]}}
     ]}),
@@ -167,6 +278,26 @@ create_design_doc(DbName, DDName, ViewName) ->
     couch_db:close(Db),
     Rev.
 
+update_design_doc(DbName, DDName, ViewName) ->
+    {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
+    {ok, Doc} = couch_db:open_doc(Db, DDName, [?ADMIN_USER]),
+    {Props} = couch_doc:to_json_obj(Doc, []),
+    Rev = couch_util:get_value(<<"_rev">>, Props),
+    DDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, DDName},
+        {<<"_rev">>, Rev},
+        {<<"language">>, <<"javascript">>},
+        {<<"views">>, {[
+            {ViewName, {[
+                {<<"map">>, <<"function(doc) { emit(doc.value, 1); }">>}
+            ]}}
+        ]}}
+    ]}),
+    {ok, NewRev} = couch_db:update_doc(Db, DDoc, [?ADMIN_USER]),
+    couch_db:ensure_full_commit(Db),
+    couch_db:close(Db),
+    NewRev.
+
 delete_design_doc(DbName, DDName, Rev) ->
     {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
     DDoc = couch_doc:from_json_obj({[
@@ -183,16 +314,43 @@ db_url(DbName) ->
     "http://" ++ Addr ++ ":" ++ Port ++ "/" ++ ?b2l(DbName).
 
 query_view(DbName, DDoc, View) ->
+    query_view(DbName, DDoc, View, false).
+
+query_view(DbName, DDoc, View, Stale) ->
     {ok, Code, _Headers, Body} = test_request:get(
-        db_url(DbName) ++ "/_design/" ++ DDoc ++ "/_view/" ++ View),
+        db_url(DbName) ++ "/_design/" ++ DDoc ++ "/_view/" ++ View
+        ++ case Stale of
+               false -> [];
+               _ -> "?stale=" ++ atom_to_list(Stale)
+           end),
     ?assertEqual(200, Code),
-    Body.
+    {Props} = ejson:decode(Body),
+    couch_util:get_value(<<"rows">>, Props, []).
+
+check_rows_value(Rows, Value) ->
+    lists:foreach(
+        fun({Row}) ->
+            ?assertEqual(Value, couch_util:get_value(<<"value">>, Row))
+        end, Rows).
 
 view_cleanup(DbName) ->
     {ok, Db} = couch_db:open(DbName, [?ADMIN_USER]),
     couch_mrview:cleanup(Db),
     couch_db:close(Db).
 
+get_db_ref_counter(DbName) ->
+    {ok, #db{fd_ref_counter = Ref} = Db} = couch_db:open_int(DbName, []),
+    ok = couch_db:close(Db),
+    Ref.
+
+count_db_refs(DbName) ->
+    Ref = get_db_ref_counter(DbName),
+    % have to sleep a bit to let couchdb cleanup all refs and leave only
+    % active ones. otherwise the related tests will randomly fail due to
+    % count number mismatch
+    timer:sleep(200),
+    couch_ref_counter:count(Ref).
+
 count_index_files(DbName) ->
     % call server to fetch the index files
     RootDir = couch_config:get("couchdb", "view_index_dir"),
@@ -217,3 +375,51 @@ restore_backup_db_file(DbName) ->
     ok = file:rename(DbFile ++ ".backup", DbFile),
     start(),
     ok.
+
+compact_db(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, _} = couch_db:start_compact(Db),
+    ok = couch_db:close(Db),
+    wait_db_compact_done(DbName, 10).
+
+wait_db_compact_done(_DbName, 0) ->
+    erlang:error({assertion_failed,
+                  [{module, ?MODULE},
+                   {line, ?LINE},
+                   {reason, "DB compaction failed to finish"}]});
+wait_db_compact_done(DbName, N) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    ok = couch_db:close(Db),
+    case is_pid(Db#db.compactor_pid) of
+    false ->
+        ok;
+    true ->
+        ok = timer:sleep(?DELAY),
+        wait_db_compact_done(DbName, N - 1)
+    end.
+
+compact_view_group(DbName, DDocId) when is_list(DDocId) ->
+    compact_view_group(DbName, ?l2b("_design/" ++ DDocId));
+compact_view_group(DbName, DDocId) when is_binary(DDocId) ->
+    ok = couch_mrview:compact(DbName, DDocId),
+    wait_view_compact_done(DbName, DDocId, 10).
+
+wait_view_compact_done(_DbName, _DDocId, 0) ->
+    erlang:error({assertion_failed,
+                  [{module, ?MODULE},
+                   {line, ?LINE},
+                   {reason, "DB compaction failed to finish"}]});
+wait_view_compact_done(DbName, DDocId, N) ->
+    {ok, Code, _Headers, Body} = test_request:get(
+        db_url(DbName) ++ "/" ++ ?b2l(DDocId) ++ "/_info"),
+    ?assertEqual(200, Code),
+    {Info} = ejson: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(?DELAY),
+            wait_view_compact_done(DbName, DDocId, N - 1)
+    end.


[39/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Add .eunit to .gitignore


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/c237090f
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/c237090f
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/c237090f

Branch: refs/heads/1963-eunit-bigcouch
Commit: c237090ffb4ba9069566390bcbaa45fa5162bc6a
Parents: e86e553
Author: Russell Branca <ch...@apache.org>
Authored: Mon Aug 11 15:40:14 2014 -0700
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:24:05 2014 -0700

----------------------------------------------------------------------
 .gitignore | 2 ++
 1 file changed, 2 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/c237090f/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index e5bb133..1e91829 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,5 @@ ebin/
 priv/couch_js/config.h
 priv/couchjs
 priv/couchspawnkillable
+
+.eunit
\ No newline at end of file


[05/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Port 074-doc-update-conflicts.t etap test suite to eunit

Timeout decreased, added 10K clients case


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/92c3c842
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/92c3c842
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/92c3c842

Branch: refs/heads/1963-eunit-bigcouch
Commit: 92c3c842ac1bdbbcabe4b797a34fa41612b5f263
Parents: 4471f8c
Author: Alexander Shorin <kx...@apache.org>
Authored: Wed May 21 18:58:12 2014 +0400
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:43 2014 -0700

----------------------------------------------------------------------
 test/couchdb/couchdb_update_conflicts_tests.erl | 243 +++++++++++++++++++
 1 file changed, 243 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/92c3c842/test/couchdb/couchdb_update_conflicts_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couchdb_update_conflicts_tests.erl b/test/couchdb/couchdb_update_conflicts_tests.erl
new file mode 100644
index 0000000..7226860
--- /dev/null
+++ b/test/couchdb/couchdb_update_conflicts_tests.erl
@@ -0,0 +1,243 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couchdb_update_conflicts_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(i2l(I), integer_to_list(I)).
+-define(ADMIN_USER, {userctx, #user_ctx{roles=[<<"_admin">>]}}).
+-define(DOC_ID, <<"foobar">>).
+-define(NUM_CLIENTS, [100, 500, 1000, 2000, 5000, 10000]).
+-define(TIMEOUT, 10000).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    couch_config:set("couchdb", "delayed_commits", "true", false),
+    Pid.
+
+stop(Pid) ->
+    erlang:monitor(process, Pid),
+    couch_server_sup:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, [?ADMIN_USER, overwrite]),
+    Doc = couch_doc:from_json_obj({[{<<"_id">>, ?DOC_ID},
+                                    {<<"value">>, 0}]}),
+    {ok, Rev} = couch_db:update_doc(Db, Doc, []),
+    ok = couch_db:close(Db),
+    RevStr = couch_doc:rev_to_str(Rev),
+    {DbName, RevStr}.
+setup(_) ->
+    setup().
+
+teardown({DbName, _}) ->
+    ok = couch_server:delete(DbName, []),
+    ok.
+teardown(_, {DbName, _RevStr}) ->
+    teardown({DbName, _RevStr}).
+
+
+view_indexes_cleanup_test_() ->
+    {
+        "Update conflicts",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            [
+                concurrent_updates(),
+                couchdb_188()
+            ]
+        }
+    }.
+
+concurrent_updates()->
+    {
+        "Concurrent updates",
+        {
+            foreachx,
+            fun setup/1, fun teardown/2,
+            [{NumClients, fun should_concurrently_update_doc/2}
+             || NumClients <- ?NUM_CLIENTS]
+        }
+    }.
+
+couchdb_188()->
+    {
+        "COUCHDB-188",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [fun should_bulk_create_delete_doc/1]
+        }
+    }.
+
+
+should_concurrently_update_doc(NumClients, {DbName, InitRev})->
+     {?i2l(NumClients) ++ " clients",
+      {inorder,
+       [{"update doc",
+         {timeout, ?TIMEOUT div 1000,
+          ?_test(concurrent_doc_update(NumClients, DbName, InitRev))}},
+        {"ensure in single leaf",
+         ?_test(ensure_in_single_revision_leaf(DbName))}]}}.
+
+should_bulk_create_delete_doc({DbName, InitRev})->
+    ?_test(bulk_delete_create(DbName, InitRev)).
+
+
+concurrent_doc_update(NumClients, DbName, InitRev) ->
+    Clients = lists:map(
+        fun(Value) ->
+            ClientDoc = couch_doc:from_json_obj({[
+                {<<"_id">>, ?DOC_ID},
+                {<<"_rev">>, InitRev},
+                {<<"value">>, Value}
+            ]}),
+            Pid = spawn_client(DbName, ClientDoc),
+            {Value, Pid, erlang:monitor(process, Pid)}
+        end,
+        lists:seq(1, NumClients)),
+
+    lists:foreach(fun({_, Pid, _}) -> Pid ! go end, Clients),
+
+    {NumConflicts, SavedValue} = lists:foldl(
+        fun({Value, Pid, MonRef}, {AccConflicts, AccValue}) ->
+            receive
+                {'DOWN', MonRef, process, Pid, {ok, _NewRev}} ->
+                    {AccConflicts, Value};
+                {'DOWN', MonRef, process, Pid, conflict} ->
+                    {AccConflicts + 1, AccValue};
+                {'DOWN', MonRef, process, Pid, Error} ->
+                    erlang:error({assertion_failed,
+                         [{module, ?MODULE},
+                          {line, ?LINE},
+                          {reason, "Client " ++ ?i2l(Value)
+                                             ++ " got update error: "
+                                             ++ couch_util:to_list(Error)}]})
+            after ?TIMEOUT div 2 ->
+                 erlang:error({assertion_failed,
+                         [{module, ?MODULE},
+                          {line, ?LINE},
+                          {reason, "Timeout waiting for client "
+                                   ++ ?i2l(Value) ++ " to die"}]})
+            end
+        end, {0, nil}, Clients),
+    ?assertEqual(NumClients - 1, NumConflicts),
+
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, Leaves} = couch_db:open_doc_revs(Db, ?DOC_ID, all, []),
+    ok = couch_db:close(Db),
+    ?assertEqual(1, length(Leaves)),
+
+    [{ok, Doc2}] = Leaves,
+    {JsonDoc} = couch_doc:to_json_obj(Doc2, []),
+    ?assertEqual(SavedValue, couch_util:get_value(<<"value">>, JsonDoc)).
+
+ensure_in_single_revision_leaf(DbName) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, Leaves} = couch_db:open_doc_revs(Db, ?DOC_ID, all, []),
+    ok = couch_db:close(Db),
+    [{ok, Doc}] = Leaves,
+
+    %% FIXME: server restart won't work from test side
+    %% stop(ok),
+    %% start(),
+
+    {ok, Db2} = couch_db:open_int(DbName, []),
+    {ok, Leaves2} = couch_db:open_doc_revs(Db2, ?DOC_ID, all, []),
+    ok = couch_db:close(Db2),
+    ?assertEqual(1, length(Leaves2)),
+
+    [{ok, Doc2}] = Leaves,
+    ?assertEqual(Doc, Doc2).
+    
+bulk_delete_create(DbName, InitRev) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    
+    DeletedDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, ?DOC_ID},
+        {<<"_rev">>, InitRev},
+        {<<"_deleted">>, true}
+    ]}),
+    NewDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, ?DOC_ID},
+        {<<"value">>, 666}
+    ]}),
+
+    {ok, Results} = couch_db:update_docs(Db, [DeletedDoc, NewDoc], []),
+    ok = couch_db:close(Db),
+
+    ?assertEqual(2, length([ok || {ok, _} <- Results])),
+    [{ok, Rev1}, {ok, Rev2}] = Results,
+    
+    {ok, Db2} = couch_db:open_int(DbName, []),
+    {ok, [{ok, Doc1}]} = couch_db:open_doc_revs(
+        Db2, ?DOC_ID, [Rev1], [conflicts, deleted_conflicts]),
+    {ok, [{ok, Doc2}]} = couch_db:open_doc_revs(
+        Db2, ?DOC_ID, [Rev2], [conflicts, deleted_conflicts]),
+    ok = couch_db:close(Db2),
+
+    {Doc1Props} = couch_doc:to_json_obj(Doc1, []),
+    {Doc2Props} = couch_doc:to_json_obj(Doc2, []),
+
+    %% Document was deleted
+    ?assert(couch_util:get_value(<<"_deleted">>, Doc1Props)),
+    %% New document not flagged as deleted
+    ?assertEqual(undefined, couch_util:get_value(<<"_deleted">>,
+                                                 Doc2Props)),
+    %% New leaf revision has the right value
+    ?assertEqual(666, couch_util:get_value(<<"value">>,
+                                           Doc2Props)),
+    %% Deleted document has no conflicts
+    ?assertEqual(undefined, couch_util:get_value(<<"_conflicts">>,
+                                                 Doc1Props)),
+    %% Deleted document has no deleted conflicts
+    ?assertEqual(undefined, couch_util:get_value(<<"_deleted_conflicts">>,
+                                                 Doc1Props)),
+    %% New leaf revision doesn't have conflicts
+    ?assertEqual(undefined, couch_util:get_value(<<"_conflicts">>,
+                                                 Doc1Props)),
+    %% New leaf revision doesn't have deleted conflicts
+    ?assertEqual(undefined, couch_util:get_value(<<"_deleted_conflicts">>,
+                                                 Doc1Props)),
+
+    %% Deleted revision has position 2
+    ?assertEqual(2, element(1, Rev1)),
+    %% New leaf revision has position 1
+    ?assertEqual(1, element(1, Rev2)).
+
+
+spawn_client(DbName, Doc) ->
+    spawn(fun() ->
+        {ok, Db} = couch_db:open_int(DbName, []),
+        receive
+            go -> ok
+        end,
+        erlang:yield(),
+        Result = try
+            couch_db:update_doc(Db, Doc, [])
+        catch _:Error ->
+            Error
+        end,
+        ok = couch_db:close(Db),
+        exit(Result)
+    end).


[38/50] [abbrv] couch commit: updated refs/heads/1963-eunit-bigcouch to 95bfc03

Posted by ch...@apache.org.
Move files out of test/couchdb into top level test/ folder


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/dfad673e
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/dfad673e
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/dfad673e

Branch: refs/heads/1963-eunit-bigcouch
Commit: dfad673ea6c8689ab00c59881de18b2d9726492b
Parents: 6b114c6
Author: Russell Branca <ch...@apache.org>
Authored: Mon Aug 11 13:19:06 2014 -0700
Committer: Russell Branca <ch...@apache.org>
Committed: Fri Aug 15 13:23:45 2014 -0700

----------------------------------------------------------------------
 test/couch_auth_cache_tests.erl                 | 238 +++++++
 test/couch_btree_tests.erl                      | 551 +++++++++++++++
 test/couch_changes_tests.erl                    | 612 +++++++++++++++++
 test/couch_config_tests.erl                     | 463 +++++++++++++
 test/couch_db_tests.erl                         | 114 ++++
 test/couch_doc_json_tests.erl                   | 391 +++++++++++
 test/couch_file_tests.erl                       | 265 ++++++++
 test/couch_key_tree_tests.erl                   | 380 +++++++++++
 test/couch_passwords_tests.erl                  |  54 ++
 test/couch_ref_counter_tests.erl                | 107 +++
 test/couch_stats_tests.erl                      | 412 ++++++++++++
 test/couch_stream_tests.erl                     | 100 +++
 test/couch_task_status_tests.erl                | 225 +++++++
 test/couch_util_tests.erl                       | 136 ++++
 test/couch_uuids_tests.erl                      | 161 +++++
 test/couch_work_queue_tests.erl                 | 393 +++++++++++
 test/couchdb/couch_auth_cache_tests.erl         | 238 -------
 test/couchdb/couch_btree_tests.erl              | 551 ---------------
 test/couchdb/couch_changes_tests.erl            | 612 -----------------
 test/couchdb/couch_config_tests.erl             | 463 -------------
 test/couchdb/couch_db_tests.erl                 | 114 ----
 test/couchdb/couch_doc_json_tests.erl           | 391 -----------
 test/couchdb/couch_file_tests.erl               | 265 --------
 test/couchdb/couch_key_tree_tests.erl           | 380 -----------
 test/couchdb/couch_passwords_tests.erl          |  54 --
 test/couchdb/couch_ref_counter_tests.erl        | 107 ---
 test/couchdb/couch_stats_tests.erl              | 412 ------------
 test/couchdb/couch_stream_tests.erl             | 100 ---
 test/couchdb/couch_task_status_tests.erl        | 225 -------
 test/couchdb/couch_util_tests.erl               | 136 ----
 test/couchdb/couch_uuids_tests.erl              | 161 -----
 test/couchdb/couch_work_queue_tests.erl         | 393 -----------
 test/couchdb/couchdb_attachments_tests.erl      | 638 ------------------
 test/couchdb/couchdb_compaction_daemon.erl      | 231 -------
 test/couchdb/couchdb_cors_tests.erl             | 344 ----------
 test/couchdb/couchdb_csp_tests.erl              |  96 ---
 test/couchdb/couchdb_file_compression_tests.erl | 239 -------
 test/couchdb/couchdb_http_proxy_tests.erl       | 462 -------------
 test/couchdb/couchdb_modules_load_tests.erl     |  68 --
 test/couchdb/couchdb_os_daemons_tests.erl       | 228 -------
 test/couchdb/couchdb_os_proc_pool.erl           | 179 -----
 test/couchdb/couchdb_update_conflicts_tests.erl | 243 -------
 test/couchdb/couchdb_vhosts_tests.erl           | 441 ------------
 test/couchdb/couchdb_views_tests.erl            | 669 -------------------
 .../3b835456c235b1827e012e25666152f3.view       | Bin 4192 -> 0 bytes
 test/couchdb/fixtures/couch_config_tests_1.ini  |  22 -
 test/couchdb/fixtures/couch_config_tests_2.ini  |  22 -
 .../couchdb/fixtures/couch_stats_aggregates.cfg |  19 -
 .../couchdb/fixtures/couch_stats_aggregates.ini |  20 -
 test/couchdb/fixtures/logo.png                  | Bin 3010 -> 0 bytes
 test/couchdb/fixtures/os_daemon_bad_perm.sh     |  17 -
 test/couchdb/fixtures/os_daemon_can_reboot.sh   |  15 -
 .../couchdb/fixtures/os_daemon_configer.escript | 101 ---
 test/couchdb/fixtures/os_daemon_die_on_boot.sh  |  15 -
 test/couchdb/fixtures/os_daemon_die_quickly.sh  |  15 -
 test/couchdb/fixtures/os_daemon_looper.escript  |  26 -
 test/couchdb/fixtures/test.couch                | Bin 16482 -> 0 bytes
 test/couchdb/json_stream_parse_tests.erl        | 151 -----
 test/couchdb/test_request.erl                   |  75 ---
 test/couchdb/test_web.erl                       | 112 ----
 test/couchdb_attachments_tests.erl              | 638 ++++++++++++++++++
 test/couchdb_compaction_daemon.erl              | 231 +++++++
 test/couchdb_cors_tests.erl                     | 344 ++++++++++
 test/couchdb_csp_tests.erl                      |  96 +++
 test/couchdb_file_compression_tests.erl         | 239 +++++++
 test/couchdb_http_proxy_tests.erl               | 462 +++++++++++++
 test/couchdb_modules_load_tests.erl             |  68 ++
 test/couchdb_os_daemons_tests.erl               | 228 +++++++
 test/couchdb_os_proc_pool.erl                   | 179 +++++
 test/couchdb_update_conflicts_tests.erl         | 243 +++++++
 test/couchdb_vhosts_tests.erl                   | 441 ++++++++++++
 test/couchdb_views_tests.erl                    | 669 +++++++++++++++++++
 .../3b835456c235b1827e012e25666152f3.view       | Bin 0 -> 4192 bytes
 test/fixtures/couch_config_tests_1.ini          |  22 +
 test/fixtures/couch_config_tests_2.ini          |  22 +
 test/fixtures/couch_stats_aggregates.cfg        |  19 +
 test/fixtures/couch_stats_aggregates.ini        |  20 +
 test/fixtures/logo.png                          | Bin 0 -> 3010 bytes
 test/fixtures/os_daemon_bad_perm.sh             |  17 +
 test/fixtures/os_daemon_can_reboot.sh           |  15 +
 test/fixtures/os_daemon_configer.escript        | 101 +++
 test/fixtures/os_daemon_die_on_boot.sh          |  15 +
 test/fixtures/os_daemon_die_quickly.sh          |  15 +
 test/fixtures/os_daemon_looper.escript          |  26 +
 test/fixtures/test.couch                        | Bin 0 -> 16482 bytes
 test/json_stream_parse_tests.erl                | 151 +++++
 test/test_request.erl                           |  75 +++
 test/test_web.erl                               | 112 ++++
 88 files changed, 9050 insertions(+), 9050 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_auth_cache_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_auth_cache_tests.erl b/test/couch_auth_cache_tests.erl
new file mode 100644
index 0000000..3b2321c
--- /dev/null
+++ b/test/couch_auth_cache_tests.erl
@@ -0,0 +1,238 @@
+% 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(couch_auth_cache_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(ADMIN_USER, {user_ctx, #user_ctx{roles=[<<"_admin">>]}}).
+-define(SALT, <<"SALT">>).
+-define(TIMEOUT, 1000).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    Pid.
+
+stop(Pid) ->
+    erlang:monitor(process, Pid),
+    couch_server_sup:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    DbName = ?tempdb(),
+    couch_config:set("couch_httpd_auth", "authentication_db",
+                     ?b2l(DbName), false),
+    DbName.
+
+teardown(DbName) ->
+    ok = couch_server:delete(DbName, [?ADMIN_USER]),
+    ok.
+
+
+couch_auth_cache_test_() ->
+    {
+        "CouchDB auth cache tests",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    fun should_get_nil_on_missed_cache/1,
+                    fun should_get_right_password_hash/1,
+                    fun should_ensure_doc_hash_equals_cached_one/1,
+                    fun should_update_password/1,
+                    fun should_cleanup_cache_after_userdoc_deletion/1,
+                    fun should_restore_cache_after_userdoc_recreation/1,
+                    fun should_drop_cache_on_auth_db_change/1,
+                    fun should_restore_cache_on_auth_db_change/1,
+                    fun should_recover_cache_after_shutdown/1
+                ]
+            }
+        }
+    }.
+
+
+should_get_nil_on_missed_cache(_) ->
+    ?_assertEqual(nil, couch_auth_cache:get_user_creds("joe")).
+
+should_get_right_password_hash(DbName) ->
+    ?_test(begin
+        PasswordHash = hash_password("pass1"),
+        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+        Creds = couch_auth_cache:get_user_creds("joe"),
+        ?assertEqual(PasswordHash,
+                      couch_util:get_value(<<"password_sha">>, Creds))
+    end).
+
+should_ensure_doc_hash_equals_cached_one(DbName) ->
+    ?_test(begin
+        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+        Creds = couch_auth_cache:get_user_creds("joe"),
+
+        CachedHash = couch_util:get_value(<<"password_sha">>, Creds),
+        StoredHash = get_user_doc_password_sha(DbName, "joe"),
+        ?assertEqual(StoredHash, CachedHash)
+    end).
+
+should_update_password(DbName) ->
+    ?_test(begin
+        PasswordHash = hash_password("pass2"),
+        {ok, Rev} = update_user_doc(DbName, "joe", "pass1"),
+        {ok, _} = update_user_doc(DbName, "joe", "pass2", Rev),
+        Creds = couch_auth_cache:get_user_creds("joe"),
+        ?assertEqual(PasswordHash,
+                      couch_util:get_value(<<"password_sha">>, Creds))
+    end).
+
+should_cleanup_cache_after_userdoc_deletion(DbName) ->
+    ?_test(begin
+        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+        delete_user_doc(DbName, "joe"),
+        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe"))
+    end).
+
+should_restore_cache_after_userdoc_recreation(DbName) ->
+    ?_test(begin
+        PasswordHash = hash_password("pass5"),
+        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+        delete_user_doc(DbName, "joe"),
+        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe")),
+
+        {ok, _} = update_user_doc(DbName, "joe", "pass5"),
+        Creds = couch_auth_cache:get_user_creds("joe"),
+
+        ?assertEqual(PasswordHash,
+                      couch_util:get_value(<<"password_sha">>, Creds))
+    end).
+
+should_drop_cache_on_auth_db_change(DbName) ->
+    ?_test(begin
+        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+        full_commit(DbName),
+        couch_config:set("couch_httpd_auth", "authentication_db",
+                         ?b2l(?tempdb()), false),
+        ?assertEqual(nil, couch_auth_cache:get_user_creds("joe"))
+    end).
+
+should_restore_cache_on_auth_db_change(DbName) ->
+    ?_test(begin
+        PasswordHash = hash_password("pass1"),
+        {ok, _} = update_user_doc(DbName, "joe", "pass1"),
+        Creds = couch_auth_cache:get_user_creds("joe"),
+        full_commit(DbName),
+
+        DbName1 = ?tempdb(),
+        couch_config:set("couch_httpd_auth", "authentication_db",
+                         ?b2l(DbName1), false),
+
+        {ok, _} = update_user_doc(DbName1, "joe", "pass5"),
+        full_commit(DbName1),
+
+        couch_config:set("couch_httpd_auth", "authentication_db",
+                         ?b2l(DbName), false),
+
+        Creds = couch_auth_cache:get_user_creds("joe"),
+        ?assertEqual(PasswordHash,
+                      couch_util:get_value(<<"password_sha">>, Creds))
+    end).
+
+should_recover_cache_after_shutdown(DbName) ->
+    ?_test(begin
+        PasswordHash = hash_password("pass2"),
+        {ok, Rev0} = update_user_doc(DbName, "joe", "pass1"),
+        {ok, Rev1} = update_user_doc(DbName, "joe", "pass2", Rev0),
+        full_commit(DbName),
+        shutdown_db(DbName),
+        {ok, Rev1} = get_doc_rev(DbName, "joe"),
+        ?assertEqual(PasswordHash, get_user_doc_password_sha(DbName, "joe"))
+    end).
+
+
+update_user_doc(DbName, UserName, Password) ->
+    update_user_doc(DbName, UserName, Password, nil).
+
+update_user_doc(DbName, UserName, Password, Rev) ->
+    User = iolist_to_binary(UserName),
+    Doc = couch_doc:from_json_obj({[
+        {<<"_id">>, <<"org.couchdb.user:", User/binary>>},
+        {<<"name">>, User},
+        {<<"type">>, <<"user">>},
+        {<<"salt">>, ?SALT},
+        {<<"password_sha">>, hash_password(Password)},
+        {<<"roles">>, []}
+    ] ++ case Rev of
+            nil -> [];
+            _ ->   [{<<"_rev">>, Rev}]
+         end
+    }),
+    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+    {ok, NewRev} = couch_db:update_doc(AuthDb, Doc, []),
+    ok = couch_db:close(AuthDb),
+    {ok, couch_doc:rev_to_str(NewRev)}.
+
+hash_password(Password) ->
+    ?l2b(couch_util:to_hex(crypto:sha(iolist_to_binary([Password, ?SALT])))).
+
+shutdown_db(DbName) ->
+    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+    ok = couch_db:close(AuthDb),
+    couch_util:shutdown_sync(AuthDb#db.main_pid),
+    ok = timer:sleep(1000).
+
+get_doc_rev(DbName, UserName) ->
+    DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
+    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+    UpdateRev =
+    case couch_db:open_doc(AuthDb, DocId, []) of
+    {ok, Doc} ->
+        {Props} = couch_doc:to_json_obj(Doc, []),
+        couch_util:get_value(<<"_rev">>, Props);
+    {not_found, missing} ->
+        nil
+    end,
+    ok = couch_db:close(AuthDb),
+    {ok, UpdateRev}.
+
+get_user_doc_password_sha(DbName, UserName) ->
+    DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
+    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+    {ok, Doc} = couch_db:open_doc(AuthDb, DocId, []),
+    ok = couch_db:close(AuthDb),
+    {Props} = couch_doc:to_json_obj(Doc, []),
+    couch_util:get_value(<<"password_sha">>, Props).
+
+delete_user_doc(DbName, UserName) ->
+    DocId = iolist_to_binary([<<"org.couchdb.user:">>, UserName]),
+    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+    {ok, Doc} = couch_db:open_doc(AuthDb, DocId, []),
+    {Props} = couch_doc:to_json_obj(Doc, []),
+    DeletedDoc = couch_doc:from_json_obj({[
+        {<<"_id">>, DocId},
+        {<<"_rev">>, couch_util:get_value(<<"_rev">>, Props)},
+        {<<"_deleted">>, true}
+    ]}),
+    {ok, _} = couch_db:update_doc(AuthDb, DeletedDoc, []),
+    ok = couch_db:close(AuthDb).
+
+full_commit(DbName) ->
+    {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_USER]),
+    {ok, _} = couch_db:ensure_full_commit(AuthDb),
+    ok = couch_db:close(AuthDb).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_btree_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_btree_tests.erl b/test/couch_btree_tests.erl
new file mode 100644
index 0000000..911640f
--- /dev/null
+++ b/test/couch_btree_tests.erl
@@ -0,0 +1,551 @@
+% 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(couch_btree_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(ROWS, 1000).
+
+
+setup() ->
+    {ok, Fd} = couch_file:open(?tempfile(), [create, overwrite]),
+    {ok, Btree} = couch_btree:open(nil, Fd, [{compression, none},
+                                             {reduce, fun reduce_fun/2}]),
+    {Fd, Btree}.
+
+setup_kvs(_) ->
+    setup().
+
+setup_red() ->
+    {_, 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)),
+    {Fd, Btree} = setup(),
+    {ok, Btree1} = couch_btree:add_remove(Btree, EvenOddKVs, []),
+    {Fd, Btree1}.
+setup_red(_) ->
+    setup_red().
+
+teardown(Fd) when is_pid(Fd) ->
+    ok = couch_file:close(Fd);
+teardown({Fd, _}) ->
+    teardown(Fd).
+teardown(_, {Fd, _}) ->
+    teardown(Fd).
+
+
+kvs_test_funs() ->
+    [
+        fun should_set_fd_correctly/2,
+        fun should_set_root_correctly/2,
+        fun should_create_zero_sized_btree/2,
+        fun should_set_reduce_option/2,
+        fun should_fold_over_empty_btree/2,
+        fun should_add_all_keys/2,
+        fun should_continuously_add_new_kv/2,
+        fun should_continuously_remove_keys/2,
+        fun should_insert_keys_in_reversed_order/2,
+        fun should_add_every_odd_key_remove_every_even/2,
+        fun should_add_every_even_key_remove_every_old/2
+    ].
+
+red_test_funs() ->
+    [
+        fun should_reduce_whole_range/2,
+        fun should_reduce_first_half/2,
+        fun should_reduce_second_half/2
+    ].
+
+
+btree_open_test_() ->
+    {ok, Fd} = couch_file:open(?tempfile(), [create, overwrite]),
+    {ok, Btree} = couch_btree:open(nil, Fd, [{compression, none}]),
+    {
+        "Ensure that created btree is really a btree record",
+        ?_assert(is_record(Btree, btree))
+    }.
+
+sorted_kvs_test_() ->
+    Funs = kvs_test_funs(),
+    Sorted = [{Seq, random:uniform()} || Seq <- lists:seq(1, ?ROWS)],
+    {
+        "BTree with sorted keys",
+        {
+            foreachx,
+            fun setup_kvs/1, fun teardown/2,
+            [{Sorted, Fun} || Fun <- Funs]
+        }
+    }.
+
+rsorted_kvs_test_() ->
+    Sorted = [{Seq, random:uniform()} || Seq <- lists:seq(1, ?ROWS)],
+    Funs = kvs_test_funs(),
+    Reversed = Sorted,
+    {
+        "BTree with backward sorted keys",
+        {
+            foreachx,
+            fun setup_kvs/1, fun teardown/2,
+            [{Reversed, Fun} || Fun <- Funs]
+        }
+    }.
+
+shuffled_kvs_test_() ->
+    Funs = kvs_test_funs(),
+    Sorted = [{Seq, random:uniform()} || Seq <- lists:seq(1, ?ROWS)],
+    Shuffled = shuffle(Sorted),
+    {
+        "BTree with shuffled keys",
+        {
+            foreachx,
+            fun setup_kvs/1, fun teardown/2,
+            [{Shuffled, Fun} || Fun <- Funs]
+        }
+    }.
+
+reductions_test_() ->
+    {
+        "BTree reductions",
+        [
+            {
+                "Common tests",
+                {
+                    foreach,
+                    fun setup_red/0, fun teardown/1,
+                    [
+                        fun should_reduce_without_specified_direction/1,
+                        fun should_reduce_forward/1,
+                        fun should_reduce_backward/1
+                    ]
+                }
+            },
+            {
+                "Range requests",
+                [
+                    {
+                        "Forward direction",
+                        {
+                            foreachx,
+                            fun setup_red/1, fun teardown/2,
+                            [{fwd, F} || F <- red_test_funs()]
+                        }
+                    },
+                    {
+                        "Backward direction",
+                        {
+                            foreachx,
+                            fun setup_red/1, fun teardown/2,
+                            [{rev, F} || F <- red_test_funs()]
+                        }
+                    }
+                ]
+            }
+        ]
+    }.
+
+
+should_set_fd_correctly(_, {Fd, Btree}) ->
+    ?_assertMatch(Fd, Btree#btree.fd).
+
+should_set_root_correctly(_, {_, Btree}) ->
+    ?_assertMatch(nil, Btree#btree.root).
+
+should_create_zero_sized_btree(_, {_, Btree}) ->
+    ?_assertMatch(0, couch_btree:size(Btree)).
+
+should_set_reduce_option(_, {_, Btree}) ->
+    ReduceFun = fun reduce_fun/2,
+    Btree1 = couch_btree:set_options(Btree, [{reduce, ReduceFun}]),
+    ?_assertMatch(ReduceFun, Btree1#btree.reduce).
+
+should_fold_over_empty_btree(_, {_, Btree}) ->
+    {ok, _, EmptyRes} = couch_btree:foldl(Btree, fun(_, X) -> {ok, X+1} end, 0),
+    ?_assertEqual(EmptyRes, 0).
+
+should_add_all_keys(KeyValues, {Fd, Btree}) ->
+    {ok, Btree1} = couch_btree:add_remove(Btree, KeyValues, []),
+    [
+        should_return_complete_btree_on_adding_all_keys(KeyValues, Btree1),
+        should_have_non_zero_size(Btree1),
+        should_have_lesser_size_than_file(Fd, Btree1),
+        should_keep_root_pointer_to_kp_node(Fd, Btree1),
+        should_remove_all_keys(KeyValues, Btree1)
+    ].
+
+should_return_complete_btree_on_adding_all_keys(KeyValues, Btree) ->
+    ?_assert(test_btree(Btree, KeyValues)).
+
+should_have_non_zero_size(Btree) ->
+    ?_assert(couch_btree:size(Btree) > 0).
+
+should_have_lesser_size_than_file(Fd, Btree) ->
+    ?_assert((couch_btree:size(Btree) =< couch_file:bytes(Fd))).
+
+should_keep_root_pointer_to_kp_node(Fd, Btree) ->
+    ?_assertMatch({ok, {kp_node, _}},
+                  couch_file:pread_term(Fd, element(1, Btree#btree.root))).
+
+should_remove_all_keys(KeyValues, Btree) ->
+    Keys = keys(KeyValues),
+    {ok, Btree1} = couch_btree:add_remove(Btree, [], Keys),
+    {
+        "Should remove all the keys",
+        [
+            should_produce_valid_btree(Btree1, []),
+            should_be_empty(Btree1)
+        ]
+    }.
+
+should_continuously_add_new_kv(KeyValues, {_, Btree}) ->
+    {Btree1, _} = lists:foldl(
+        fun(KV, {BtAcc, PrevSize}) ->
+            {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [KV], []),
+            ?assert(couch_btree:size(BtAcc2) > PrevSize),
+            {BtAcc2, couch_btree:size(BtAcc2)}
+        end, {Btree, couch_btree:size(Btree)}, KeyValues),
+    {
+        "Should continuously add key-values to btree",
+        [
+            should_produce_valid_btree(Btree1, KeyValues),
+            should_not_be_empty(Btree1)
+        ]
+    }.
+
+should_continuously_remove_keys(KeyValues, {_, Btree}) ->
+    {ok, Btree1} = couch_btree:add_remove(Btree, KeyValues, []),
+    {Btree2, _} = lists:foldl(
+        fun({K, _}, {BtAcc, PrevSize}) ->
+            {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [], [K]),
+            ?assert(couch_btree:size(BtAcc2) < PrevSize),
+            {BtAcc2, couch_btree:size(BtAcc2)}
+        end, {Btree1, couch_btree:size(Btree1)}, KeyValues),
+    {
+        "Should continuously remove keys from btree",
+        [
+            should_produce_valid_btree(Btree2, []),
+            should_be_empty(Btree2)
+        ]
+    }.
+
+should_insert_keys_in_reversed_order(KeyValues, {_, Btree}) ->
+    KeyValuesRev = lists:reverse(KeyValues),
+    {Btree1, _} = lists:foldl(
+        fun(KV, {BtAcc, PrevSize}) ->
+            {ok, BtAcc2} = couch_btree:add_remove(BtAcc, [KV], []),
+            ?assert(couch_btree:size(BtAcc2) > PrevSize),
+            {BtAcc2, couch_btree:size(BtAcc2)}
+        end, {Btree, couch_btree:size(Btree)}, KeyValuesRev),
+    should_produce_valid_btree(Btree1, KeyValues).
+
+should_add_every_odd_key_remove_every_even(KeyValues, {_, Btree}) ->
+    {ok, Btree1} = couch_btree:add_remove(Btree, KeyValues, []),
+    {_, 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),
+    ?_assert(test_add_remove(Btree1, Rem2Keys0, Rem2Keys1)).
+
+should_add_every_even_key_remove_every_old(KeyValues, {_, Btree}) ->
+    {ok, Btree1} = couch_btree:add_remove(Btree, KeyValues, []),
+    {_, 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),
+    ?_assert(test_add_remove(Btree1, Rem2Keys1, Rem2Keys0)).
+
+
+should_reduce_without_specified_direction({_, Btree}) ->
+    ?_assertMatch(
+        {ok, [{{"odd", _}, ?ROWS div 2}, {{"even", _}, ?ROWS div 2}]},
+        fold_reduce(Btree, [])).
+
+should_reduce_forward({_, Btree}) ->
+    ?_assertMatch(
+        {ok, [{{"odd", _}, ?ROWS div 2}, {{"even", _}, ?ROWS div 2}]},
+        fold_reduce(Btree, [{dir, fwd}])).
+
+should_reduce_backward({_, Btree}) ->
+    ?_assertMatch(
+        {ok, [{{"even", _}, ?ROWS div 2}, {{"odd", _}, ?ROWS div 2}]},
+        fold_reduce(Btree, [{dir, rev}])).
+
+should_reduce_whole_range(fwd, {_, Btree}) ->
+    {SK, EK} = {{"even", 0}, {"odd", ?ROWS - 1}},
+    [
+        {
+            "include endkey",
+            ?_assertMatch(
+                {ok, [{{"odd", 1}, ?ROWS div 2},
+                      {{"even", 2}, ?ROWS div 2}]},
+                fold_reduce(Btree, [{dir, fwd},
+                                    {start_key, SK},
+                                    {end_key, EK}]))
+        },
+        {
+            "exclude endkey",
+            ?_assertMatch(
+                {ok, [{{"odd", 1}, (?ROWS div 2) - 1},
+                      {{"even", 2}, ?ROWS div 2}]},
+                fold_reduce(Btree, [{dir, fwd},
+                                    {start_key, SK},
+                                    {end_key_gt, EK}]))
+        }
+    ];
+should_reduce_whole_range(rev, {_, Btree}) ->
+    {SK, EK} = {{"odd", ?ROWS - 1}, {"even", 2}},
+    [
+        {
+            "include endkey",
+            ?_assertMatch(
+                {ok, [{{"even", ?ROWS}, ?ROWS div 2},
+                      {{"odd", ?ROWS - 1}, ?ROWS div 2}]},
+                fold_reduce(Btree, [{dir, rev},
+                                    {start_key, SK},
+                                    {end_key, EK}]))
+        },
+        {
+            "exclude endkey",
+            ?_assertMatch(
+                {ok, [{{"even", ?ROWS}, (?ROWS div 2) - 1},
+                      {{"odd", ?ROWS - 1}, ?ROWS div 2}]},
+                fold_reduce(Btree, [{dir, rev},
+                                    {start_key, SK},
+                                    {end_key_gt, EK}]))
+        }
+    ].
+
+should_reduce_first_half(fwd, {_, Btree}) ->
+    {SK, EK} = {{"even", 0}, {"odd", (?ROWS div 2) - 1}},
+    [
+        {
+            "include endkey",
+            ?_assertMatch(
+                {ok, [{{"odd", 1}, ?ROWS div 4},
+                      {{"even", 2}, ?ROWS div 2}]},
+                fold_reduce(Btree, [{dir, fwd},
+                                    {start_key, SK}, {end_key, EK}]))
+        },
+        {
+            "exclude endkey",
+            ?_assertMatch(
+                {ok, [{{"odd", 1}, (?ROWS div 4) - 1},
+                      {{"even", 2}, ?ROWS div 2}]},
+                fold_reduce(Btree, [{dir, fwd},
+                                    {start_key, SK},
+                                    {end_key_gt, EK}]))
+        }
+    ];
+should_reduce_first_half(rev, {_, Btree}) ->
+    {SK, EK} = {{"odd", ?ROWS - 1}, {"even", ?ROWS div 2}},
+    [
+        {
+            "include endkey",
+            ?_assertMatch(
+                {ok, [{{"even", ?ROWS}, (?ROWS div 4) + 1},
+                      {{"odd", ?ROWS - 1}, ?ROWS div 2}]},
+                fold_reduce(Btree, [{dir, rev},
+                                    {start_key, SK},
+                                    {end_key, EK}]))
+        },
+        {
+            "exclude endkey",
+            ?_assertMatch(
+                {ok, [{{"even", ?ROWS}, ?ROWS div 4},
+                      {{"odd", ?ROWS - 1}, ?ROWS div 2}]},
+                fold_reduce(Btree, [{dir, rev},
+                                    {start_key, SK},
+                                    {end_key_gt, EK}]))
+        }
+    ].
+
+should_reduce_second_half(fwd, {_, Btree}) ->
+    {SK, EK} = {{"even", ?ROWS div 2}, {"odd", ?ROWS - 1}},
+    [
+        {
+            "include endkey",
+            ?_assertMatch(
+                {ok, [{{"odd", 1}, ?ROWS div 2},
+                      {{"even", ?ROWS div 2}, (?ROWS div 4) + 1}]},
+                fold_reduce(Btree, [{dir, fwd},
+                                    {start_key, SK},
+                                    {end_key, EK}]))
+        },
+        {
+            "exclude endkey",
+            ?_assertMatch(
+                {ok, [{{"odd", 1}, (?ROWS div 2) - 1},
+                      {{"even", ?ROWS div 2}, (?ROWS div 4) + 1}]},
+                fold_reduce(Btree, [{dir, fwd},
+                                    {start_key, SK},
+                                    {end_key_gt, EK}]))
+        }
+    ];
+should_reduce_second_half(rev, {_, Btree}) ->
+    {SK, EK} = {{"odd", (?ROWS div 2) + 1}, {"even", 2}},
+    [
+        {
+            "include endkey",
+            ?_assertMatch(
+                {ok, [{{"even", ?ROWS}, ?ROWS div 2},
+                      {{"odd", (?ROWS div 2) + 1}, (?ROWS div 4) + 1}]},
+                fold_reduce(Btree, [{dir, rev},
+                                    {start_key, SK},
+                                    {end_key, EK}]))
+        },
+        {
+            "exclude endkey",
+            ?_assertMatch(
+                {ok, [{{"even", ?ROWS}, (?ROWS div 2) - 1},
+                      {{"odd", (?ROWS div 2) + 1}, (?ROWS div 4) + 1}]},
+                fold_reduce(Btree, [{dir, rev},
+                                    {start_key, SK},
+                                    {end_key_gt, EK}]))
+        }
+    ].
+
+should_produce_valid_btree(Btree, KeyValues) ->
+    ?_assert(test_btree(Btree, KeyValues)).
+
+should_be_empty(Btree) ->
+    ?_assertEqual(couch_btree:size(Btree), 0).
+
+should_not_be_empty(Btree) ->
+    ?_assert(couch_btree:size(Btree) > 0).
+
+fold_reduce(Btree, Opts) ->
+    GroupFun = fun({K1, _}, {K2, _}) ->
+        K1 == K2
+    end,
+    FoldFun = fun(GroupedKey, Unreduced, Acc) ->
+        {ok, [{GroupedKey, couch_btree:final_reduce(Btree, Unreduced)} | Acc]}
+    end,
+    couch_btree:fold_reduce(Btree, FoldFun, [],
+                            [{key_group_fun, GroupFun}] ++ Opts).
+
+
+keys(KVs) ->
+    [K || {K, _} <- KVs].
+
+reduce_fun(reduce, KVs) ->
+    length(KVs);
+reduce_fun(rereduce, Reds) ->
+    lists:sum(Reds).
+
+
+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.
+
+test_btree(Btree, KeyValues) ->
+    ok = test_key_access(Btree, KeyValues),
+    ok = test_lookup_access(Btree, KeyValues),
+    ok = test_final_reductions(Btree, KeyValues),
+    ok = test_traversal_callbacks(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.
+
+test_traversal_callbacks(Btree, _KeyValues) ->
+    FoldFun = fun
+        (visit, _GroupedKey, _Unreduced, Acc) ->
+            {ok, Acc andalso false};
+        (traverse, _LK, _Red, Acc) ->
+            {skip, Acc andalso true}
+    end,
+    % With 250 items the root is a kp. Always skipping should reduce to true.
+    {ok, _, true} = couch_btree:fold(Btree, FoldFun, true, [{dir, fwd}]),
+    ok.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_changes_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_changes_tests.erl b/test/couch_changes_tests.erl
new file mode 100644
index 0000000..a129ba2
--- /dev/null
+++ b/test/couch_changes_tests.erl
@@ -0,0 +1,612 @@
+% 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(couch_changes_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(ADMIN_USER, {user_ctx, #user_ctx{roles = [<<"_admin">>]}}).
+-define(TIMEOUT, 3000).
+-define(TEST_TIMEOUT, 10000).
+
+-record(row, {
+    id,
+    seq,
+    deleted = false
+}).
+
+
+start() ->
+    {ok, Pid} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    Pid.
+
+stop(Pid) ->
+    erlang:monitor(process, Pid),
+    couch_server_sup:stop(),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout, server_stop})
+    end.
+
+setup() ->
+    DbName = ?tempdb(),
+    {ok, Db} = create_db(DbName),
+    Revs = [R || {ok, R} <- [
+        save_doc(Db, {[{<<"_id">>, <<"doc1">>}]}),
+        save_doc(Db, {[{<<"_id">>, <<"doc2">>}]}),
+        save_doc(Db, {[{<<"_id">>, <<"doc3">>}]}),
+        save_doc(Db, {[{<<"_id">>, <<"doc4">>}]}),
+        save_doc(Db, {[{<<"_id">>, <<"doc5">>}]})
+    ]],
+    Rev = lists:nth(3, Revs),
+    {ok, Rev1} = save_doc(Db, {[{<<"_id">>, <<"doc3">>}, {<<"_rev">>, Rev}]}),
+    Revs1 = Revs ++ [Rev1],
+    Revs2 = Revs1 ++ [R || {ok, R} <- [
+        save_doc(Db, {[{<<"_id">>, <<"doc6">>}]}),
+        save_doc(Db, {[{<<"_id">>, <<"_design/foo">>}]}),
+        save_doc(Db, {[{<<"_id">>, <<"doc7">>}]}),
+        save_doc(Db, {[{<<"_id">>, <<"doc8">>}]})
+    ]],
+    {DbName, list_to_tuple(Revs2)}.
+
+teardown({DbName, _}) ->
+    delete_db(DbName),
+    ok.
+
+
+changes_test_() ->
+    {
+        "Changes feeed",
+        {
+            setup,
+            fun start/0, fun stop/1,
+            [
+                filter_by_doc_id(),
+                filter_by_design(),
+                continuous_feed(),
+                filter_by_custom_function()
+            ]
+        }
+    }.
+
+filter_by_doc_id() ->
+    {
+        "Filter _doc_id",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_filter_by_specific_doc_ids/1,
+                fun should_filter_by_specific_doc_ids_descending/1,
+                fun should_filter_by_specific_doc_ids_with_since/1,
+                fun should_filter_by_specific_doc_ids_no_result/1,
+                fun should_handle_deleted_docs/1
+            ]
+        }
+    }.
+
+filter_by_design() ->
+    {
+        "Filter _design",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_emit_only_design_documents/1
+            ]
+        }
+    }.
+
+filter_by_custom_function() ->
+    {
+        "Filter function",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_receive_heartbeats/1
+            ]
+        }
+    }.
+
+continuous_feed() ->
+    {
+        "Continuous Feed",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                fun should_filter_continuous_feed_by_specific_doc_ids/1
+            ]
+        }
+    }.
+
+
+should_filter_by_specific_doc_ids({DbName, _}) ->
+    ?_test(
+        begin
+            ChangesArgs = #changes_args{
+                filter = "_doc_ids"
+            },
+            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+
+            {Rows, LastSeq} = wait_finished(Consumer),
+            {ok, Db} = couch_db:open_int(DbName, []),
+            UpSeq = couch_db:get_update_seq(Db),
+            couch_db:close(Db),
+            stop_consumer(Consumer),
+
+            ?assertEqual(2, length(Rows)),
+            [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
+            ?assertEqual(<<"doc4">>, Id1),
+            ?assertEqual(4, Seq1),
+            ?assertEqual(<<"doc3">>, Id2),
+            ?assertEqual(6, Seq2),
+            ?assertEqual(UpSeq, LastSeq)
+        end).
+
+should_filter_by_specific_doc_ids_descending({DbName, _}) ->
+    ?_test(
+        begin
+            ChangesArgs = #changes_args{
+                filter = "_doc_ids",
+                dir = rev
+            },
+            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+
+            {Rows, LastSeq} = wait_finished(Consumer),
+            {ok, Db} = couch_db:open_int(DbName, []),
+            couch_db:close(Db),
+            stop_consumer(Consumer),
+
+            ?assertEqual(2, length(Rows)),
+            [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
+            ?assertEqual(<<"doc3">>, Id1),
+            ?assertEqual(6, Seq1),
+            ?assertEqual(<<"doc4">>, Id2),
+            ?assertEqual(4, Seq2),
+            ?assertEqual(4, LastSeq)
+        end).
+
+should_filter_by_specific_doc_ids_with_since({DbName, _}) ->
+    ?_test(
+        begin
+            ChangesArgs = #changes_args{
+                filter = "_doc_ids",
+                since = 5
+            },
+            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+
+            {Rows, LastSeq} = wait_finished(Consumer),
+            {ok, Db} = couch_db:open_int(DbName, []),
+            UpSeq = couch_db:get_update_seq(Db),
+            couch_db:close(Db),
+            stop_consumer(Consumer),
+
+            ?assertEqual(1, length(Rows)),
+            [#row{seq = Seq1, id = Id1}] = Rows,
+            ?assertEqual(<<"doc3">>, Id1),
+            ?assertEqual(6, Seq1),
+            ?assertEqual(UpSeq, LastSeq)
+        end).
+
+should_filter_by_specific_doc_ids_no_result({DbName, _}) ->
+    ?_test(
+        begin
+            ChangesArgs = #changes_args{
+                filter = "_doc_ids",
+                since = 6
+            },
+            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+
+            {Rows, LastSeq} = wait_finished(Consumer),
+            {ok, Db} = couch_db:open_int(DbName, []),
+            UpSeq = couch_db:get_update_seq(Db),
+            couch_db:close(Db),
+            stop_consumer(Consumer),
+
+            ?assertEqual(0, length(Rows)),
+            ?assertEqual(UpSeq, LastSeq)
+        end).
+
+should_handle_deleted_docs({DbName, Revs}) ->
+    ?_test(
+        begin
+            Rev3_2 = element(6, Revs),
+            {ok, Db} = couch_db:open_int(DbName, []),
+            {ok, _} = save_doc(
+                Db,
+                {[{<<"_id">>, <<"doc3">>},
+                  {<<"_deleted">>, true},
+                  {<<"_rev">>, Rev3_2}]}),
+
+            ChangesArgs = #changes_args{
+                filter = "_doc_ids",
+                since = 9
+            },
+            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+
+            {Rows, LastSeq} = wait_finished(Consumer),
+            couch_db:close(Db),
+            stop_consumer(Consumer),
+
+            ?assertEqual(1, length(Rows)),
+            ?assertMatch(
+                [#row{seq = LastSeq, id = <<"doc3">>, deleted = true}],
+                Rows
+            ),
+            ?assertEqual(11, LastSeq)
+        end).
+
+should_filter_continuous_feed_by_specific_doc_ids({DbName, Revs}) ->
+    ?_test(
+        begin
+            {ok, Db} = couch_db:open_int(DbName, []),
+            ChangesArgs = #changes_args{
+                filter = "_doc_ids",
+                feed = "continuous"
+            },
+            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
+            pause(Consumer),
+
+            Rows = get_rows(Consumer),
+            ?assertEqual(2, length(Rows)),
+            [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
+            ?assertEqual(<<"doc4">>, Id1),
+            ?assertEqual(4, Seq1),
+            ?assertEqual(<<"doc3">>, Id2),
+            ?assertEqual(6, Seq2),
+
+            clear_rows(Consumer),
+            {ok, _Rev9} = save_doc(Db, {[{<<"_id">>, <<"doc9">>}]}),
+            {ok, _Rev10} = save_doc(Db, {[{<<"_id">>, <<"doc10">>}]}),
+            unpause(Consumer),
+            pause(Consumer),
+            ?assertEqual([], get_rows(Consumer)),
+
+            Rev4 = element(4, Revs),
+            Rev3_2 = element(6, Revs),
+            {ok, Rev4_2} = save_doc(Db, {[{<<"_id">>, <<"doc4">>},
+                                          {<<"_rev">>, Rev4}]}),
+            {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc11">>}]}),
+            {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc4">>},
+                                     {<<"_rev">>, Rev4_2}]}),
+            {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc12">>}]}),
+            {ok, Rev3_3} = save_doc(Db, {[{<<"_id">>, <<"doc3">>},
+                                          {<<"_rev">>, Rev3_2}]}),
+            unpause(Consumer),
+            pause(Consumer),
+
+            NewRows = get_rows(Consumer),
+            ?assertEqual(2, length(NewRows)),
+            [Row14, Row16] = NewRows,
+            ?assertEqual(<<"doc4">>, Row14#row.id),
+            ?assertEqual(15, Row14#row.seq),
+            ?assertEqual(<<"doc3">>, Row16#row.id),
+            ?assertEqual(17, Row16#row.seq),
+
+            clear_rows(Consumer),
+            {ok, _Rev3_4} = save_doc(Db, {[{<<"_id">>, <<"doc3">>},
+                                           {<<"_rev">>, Rev3_3}]}),
+            unpause(Consumer),
+            pause(Consumer),
+
+            FinalRows = get_rows(Consumer),
+
+            unpause(Consumer),
+            stop_consumer(Consumer),
+
+            ?assertMatch([#row{seq = 18, id = <<"doc3">>}], FinalRows)
+        end).
+
+should_emit_only_design_documents({DbName, Revs}) ->
+    ?_test(
+        begin
+            ChangesArgs = #changes_args{
+                filter = "_design"
+            },
+            Consumer = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
+
+            {Rows, LastSeq} = wait_finished(Consumer),
+            {ok, Db} = couch_db:open_int(DbName, []),
+            UpSeq = couch_db:get_update_seq(Db),
+            couch_db:close(Db),
+
+            ?assertEqual(1, length(Rows)),
+            ?assertEqual(UpSeq, LastSeq),
+            ?assertEqual([#row{seq = 8, id = <<"_design/foo">>}], Rows),
+
+            stop_consumer(Consumer),
+
+            {ok, Db2} = couch_db:open_int(DbName, [?ADMIN_USER]),
+            {ok, _} = save_doc(Db2, {[{<<"_id">>, <<"_design/foo">>},
+                                      {<<"_rev">>, element(8, Revs)},
+                                      {<<"_deleted">>, true}]}),
+
+            Consumer2 = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
+
+            {Rows2, LastSeq2} = wait_finished(Consumer2),
+            UpSeq2 = UpSeq + 1,
+            couch_db:close(Db2),
+
+            ?assertEqual(1, length(Rows2)),
+            ?assertEqual(UpSeq2, LastSeq2),
+            ?assertEqual([#row{seq = 11,
+                               id = <<"_design/foo">>,
+                               deleted = true}],
+                          Rows2)
+        end).
+
+should_receive_heartbeats(_) ->
+    {timeout, ?TEST_TIMEOUT div 1000,
+     ?_test(
+         begin
+             DbName = ?tempdb(),
+             Timeout = 100,
+             {ok, Db} = create_db(DbName),
+
+             {ok, _} = save_doc(Db, {[
+                 {<<"_id">>, <<"_design/filtered">>},
+                 {<<"language">>, <<"javascript">>},
+                     {<<"filters">>, {[
+                         {<<"foo">>, <<"function(doc) {
+                             return ['doc10', 'doc11', 'doc12'].indexOf(doc._id) != -1;}">>
+                     }]}}
+             ]}),
+
+             ChangesArgs = #changes_args{
+                 filter = "filtered/foo",
+                 feed = "continuous",
+                 timeout = 10000,
+                 heartbeat = 1000
+             },
+             Consumer = spawn_consumer(DbName, ChangesArgs, {json_req, null}),
+
+             {ok, _Rev1} = save_doc(Db, {[{<<"_id">>, <<"doc1">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev2} = save_doc(Db, {[{<<"_id">>, <<"doc2">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev3} = save_doc(Db, {[{<<"_id">>, <<"doc3">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev4} = save_doc(Db, {[{<<"_id">>, <<"doc4">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev5} = save_doc(Db, {[{<<"_id">>, <<"doc5">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev6} = save_doc(Db, {[{<<"_id">>, <<"doc6">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev7} = save_doc(Db, {[{<<"_id">>, <<"doc7">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev8} = save_doc(Db, {[{<<"_id">>, <<"doc8">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev9} = save_doc(Db, {[{<<"_id">>, <<"doc9">>}]}),
+
+             Heartbeats = get_heartbeats(Consumer),
+             ?assert(Heartbeats > 0),
+
+             {ok, _Rev10} = save_doc(Db, {[{<<"_id">>, <<"doc10">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev11} = save_doc(Db, {[{<<"_id">>, <<"doc11">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev12} = save_doc(Db, {[{<<"_id">>, <<"doc12">>}]}),
+
+             Heartbeats2 = get_heartbeats(Consumer),
+             ?assert(Heartbeats2 > Heartbeats),
+
+             Rows = get_rows(Consumer),
+             ?assertEqual(3, length(Rows)),
+
+             {ok, _Rev13} = save_doc(Db, {[{<<"_id">>, <<"doc13">>}]}),
+             timer:sleep(Timeout),
+             {ok, _Rev14} = save_doc(Db, {[{<<"_id">>, <<"doc14">>}]}),
+             timer:sleep(Timeout),
+
+             Heartbeats3 = get_heartbeats(Consumer),
+             ?assert(Heartbeats3 > Heartbeats2)
+        end)}.
+
+
+save_doc(Db, Json) ->
+    Doc = couch_doc:from_json_obj(Json),
+    {ok, Rev} = couch_db:update_doc(Db, Doc, []),
+    {ok, couch_doc:rev_to_str(Rev)}.
+
+get_rows(Consumer) ->
+    Ref = make_ref(),
+    Consumer ! {get_rows, Ref},
+    Resp = receive
+        {rows, Ref, Rows} ->
+            Rows
+    after ?TIMEOUT ->
+        timeout
+    end,
+    ?assertNotEqual(timeout, Resp),
+    Resp.
+
+get_heartbeats(Consumer) ->
+    Ref = make_ref(),
+    Consumer ! {get_heartbeats, Ref},
+    Resp = receive
+        {hearthbeats, Ref, HeartBeats} ->
+            HeartBeats
+    after ?TIMEOUT ->
+        timeout
+    end,
+    ?assertNotEqual(timeout, Resp),
+    Resp.
+
+clear_rows(Consumer) ->
+    Ref = make_ref(),
+    Consumer ! {reset, Ref},
+    Resp = receive
+        {ok, Ref} ->
+            ok
+    after ?TIMEOUT ->
+        timeout
+    end,
+    ?assertNotEqual(timeout, Resp),
+    Resp.
+
+stop_consumer(Consumer) ->
+    Ref = make_ref(),
+    Consumer ! {stop, Ref},
+    Resp = receive
+        {ok, Ref} ->
+            ok
+    after ?TIMEOUT ->
+        timeout
+    end,
+    ?assertNotEqual(timeout, Resp),
+    Resp.
+
+pause(Consumer) ->
+    Ref = make_ref(),
+    Consumer ! {pause, Ref},
+    Resp = receive
+        {paused, Ref} ->
+            ok
+    after ?TIMEOUT ->
+        timeout
+    end,
+    ?assertNotEqual(timeout, Resp),
+    Resp.
+
+unpause(Consumer) ->
+    Ref = make_ref(),
+    Consumer ! {continue, Ref},
+    Resp = receive
+        {ok, Ref} ->
+            ok
+    after ?TIMEOUT ->
+       timeout
+    end,
+    ?assertNotEqual(timeout, Resp),
+    Resp.
+
+wait_finished(_Consumer) ->
+    Resp = receive
+        {consumer_finished, Rows, LastSeq} ->
+            {Rows, LastSeq}
+    after ?TIMEOUT ->
+        timeout
+    end,
+    ?assertNotEqual(timeout, Resp),
+    Resp.
+
+spawn_consumer(DbName, ChangesArgs0, Req) ->
+    Parent = self(),
+    spawn(fun() ->
+        put(heartbeat_count, 0),
+        Callback = fun
+            ({change, {Change}, _}, _, Acc) ->
+                Id = couch_util:get_value(<<"id">>, Change),
+                Seq = couch_util:get_value(<<"seq">>, Change),
+                Del = couch_util:get_value(<<"deleted">>, Change, false),
+                [#row{id = Id, seq = Seq, deleted = Del} | Acc];
+            ({stop, LastSeq}, _, Acc) ->
+                Parent ! {consumer_finished, lists:reverse(Acc), LastSeq},
+                stop_loop(Parent, Acc);
+            (timeout, _, Acc) ->
+                put(heartbeat_count, get(heartbeat_count) + 1),
+                maybe_pause(Parent, Acc);
+            (_, _, Acc) ->
+                maybe_pause(Parent, Acc)
+        end,
+        {ok, Db} = couch_db:open_int(DbName, []),
+        ChangesArgs = case (ChangesArgs0#changes_args.timeout =:= undefined)
+            andalso (ChangesArgs0#changes_args.heartbeat =:= undefined) of
+            true ->
+                ChangesArgs0#changes_args{timeout = 10, heartbeat = 10};
+            false ->
+                ChangesArgs0
+        end,
+        FeedFun = couch_changes:handle_changes(ChangesArgs, Req, Db),
+        try
+            FeedFun({Callback, []})
+        catch throw:{stop, _} ->
+            ok
+        end,
+        catch couch_db:close(Db)
+    end).
+
+maybe_pause(Parent, Acc) ->
+    receive
+        {get_rows, Ref} ->
+            Parent ! {rows, Ref, lists:reverse(Acc)},
+            maybe_pause(Parent, Acc);
+        {get_heartbeats, Ref} ->
+            Parent ! {hearthbeats, Ref, get(heartbeat_count)},
+            maybe_pause(Parent, Acc);
+        {reset, Ref} ->
+            Parent ! {ok, Ref},
+            maybe_pause(Parent, []);
+        {pause, Ref} ->
+            Parent ! {paused, Ref},
+            pause_loop(Parent, Acc);
+        {stop, Ref} ->
+            Parent ! {ok, Ref},
+            throw({stop, Acc});
+        V ->
+            erlang:error({assertion_failed,
+                      [{module, ?MODULE},
+                       {line, ?LINE},
+                       {value, V},
+                       {reason, "Received unexpected message"}]})
+    after 0 ->
+        Acc
+    end.
+
+pause_loop(Parent, Acc) ->
+    receive
+        {stop, Ref} ->
+            Parent ! {ok, Ref},
+            throw({stop, Acc});
+        {reset, Ref} ->
+            Parent ! {ok, Ref},
+            pause_loop(Parent, []);
+        {continue, Ref} ->
+            Parent ! {ok, Ref},
+            Acc;
+        {get_rows, Ref} ->
+            Parent ! {rows, Ref, lists:reverse(Acc)},
+            pause_loop(Parent, Acc)
+    end.
+
+stop_loop(Parent, Acc) ->
+    receive
+        {get_rows, Ref} ->
+            Parent ! {rows, Ref, lists:reverse(Acc)},
+            stop_loop(Parent, Acc);
+        {stop, Ref} ->
+            Parent ! {ok, Ref},
+            Acc
+    end.
+
+create_db(DbName) ->
+    couch_db:create(DbName, [?ADMIN_USER, overwrite]).
+
+delete_db(DbName) ->
+    ok = couch_server:delete(DbName, [?ADMIN_USER]).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_config_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_config_tests.erl b/test/couch_config_tests.erl
new file mode 100644
index 0000000..9e9dfe7
--- /dev/null
+++ b/test/couch_config_tests.erl
@@ -0,0 +1,463 @@
+% 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(couch_config_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+-define(SHORT_TIMEOUT, 100).
+-define(TIMEOUT, 1000).
+
+-define(CONFIG_DEFAULT,
+        filename:join([?BUILDDIR, "etc", "couchdb", "default_dev.ini"])).
+-define(CONFIG_FIXTURE_1,
+        filename:join([?FIXTURESDIR, "couch_config_tests_1.ini"])).
+-define(CONFIG_FIXTURE_2,
+        filename:join([?FIXTURESDIR, "couch_config_tests_2.ini"])).
+-define(CONFIG_FIXTURE_TEMP,
+    begin
+        FileName = filename:join([?TEMPDIR, "couch_config_temp.ini"]),
+        {ok, Fd} = file:open(FileName, write),
+        ok = file:truncate(Fd),
+        ok = file:close(Fd),
+        FileName
+    end).
+
+
+setup() ->
+    setup(?CONFIG_CHAIN).
+setup({temporary, Chain}) ->
+    setup(Chain);
+setup({persistent, Chain}) ->
+    setup(lists:append(Chain, [?CONFIG_FIXTURE_TEMP]));
+setup(Chain) ->
+    {ok, Pid} = couch_config:start_link(Chain),
+    Pid.
+
+setup_empty() ->
+    setup([]).
+
+setup_register() ->
+    ConfigPid = setup(),
+    SentinelFunc = fun() ->
+        % Ping/Pong to make sure we wait for this
+        % process to die
+        receive
+            {ping, From} ->
+                From ! pong
+        end
+    end,
+    SentinelPid = spawn(SentinelFunc),
+    {ConfigPid, SentinelPid}.
+
+teardown({ConfigPid, SentinelPid}) ->
+    teardown(ConfigPid),
+    case process_info(SentinelPid) of
+        undefined -> ok;
+        _ ->
+            SentinelPid ! {ping, self()},
+            receive
+                pong ->
+                    ok
+            after 100 ->
+                throw({timeout_error, registered_pid})
+            end
+    end;
+teardown(Pid) ->
+    couch_config:stop(),
+    erlang:monitor(process, Pid),
+    receive
+        {'DOWN', _, _, Pid, _} ->
+            ok
+    after ?TIMEOUT ->
+        throw({timeout_error, config_stop})
+    end.
+teardown(_, Pid) ->
+    teardown(Pid).
+
+
+couch_config_test_() ->
+    {
+        "CouchDB config tests",
+        [
+            couch_config_get_tests(),
+            couch_config_set_tests(),
+            couch_config_del_tests(),
+            config_override_tests(),
+            config_persistent_changes_tests(),
+            config_register_tests(),
+            config_no_files_tests()
+        ]
+    }.
+
+couch_config_get_tests() ->
+    {
+        "Config get tests",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                should_load_all_configs(),
+                should_locate_daemons_section(),
+                should_locate_mrview_handler(),
+                should_return_undefined_atom_on_missed_section(),
+                should_return_undefined_atom_on_missed_option(),
+                should_return_custom_default_value_on_missed_option(),
+                should_only_return_default_on_missed_option(),
+                should_get_binary_option()
+            ]
+        }
+    }.
+
+couch_config_set_tests() ->
+    {
+        "Config set tests",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                should_update_option(),
+                should_create_new_section(),
+                should_set_binary_option()
+            ]
+        }
+    }.
+
+couch_config_del_tests() ->
+    {
+        "Config deletion tests",
+        {
+            foreach,
+            fun setup/0, fun teardown/1,
+            [
+                should_return_undefined_atom_after_option_deletion(),
+                should_be_ok_on_deleting_unknown_options(),
+                should_delete_binary_option()
+            ]
+        }
+    }.
+
+config_override_tests() ->
+    {
+        "Configs overide tests",
+        {
+            foreachx,
+            fun setup/1, fun teardown/2,
+            [
+                {{temporary, [?CONFIG_DEFAULT]},
+                 fun should_ensure_in_defaults/2},
+                {{temporary, [?CONFIG_DEFAULT, ?CONFIG_FIXTURE_1]},
+                 fun should_override_options/2},
+                {{temporary, [?CONFIG_DEFAULT, ?CONFIG_FIXTURE_2]},
+                 fun should_create_new_sections_on_override/2},
+                {{temporary, [?CONFIG_DEFAULT, ?CONFIG_FIXTURE_1,
+                              ?CONFIG_FIXTURE_2]},
+                 fun should_win_last_in_chain/2}
+            ]
+        }
+    }.
+
+config_persistent_changes_tests() ->
+    {
+        "Config persistent changes",
+        {
+            foreachx,
+            fun setup/1, fun teardown/2,
+            [
+                {{persistent, [?CONFIG_DEFAULT]},
+                 fun should_write_changes/2},
+                {{temporary, [?CONFIG_DEFAULT]},
+                 fun should_ensure_that_default_wasnt_modified/2},
+                {{temporary, [?CONFIG_FIXTURE_TEMP]},
+                 fun should_ensure_that_written_to_last_config_in_chain/2}
+            ]
+        }
+    }.
+
+config_register_tests() ->
+    {
+        "Config changes subscriber",
+        {
+            foreach,
+            fun setup_register/0, fun teardown/1,
+            [
+                fun should_handle_port_changes/1,
+                fun should_pass_persistent_flag/1,
+                fun should_not_trigger_handler_on_other_options_changes/1,
+                fun should_not_trigger_handler_after_related_process_death/1
+            ]
+        }
+    }.
+
+config_no_files_tests() ->
+    {
+        "Test couch_config with no files",
+        {
+            foreach,
+            fun setup_empty/0, fun teardown/1,
+            [
+                should_ensure_that_no_ini_files_loaded(),
+                should_create_non_persistent_option(),
+                should_create_persistent_option()
+            ]
+        }
+    }.
+
+
+should_load_all_configs() ->
+    ?_assert(length(couch_config:all()) > 0).
+
+should_locate_daemons_section() ->
+    ?_assert(length(couch_config:get("daemons")) > 0).
+
+should_locate_mrview_handler() ->
+    ?_assertEqual("{couch_mrview_http, handle_view_req}",
+                  couch_config:get("httpd_design_handlers", "_view")).
+
+should_return_undefined_atom_on_missed_section() ->
+    ?_assertEqual(undefined,
+                  couch_config:get("foo", "bar")).
+
+should_return_undefined_atom_on_missed_option() ->
+    ?_assertEqual(undefined,
+                  couch_config:get("httpd", "foo")).
+
+should_return_custom_default_value_on_missed_option() ->
+    ?_assertEqual("bar",
+                  couch_config:get("httpd", "foo", "bar")).
+
+should_only_return_default_on_missed_option() ->
+    ?_assertEqual("0",
+                  couch_config:get("httpd", "port", "bar")).
+
+should_get_binary_option() ->
+    ?_assertEqual(<<"baz">>,
+                  couch_config:get(<<"foo">>, <<"bar">>, <<"baz">>)).
+
+should_update_option() ->
+    ?_assertEqual("severe",
+        begin
+            ok = couch_config:set("log", "level", "severe", false),
+            couch_config:get("log", "level")
+        end).
+
+should_create_new_section() ->
+    ?_assertEqual("bang",
+        begin
+            undefined = couch_config:get("new_section", "bizzle"),
+            ok = couch_config:set("new_section", "bizzle", "bang", false),
+            couch_config:get("new_section", "bizzle")
+        end).
+
+should_set_binary_option() ->
+    ?_assertEqual(<<"baz">>,
+        begin
+            ok = couch_config:set(<<"foo">>, <<"bar">>, <<"baz">>, false),
+            couch_config:get(<<"foo">>, <<"bar">>)
+        end).
+
+should_return_undefined_atom_after_option_deletion() ->
+    ?_assertEqual(undefined,
+        begin
+            ok = couch_config:delete("log", "level", false),
+            couch_config:get("log", "level")
+        end).
+
+should_be_ok_on_deleting_unknown_options() ->
+    ?_assertEqual(ok, couch_config:delete("zoo", "boo", false)).
+
+should_delete_binary_option() ->
+    ?_assertEqual(undefined,
+        begin
+            ok = couch_config:set(<<"foo">>, <<"bar">>, <<"baz">>, false),
+            ok = couch_config:delete(<<"foo">>, <<"bar">>, false),
+            couch_config:get(<<"foo">>, <<"bar">>)
+        end).
+
+should_ensure_in_defaults(_, _) ->
+    ?_test(begin
+        ?assertEqual("100",
+                     couch_config:get("couchdb", "max_dbs_open")),
+        ?assertEqual("5984",
+                     couch_config:get("httpd", "port")),
+        ?assertEqual(undefined,
+                     couch_config:get("fizbang", "unicode"))
+    end).
+
+should_override_options(_, _) ->
+    ?_test(begin
+        ?assertEqual("10",
+                     couch_config:get("couchdb", "max_dbs_open")),
+        ?assertEqual("4895",
+                     couch_config:get("httpd", "port"))
+    end).
+
+should_create_new_sections_on_override(_, _) ->
+    ?_test(begin
+        ?assertEqual("80",
+                     couch_config:get("httpd", "port")),
+        ?assertEqual("normalized",
+                     couch_config:get("fizbang", "unicode"))
+    end).
+
+should_win_last_in_chain(_, _) ->
+    ?_assertEqual("80", couch_config:get("httpd", "port")).
+
+should_write_changes(_, _) ->
+    ?_test(begin
+        ?assertEqual("5984",
+                     couch_config:get("httpd", "port")),
+        ?assertEqual(ok,
+                     couch_config:set("httpd", "port", "8080")),
+        ?assertEqual("8080",
+                     couch_config:get("httpd", "port")),
+        ?assertEqual(ok,
+                     couch_config:delete("httpd", "bind_address", "8080")),
+        ?assertEqual(undefined,
+                     couch_config:get("httpd", "bind_address"))
+    end).
+
+should_ensure_that_default_wasnt_modified(_, _) ->
+    ?_test(begin
+        ?assertEqual("5984",
+                     couch_config:get("httpd", "port")),
+        ?assertEqual("127.0.0.1",
+                     couch_config:get("httpd", "bind_address"))
+    end).
+
+should_ensure_that_written_to_last_config_in_chain(_, _) ->
+    ?_test(begin
+        ?assertEqual("8080",
+                     couch_config:get("httpd", "port")),
+        ?assertEqual(undefined,
+                     couch_config:get("httpd", "bind_address"))
+    end).
+
+should_handle_port_changes({_, SentinelPid}) ->
+    ?_assert(begin
+        MainProc = self(),
+        Port = "8080",
+
+        couch_config:register(
+            fun("httpd", "port", Value) ->
+                % couch_config catches every error raised from handler
+                % so it's not possible to just assert on wrong value.
+                % We have to return the result as message
+                MainProc ! (Value =:= Port)
+            end,
+            SentinelPid
+        ),
+        ok = couch_config:set("httpd", "port", Port, false),
+
+        receive
+            R ->
+                R
+        after ?TIMEOUT ->
+             erlang:error({assertion_failed,
+                           [{module, ?MODULE},
+                            {line, ?LINE},
+                            {reason, "Timeout"}]})
+        end
+    end).
+
+should_pass_persistent_flag({_, SentinelPid}) ->
+    ?_assert(begin
+        MainProc = self(),
+
+        couch_config:register(
+            fun("httpd", "port", _, Persist) ->
+                % couch_config catches every error raised from handler
+                % so it's not possible to just assert on wrong value.
+                % We have to return the result as message
+                MainProc ! Persist
+            end,
+            SentinelPid
+        ),
+        ok = couch_config:set("httpd", "port", "8080", false),
+
+        receive
+            false ->
+                true
+        after ?SHORT_TIMEOUT ->
+            false
+        end
+    end).
+
+should_not_trigger_handler_on_other_options_changes({_, SentinelPid}) ->
+    ?_assert(begin
+        MainProc = self(),
+
+        couch_config:register(
+            fun("httpd", "port", _) ->
+                MainProc ! ok
+            end,
+            SentinelPid
+        ),
+        ok = couch_config:set("httpd", "bind_address", "0.0.0.0", false),
+
+        receive
+            ok ->
+                false
+        after ?SHORT_TIMEOUT ->
+            true
+        end
+    end).
+
+should_not_trigger_handler_after_related_process_death({_, SentinelPid}) ->
+    ?_assert(begin
+        MainProc = self(),
+
+        couch_config:register(
+            fun("httpd", "port", _) ->
+                MainProc ! ok
+            end,
+            SentinelPid
+        ),
+
+        SentinelPid ! {ping, MainProc},
+        receive
+            pong ->
+                ok
+        after ?SHORT_TIMEOUT ->
+             erlang:error({assertion_failed,
+                           [{module, ?MODULE},
+                            {line, ?LINE},
+                            {reason, "Timeout"}]})
+        end,
+
+        ok = couch_config:set("httpd", "port", "12345", false),
+
+        receive
+            ok ->
+                false
+        after ?SHORT_TIMEOUT ->
+            true
+        end
+    end).
+
+should_ensure_that_no_ini_files_loaded() ->
+    ?_assertEqual(0, length(couch_config:all())).
+
+should_create_non_persistent_option() ->
+    ?_assertEqual("80",
+        begin
+            ok = couch_config:set("httpd", "port", "80", false),
+            couch_config:get("httpd", "port")
+        end).
+
+should_create_persistent_option() ->
+    ?_assertEqual("127.0.0.1",
+        begin
+            ok = couch_config:set("httpd", "bind_address", "127.0.0.1"),
+            couch_config:get("httpd", "bind_address")
+        end).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_db_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_db_tests.erl b/test/couch_db_tests.erl
new file mode 100644
index 0000000..3089714
--- /dev/null
+++ b/test/couch_db_tests.erl
@@ -0,0 +1,114 @@
+% 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(couch_db_tests).
+
+-include("couch_eunit.hrl").
+
+-define(TIMEOUT, 120).
+
+
+setup() ->
+    {ok, _} = couch_server_sup:start_link(?CONFIG_CHAIN),
+    couch_config:set("log", "include_sasl", "false", false),
+    ok.
+
+teardown(_) ->
+    couch_server_sup:stop().
+
+
+create_delete_db_test_()->
+    {
+        "Database create/delete tests",
+        {
+            setup,
+            fun setup/0, fun teardown/1,
+            fun(_) ->
+                [should_create_db(),
+                 should_delete_db(),
+                 should_create_multiple_dbs(),
+                 should_delete_multiple_dbs(),
+                 should_create_delete_database_continuously()]
+            end
+        }
+    }.
+
+
+should_create_db() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, []),
+    ok = couch_db:close(Db),
+    {ok, AllDbs} = couch_server:all_databases(),
+    ?_assert(lists:member(DbName, AllDbs)).
+
+should_delete_db() ->
+    DbName = ?tempdb(),
+    couch_db:create(DbName, []),
+    couch_server:delete(DbName, []),
+    {ok, AllDbs} = couch_server:all_databases(),
+    ?_assertNot(lists:member(DbName, AllDbs)).
+
+should_create_multiple_dbs() ->
+    gen_server:call(couch_server, {set_max_dbs_open, 3}),
+
+    DbNames = [?tempdb() || _ <- lists:seq(1, 6)],
+    lists:foreach(fun(DbName) ->
+        {ok, Db} = couch_db:create(DbName, []),
+        ok = couch_db:close(Db)
+    end, DbNames),
+
+    {ok, AllDbs} = couch_server:all_databases(),
+    NumCreated = lists:foldl(fun(DbName, Acc) ->
+        ?assert(lists:member(DbName, AllDbs)),
+        Acc+1
+    end, 0, DbNames),
+
+    ?_assertEqual(NumCreated, 6).
+
+should_delete_multiple_dbs() ->
+    DbNames = [?tempdb() || _ <- lists:seq(1, 6)],
+    lists:foreach(fun(DbName) ->
+        {ok, Db} = couch_db:create(DbName, []),
+        ok = couch_db:close(Db)
+    end, DbNames),
+
+    lists:foreach(fun(DbName) ->
+        ok = couch_server:delete(DbName, [])
+    end, DbNames),
+
+    {ok, AllDbs} = couch_server:all_databases(),
+    NumDeleted = lists:foldl(fun(DbName, Acc) ->
+        ?assertNot(lists:member(DbName, AllDbs)),
+        Acc + 1
+    end, 0, DbNames),
+
+    ?_assertEqual(NumDeleted, 6).
+
+should_create_delete_database_continuously() ->
+    DbName = ?tempdb(),
+    {ok, Db} = couch_db:create(DbName, []),
+    couch_db:close(Db),
+    [{timeout, ?TIMEOUT, {integer_to_list(N) ++ " times",
+                           ?_assert(loop(DbName, N))}}
+     || N <- [10, 100, 1000]].
+
+loop(_, 0) ->
+    true;
+loop(DbName, N) ->
+    ok = cycle(DbName),
+    loop(DbName, N - 1).
+
+cycle(DbName) ->
+    ok = couch_server:delete(DbName, []),
+    {ok, Db} = couch_db:create(DbName, []),
+    couch_db:close(Db),
+    ok.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couch_doc_json_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_doc_json_tests.erl b/test/couch_doc_json_tests.erl
new file mode 100644
index 0000000..1592b6b
--- /dev/null
+++ b/test/couch_doc_json_tests.erl
@@ -0,0 +1,391 @@
+% 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(couch_doc_json_tests).
+
+-include("couch_eunit.hrl").
+-include_lib("couchdb/couch_db.hrl").
+
+
+setup() ->
+    couch_config:start_link(?CONFIG_CHAIN),
+    couch_config:set("attachments", "compression_level", "0", false),
+    ok.
+
+teardown(_) ->
+    couch_config:stop().
+
+
+json_doc_test_() ->
+    {
+        setup,
+        fun setup/0, fun teardown/1,
+        [
+            {
+                "Document from JSON",
+                [
+                    from_json_success_cases(),
+                    from_json_error_cases()
+                ]
+            },
+            {
+                "Document to JSON",
+                [
+                    to_json_success_cases()
+                ]
+            }
+        ]
+    }.
+
+from_json_success_cases() ->
+    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:map(
+        fun({EJson, Expect, Msg}) ->
+            {Msg, ?_assertMatch(Expect, couch_doc:from_json_obj(EJson))}
+        end,
+        Cases).
+
+from_json_error_cases() ->
+    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:map(fun
+        ({EJson, Expect, Msg}) ->
+            Error = (catch couch_doc:from_json_obj(EJson)),
+            {Msg, ?_assertMatch(Expect, Error)};
+        ({EJson, Msg}) ->
+            try
+                couch_doc:from_json_obj(EJson),
+                {"Conversion failed to raise an exception", ?_assert(false)}
+            catch
+                _:_ -> {Msg, ?_assert(true)}
+            end
+    end, Cases).
+
+to_json_success_cases() ->
+    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:map(fun
+        ({Doc, EJson, Msg}) ->
+            {Msg, ?_assertMatch(EJson, couch_doc:to_json_obj(Doc, []))};
+        ({Options, Doc, EJson, Msg}) ->
+            {Msg, ?_assertMatch(EJson, couch_doc:to_json_obj(Doc, Options))}
+    end, Cases).


[35/50] [abbrv] Move files out of test/couchdb into top level test/ folder

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_file_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_file_tests.erl b/test/couchdb/couch_file_tests.erl
deleted file mode 100644
index ad13383..0000000
--- a/test/couchdb/couch_file_tests.erl
+++ /dev/null
@@ -1,265 +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(couch_file_tests).
-
--include("couch_eunit.hrl").
-
--define(BLOCK_SIZE, 4096).
--define(setup(F), {setup, fun setup/0, fun teardown/1, F}).
--define(foreach(Fs), {foreach, fun setup/0, fun teardown/1, Fs}).
-
-
-setup() ->
-    {ok, Fd} = couch_file:open(?tempfile(), [create, overwrite]),
-    Fd.
-
-teardown(Fd) ->
-    ok = couch_file:close(Fd).
-
-
-open_close_test_() ->
-    {
-        "Test for proper file open and close",
-        [
-            should_return_enoent_if_missed(),
-            should_ignore_invalid_flags_with_open(),
-            ?setup(fun should_return_pid_on_file_open/1),
-            should_close_file_properly(),
-            ?setup(fun should_create_empty_new_files/1)
-        ]
-    }.
-
-should_return_enoent_if_missed() ->
-    ?_assertEqual({error, enoent}, couch_file:open("not a real file")).
-
-should_ignore_invalid_flags_with_open() ->
-    ?_assertMatch({ok, _},
-                  couch_file:open(?tempfile(), [create, invalid_option])).
-
-should_return_pid_on_file_open(Fd) ->
-    ?_assert(is_pid(Fd)).
-
-should_close_file_properly() ->
-    {ok, Fd} = couch_file:open(?tempfile(), [create, overwrite]),
-    ok = couch_file:close(Fd),
-    ?_assert(true).
-
-should_create_empty_new_files(Fd) ->
-    ?_assertMatch({ok, 0}, couch_file:bytes(Fd)).
-
-
-read_write_test_() ->
-    {
-        "Common file read/write tests",
-        ?foreach([
-            fun should_increase_file_size_on_write/1,
-            fun should_return_current_file_size_on_write/1,
-            fun should_write_and_read_term/1,
-            fun should_write_and_read_binary/1,
-            fun should_write_and_read_large_binary/1,
-            fun should_return_term_as_binary_for_reading_binary/1,
-            fun should_read_term_written_as_binary/1,
-            fun should_read_iolist/1,
-            fun should_fsync/1,
-            fun should_not_read_beyond_eof/1,
-            fun should_truncate/1
-        ])
-    }.
-
-
-should_increase_file_size_on_write(Fd) ->
-    {ok, 0, _} = couch_file:append_term(Fd, foo),
-    {ok, Size} = couch_file:bytes(Fd),
-    ?_assert(Size > 0).
-
-should_return_current_file_size_on_write(Fd) ->
-    {ok, 0, _} = couch_file:append_term(Fd, foo),
-    {ok, Size} = couch_file:bytes(Fd),
-    ?_assertMatch({ok, Size, _}, couch_file:append_term(Fd, bar)).
-
-should_write_and_read_term(Fd) ->
-    {ok, Pos, _} = couch_file:append_term(Fd, foo),
-    ?_assertMatch({ok, foo}, couch_file:pread_term(Fd, Pos)).
-
-should_write_and_read_binary(Fd) ->
-    {ok, Pos, _} = couch_file:append_binary(Fd, <<"fancy!">>),
-    ?_assertMatch({ok, <<"fancy!">>}, couch_file:pread_binary(Fd, Pos)).
-
-should_return_term_as_binary_for_reading_binary(Fd) ->
-    {ok, Pos, _} = couch_file:append_term(Fd, foo),
-    Foo = couch_compress:compress(foo, snappy),
-    ?_assertMatch({ok, Foo}, couch_file:pread_binary(Fd, Pos)).
-
-should_read_term_written_as_binary(Fd) ->
-    {ok, Pos, _} = couch_file:append_binary(Fd, <<131,100,0,3,102,111,111>>),
-    ?_assertMatch({ok, foo}, couch_file:pread_term(Fd, Pos)).
-
-should_write_and_read_large_binary(Fd) ->
-    BigBin = list_to_binary(lists:duplicate(100000, 0)),
-    {ok, Pos, _} = couch_file:append_binary(Fd, BigBin),
-    ?_assertMatch({ok, BigBin}, couch_file:pread_binary(Fd, Pos)).
-
-should_read_iolist(Fd) ->
-    %% append_binary == append_iolist?
-    %% Possible bug in pread_iolist or iolist() -> append_binary
-    {ok, Pos, _} = couch_file:append_binary(Fd, ["foo", $m, <<"bam">>]),
-    {ok, IoList} = couch_file:pread_iolist(Fd, Pos),
-    ?_assertMatch(<<"foombam">>, iolist_to_binary(IoList)).
-
-should_fsync(Fd) ->
-    {"How does on test fsync?", ?_assertMatch(ok, couch_file:sync(Fd))}.
-
-should_not_read_beyond_eof(_) ->
-    {"No idea how to test reading beyond EOF", ?_assert(true)}.
-
-should_truncate(Fd) ->
-    {ok, 0, _} = couch_file:append_term(Fd, foo),
-    {ok, Size} = couch_file:bytes(Fd),
-    BigBin = list_to_binary(lists:duplicate(100000, 0)),
-    {ok, _, _} = couch_file:append_binary(Fd, BigBin),
-    ok = couch_file:truncate(Fd, Size),
-    ?_assertMatch({ok, foo}, couch_file:pread_term(Fd, 0)).
-
-
-header_test_() ->
-    {
-        "File header read/write tests",
-        [
-            ?foreach([
-                fun should_write_and_read_atom_header/1,
-                fun should_write_and_read_tuple_header/1,
-                fun should_write_and_read_second_header/1,
-                fun should_truncate_second_header/1,
-                fun should_produce_same_file_size_on_rewrite/1,
-                fun should_save_headers_larger_than_block_size/1
-            ]),
-            should_recover_header_marker_corruption(),
-            should_recover_header_size_corruption(),
-            should_recover_header_md5sig_corruption(),
-            should_recover_header_data_corruption()
-        ]
-    }.
-
-
-should_write_and_read_atom_header(Fd) ->
-    ok = couch_file:write_header(Fd, hello),
-    ?_assertMatch({ok, hello}, couch_file:read_header(Fd)).
-
-should_write_and_read_tuple_header(Fd) ->
-    ok = couch_file:write_header(Fd, {<<"some_data">>, 32}),
-    ?_assertMatch({ok, {<<"some_data">>, 32}}, couch_file:read_header(Fd)).
-
-should_write_and_read_second_header(Fd) ->
-    ok = couch_file:write_header(Fd, {<<"some_data">>, 32}),
-    ok = couch_file:write_header(Fd, [foo, <<"more">>]),
-    ?_assertMatch({ok, [foo, <<"more">>]}, couch_file:read_header(Fd)).
-
-should_truncate_second_header(Fd) ->
-    ok = couch_file:write_header(Fd, {<<"some_data">>, 32}),
-    {ok, Size} = couch_file:bytes(Fd),
-    ok = couch_file:write_header(Fd, [foo, <<"more">>]),
-    ok = couch_file:truncate(Fd, Size),
-    ?_assertMatch({ok, {<<"some_data">>, 32}}, couch_file:read_header(Fd)).
-
-should_produce_same_file_size_on_rewrite(Fd) ->
-    ok = couch_file:write_header(Fd, {<<"some_data">>, 32}),
-    {ok, Size1} = couch_file:bytes(Fd),
-    ok = couch_file:write_header(Fd, [foo, <<"more">>]),
-    {ok, Size2} = couch_file:bytes(Fd),
-    ok = couch_file:truncate(Fd, Size1),
-    ok = couch_file:write_header(Fd, [foo, <<"more">>]),
-    ?_assertMatch({ok, Size2}, couch_file:bytes(Fd)).
-
-should_save_headers_larger_than_block_size(Fd) ->
-    Header = erlang:make_tuple(5000, <<"CouchDB">>),
-    couch_file:write_header(Fd, Header),
-    {"COUCHDB-1319", ?_assertMatch({ok, Header}, couch_file:read_header(Fd))}.
-
-
-should_recover_header_marker_corruption() ->
-    ?_assertMatch(
-        ok,
-        check_header_recovery(
-            fun(CouchFd, RawFd, Expect, HeaderPos) ->
-                ?assertNotMatch(Expect, couch_file:read_header(CouchFd)),
-                file:pwrite(RawFd, HeaderPos, <<0>>),
-                ?assertMatch(Expect, couch_file:read_header(CouchFd))
-            end)
-    ).
-
-should_recover_header_size_corruption() ->
-    ?_assertMatch(
-        ok,
-        check_header_recovery(
-            fun(CouchFd, RawFd, Expect, HeaderPos) ->
-                ?assertNotMatch(Expect, couch_file:read_header(CouchFd)),
-                % +1 for 0x1 byte marker
-                file:pwrite(RawFd, HeaderPos + 1, <<10/integer>>),
-                ?assertMatch(Expect, couch_file:read_header(CouchFd))
-            end)
-    ).
-
-should_recover_header_md5sig_corruption() ->
-    ?_assertMatch(
-        ok,
-        check_header_recovery(
-            fun(CouchFd, RawFd, Expect, HeaderPos) ->
-                ?assertNotMatch(Expect, couch_file:read_header(CouchFd)),
-                % +5 = +1 for 0x1 byte and +4 for term size.
-                file:pwrite(RawFd, HeaderPos + 5, <<"F01034F88D320B22">>),
-                ?assertMatch(Expect, couch_file:read_header(CouchFd))
-            end)
-    ).
-
-should_recover_header_data_corruption() ->
-    ?_assertMatch(
-        ok,
-        check_header_recovery(
-            fun(CouchFd, RawFd, Expect, HeaderPos) ->
-                ?assertNotMatch(Expect, couch_file:read_header(CouchFd)),
-                % +21 = +1 for 0x1 byte, +4 for term size and +16 for MD5 sig
-                file:pwrite(RawFd, HeaderPos + 21, <<"some data goes here!">>),
-                ?assertMatch(Expect, couch_file:read_header(CouchFd))
-            end)
-    ).
-
-
-check_header_recovery(CheckFun) ->
-    Path = ?tempfile(),
-    {ok, Fd} = couch_file:open(Path, [create, overwrite]),
-    {ok, RawFd} = file:open(Path, [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 ?BLOCK_SIZE) * ?BLOCK_SIZE};
-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).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_key_tree_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_key_tree_tests.erl b/test/couchdb/couch_key_tree_tests.erl
deleted file mode 100644
index 753ecc4..0000000
--- a/test/couchdb/couch_key_tree_tests.erl
+++ /dev/null
@@ -1,380 +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(couch_key_tree_tests).
-
--include("couch_eunit.hrl").
-
--define(DEPTH, 10).
-
-
-key_tree_merge_test_()->
-    {
-        "Key tree merge",
-        [
-            should_merge_with_empty_tree(),
-            should_merge_reflexive(),
-            should_merge_prefix_of_a_tree_with_tree(),
-            should_produce_conflict_on_merge_with_unrelated_branch(),
-            should_merge_reflexive_for_child_nodes(),
-            should_merge_tree_to_itself(),
-            should_merge_tree_of_odd_length(),
-            should_merge_tree_with_stem(),
-            should_merge_with_stem_at_deeper_level(),
-            should_merge_with_stem_at_deeper_level_with_deeper_paths(),
-            should_merge_single_tree_with_deeper_stem(),
-            should_merge_tree_with_large_stem(),
-            should_merge_stems(),
-            should_create_conflicts_on_merge(),
-            should_create_no_conflicts_on_merge(),
-            should_ignore_conflicting_branch()
-        ]
-    }.
-
-key_tree_missing_leaves_test_()->
-    {
-        "Missing tree leaves",
-        [
-            should_not_find_missing_leaves(),
-            should_find_missing_leaves()
-        ]
-    }.
-
-key_tree_remove_leaves_test_()->
-    {
-        "Remove tree leaves",
-        [
-            should_have_no_effect_on_removing_no_leaves(),
-            should_have_no_effect_on_removing_non_existant_branch(),
-            should_remove_leaf(),
-            should_produce_empty_tree_on_removing_all_leaves(),
-            should_have_no_effect_on_removing_non_existant_node(),
-            should_produce_empty_tree_on_removing_last_leaf()
-        ]
-    }.
-
-key_tree_get_leaves_test_()->
-    {
-        "Leaves retrieving",
-        [
-            should_extract_subtree(),
-            should_extract_subsubtree(),
-            should_gather_non_existant_leaf(),
-            should_gather_leaf(),
-            shoul_gather_multiple_leaves(),
-            should_retrieve_full_key_path(),
-            should_retrieve_full_key_path_for_node(),
-            should_retrieve_leaves_with_parent_node(),
-            should_retrieve_all_leaves()
-        ]
-    }.
-
-key_tree_leaf_counting_test_()->
-    {
-        "Leaf counting",
-        [
-            should_have_no_leaves_for_empty_tree(),
-            should_have_single_leaf_for_tree_with_single_node(),
-            should_have_two_leaves_for_tree_with_chindler_siblings(),
-            should_not_affect_on_leaf_counting_for_stemmed_tree()
-        ]
-    }.
-
-key_tree_stemming_test_()->
-    {
-        "Stemming",
-        [
-            should_have_no_effect_for_stemming_more_levels_than_exists(),
-            should_return_one_deepest_node(),
-            should_return_two_deepest_nodes()
-        ]
-    }.
-
-
-should_merge_with_empty_tree()->
-    One = {1, {"1","foo",[]}},
-    ?_assertEqual({[One], no_conflicts},
-                  couch_key_tree:merge([], One, ?DEPTH)).
-
-should_merge_reflexive()->
-    One = {1, {"1","foo",[]}},
-    ?_assertEqual({[One], no_conflicts},
-                  couch_key_tree:merge([One], One, ?DEPTH)).
-
-should_merge_prefix_of_a_tree_with_tree()->
-    One = {1, {"1","foo",[]}},
-    TwoSibs = [{1, {"1","foo",[]}},
-               {1, {"2","foo",[]}}],
-    ?_assertEqual({TwoSibs, no_conflicts},
-                  couch_key_tree:merge(TwoSibs, One, ?DEPTH)).
-
-should_produce_conflict_on_merge_with_unrelated_branch()->
-    TwoSibs = [{1, {"1","foo",[]}},
-               {1, {"2","foo",[]}}],
-    Three = {1, {"3","foo",[]}},
-    ThreeSibs = [{1, {"1","foo",[]}},
-                 {1, {"2","foo",[]}},
-                 {1, {"3","foo",[]}}],
-    ?_assertEqual({ThreeSibs, conflicts},
-                  couch_key_tree:merge(TwoSibs, Three, ?DEPTH)).
-
-should_merge_reflexive_for_child_nodes()->
-    TwoChild = {1, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}},
-    ?_assertEqual({[TwoChild], no_conflicts},
-                  couch_key_tree:merge([TwoChild], TwoChild, ?DEPTH)).
-
-should_merge_tree_to_itself()->
-    TwoChildSibs = {1, {"1","foo", [{"1a", "bar", []},
-                                    {"1b", "bar", []}]}},
-    ?_assertEqual({[TwoChildSibs], no_conflicts},
-                  couch_key_tree:merge([TwoChildSibs], TwoChildSibs, ?DEPTH)).
-
-should_merge_tree_of_odd_length()->
-    TwoChild = {1, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}},
-    TwoChildSibs = {1, {"1","foo", [{"1a", "bar", []},
-                                    {"1b", "bar", []}]}},
-    TwoChildPlusSibs = {1, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]},
-                                        {"1b", "bar", []}]}},
-
-    ?_assertEqual({[TwoChildPlusSibs], no_conflicts},
-                  couch_key_tree:merge([TwoChild], TwoChildSibs, ?DEPTH)).
-
-should_merge_tree_with_stem()->
-    Stemmed = {2, {"1a", "bar", []}},
-    TwoChildSibs = {1, {"1","foo", [{"1a", "bar", []},
-                                    {"1b", "bar", []}]}},
-
-    ?_assertEqual({[TwoChildSibs], no_conflicts},
-                  couch_key_tree:merge([TwoChildSibs], Stemmed, ?DEPTH)).
-
-should_merge_with_stem_at_deeper_level()->
-    Stemmed = {3, {"1bb", "boo", []}},
-    TwoChildSibs = {1, {"1","foo", [{"1a", "bar", []},
-                                    {"1b", "bar", [{"1bb", "boo", []}]}]}},
-    ?_assertEqual({[TwoChildSibs], no_conflicts},
-                  couch_key_tree:merge([TwoChildSibs], Stemmed, ?DEPTH)).
-
-should_merge_with_stem_at_deeper_level_with_deeper_paths()->
-    Stemmed = {3, {"1bb", "boo", []}},
-    StemmedTwoChildSibs = [{2,{"1a", "bar", []}},
-                           {2,{"1b", "bar", [{"1bb", "boo", []}]}}],
-    ?_assertEqual({StemmedTwoChildSibs, no_conflicts},
-                  couch_key_tree:merge(StemmedTwoChildSibs, Stemmed, ?DEPTH)).
-
-should_merge_single_tree_with_deeper_stem()->
-    Stemmed = {3, {"1aa", "bar", []}},
-    TwoChild = {1, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}},
-    ?_assertEqual({[TwoChild], no_conflicts},
-                  couch_key_tree:merge([TwoChild], Stemmed, ?DEPTH)).
-
-should_merge_tree_with_large_stem()->
-    Stemmed = {2, {"1a", "bar", [{"1aa", "bar", []}]}},
-    TwoChild = {1, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}},
-    ?_assertEqual({[TwoChild], no_conflicts},
-                  couch_key_tree:merge([TwoChild], Stemmed, ?DEPTH)).
-
-should_merge_stems()->
-    StemmedA = {2, {"1a", "bar", [{"1aa", "bar", []}]}},
-    StemmedB = {3, {"1aa", "bar", []}},
-    ?_assertEqual({[StemmedA], no_conflicts},
-                  couch_key_tree:merge([StemmedA], StemmedB, ?DEPTH)).
-
-should_create_conflicts_on_merge()->
-    OneChild = {1, {"1","foo",[{"1a", "bar", []}]}},
-    Stemmed = {3, {"1aa", "bar", []}},
-    ?_assertEqual({[OneChild, Stemmed], conflicts},
-                  couch_key_tree:merge([OneChild], Stemmed, ?DEPTH)).
-
-should_create_no_conflicts_on_merge()->
-    OneChild = {1, {"1","foo",[{"1a", "bar", []}]}},
-    Stemmed = {3, {"1aa", "bar", []}},
-    TwoChild = {1, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}},
-    ?_assertEqual({[TwoChild], no_conflicts},
-                  couch_key_tree:merge([OneChild, Stemmed], TwoChild, ?DEPTH)).
-
-should_ignore_conflicting_branch()->
-    %% 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",[]}]}
-               ]}},
-    {
-        "COUCHDB-902",
-        ?_assertEqual({[FooBar], no_conflicts},
-                      couch_key_tree:merge([Foo], Bar, ?DEPTH))
-    }.
-
-should_not_find_missing_leaves()->
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    ?_assertEqual([],
-                  couch_key_tree:find_missing(TwoChildSibs,
-                                              [{0,"1"}, {1,"1a"}])).
-
-should_find_missing_leaves()->
-    Stemmed1 = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}],
-    Stemmed2 = [{2, {"1aa", "bar", []}}],
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    [
-        ?_assertEqual(
-            [{0, "10"}, {100, "x"}],
-            couch_key_tree:find_missing(
-                TwoChildSibs,
-                [{0,"1"}, {0, "10"}, {1,"1a"}, {100, "x"}])),
-        ?_assertEqual(
-            [{0, "1"}, {100, "x"}],
-            couch_key_tree:find_missing(
-                Stemmed1,
-                [{0,"1"}, {1,"1a"}, {100, "x"}])),
-        ?_assertEqual(
-            [{0, "1"}, {1,"1a"}, {100, "x"}],
-            couch_key_tree:find_missing(
-                Stemmed2,
-                [{0,"1"}, {1,"1a"}, {100, "x"}]))
-    ].
-
-should_have_no_effect_on_removing_no_leaves()->
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    ?_assertEqual({TwoChildSibs, []},
-                  couch_key_tree:remove_leafs(TwoChildSibs,
-                                              [])).
-
-should_have_no_effect_on_removing_non_existant_branch()->
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    ?_assertEqual({TwoChildSibs, []},
-                  couch_key_tree:remove_leafs(TwoChildSibs,
-                                              [{0, "1"}])).
-
-should_remove_leaf()->
-    OneChild = [{0, {"1","foo",[{"1a", "bar", []}]}}],
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    ?_assertEqual({OneChild, [{1, "1b"}]},
-                  couch_key_tree:remove_leafs(TwoChildSibs,
-                                              [{1, "1b"}])).
-
-should_produce_empty_tree_on_removing_all_leaves()->
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    ?_assertEqual({[], [{1, "1b"}, {1, "1a"}]},
-                  couch_key_tree:remove_leafs(TwoChildSibs,
-                                              [{1, "1b"}, {1, "1a"}])).
-
-should_have_no_effect_on_removing_non_existant_node()->
-    Stemmed = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}],
-    ?_assertEqual({Stemmed, []},
-                  couch_key_tree:remove_leafs(Stemmed,
-                                              [{1, "1a"}])).
-
-should_produce_empty_tree_on_removing_last_leaf()->
-    Stemmed = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}],
-    ?_assertEqual({[], [{2, "1aa"}]},
-                  couch_key_tree:remove_leafs(Stemmed,
-                                              [{2, "1aa"}])).
-
-should_extract_subtree()->
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    ?_assertEqual({[{"foo", {0, ["1"]}}],[]},
-                  couch_key_tree:get(TwoChildSibs, [{0, "1"}])).
-
-should_extract_subsubtree()->
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    ?_assertEqual({[{"bar", {1, ["1a", "1"]}}],[]},
-                  couch_key_tree:get(TwoChildSibs, [{1, "1a"}])).
-
-should_gather_non_existant_leaf()->
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    ?_assertEqual({[],[{0, "x"}]},
-                  couch_key_tree:get_key_leafs(TwoChildSibs, [{0, "x"}])).
-
-should_gather_leaf()->
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    ?_assertEqual({[{"bar", {1, ["1a","1"]}}],[]},
-                  couch_key_tree:get_key_leafs(TwoChildSibs, [{1, "1a"}])).
-
-shoul_gather_multiple_leaves()->
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    ?_assertEqual({[{"bar", {1, ["1a","1"]}},{"bar",{1, ["1b","1"]}}],[]},
-                  couch_key_tree:get_key_leafs(TwoChildSibs, [{0, "1"}])).
-
-should_retrieve_full_key_path()->
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    ?_assertEqual({[{0,[{"1", "foo"}]}],[]},
-                  couch_key_tree:get_full_key_paths(TwoChildSibs, [{0, "1"}])).
-
-should_retrieve_full_key_path_for_node()->
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    ?_assertEqual({[{1,[{"1a", "bar"},{"1", "foo"}]}],[]},
-                  couch_key_tree:get_full_key_paths(TwoChildSibs, [{1, "1a"}])).
-
-should_retrieve_leaves_with_parent_node()->
-    Stemmed = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}],
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    [
-        ?_assertEqual([{2, [{"1aa", "bar"},{"1a", "bar"}]}],
-                      couch_key_tree:get_all_leafs_full(Stemmed)),
-        ?_assertEqual([{1, [{"1a", "bar"},{"1", "foo"}]},
-                       {1, [{"1b", "bar"},{"1", "foo"}]}],
-                      couch_key_tree:get_all_leafs_full(TwoChildSibs))
-    ].
-
-should_retrieve_all_leaves()->
-    Stemmed = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}],
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    [
-        ?_assertEqual([{"bar", {2, ["1aa","1a"]}}],
-                      couch_key_tree:get_all_leafs(Stemmed)),
-        ?_assertEqual([{"bar", {1, ["1a", "1"]}}, {"bar", {1, ["1b","1"]}}],
-                      couch_key_tree:get_all_leafs(TwoChildSibs))
-    ].
-
-should_have_no_leaves_for_empty_tree()->
-    ?_assertEqual(0, couch_key_tree:count_leafs([])).
-
-should_have_single_leaf_for_tree_with_single_node()->
-    ?_assertEqual(1, couch_key_tree:count_leafs([{0, {"1","foo",[]}}])).
-
-should_have_two_leaves_for_tree_with_chindler_siblings()->
-    TwoChildSibs = [{0, {"1","foo", [{"1a", "bar", []}, {"1b", "bar", []}]}}],
-    ?_assertEqual(2, couch_key_tree:count_leafs(TwoChildSibs)).
-
-should_not_affect_on_leaf_counting_for_stemmed_tree()->
-    ?_assertEqual(1, couch_key_tree:count_leafs([{2, {"1bb", "boo", []}}])).
-
-should_have_no_effect_for_stemming_more_levels_than_exists()->
-    TwoChild = [{0, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}}],
-    ?_assertEqual(TwoChild, couch_key_tree:stem(TwoChild, 3)).
-
-should_return_one_deepest_node()->
-    TwoChild = [{0, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}}],
-    Stemmed = [{2, {"1aa", "bar", []}}],
-    ?_assertEqual(Stemmed, couch_key_tree:stem(TwoChild, 1)).
-
-should_return_two_deepest_nodes()->
-    TwoChild = [{0, {"1","foo", [{"1a", "bar", [{"1aa", "bar", []}]}]}}],
-    Stemmed = [{1, {"1a", "bar", [{"1aa", "bar", []}]}}],
-    ?_assertEqual(Stemmed, couch_key_tree:stem(TwoChild, 2)).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_passwords_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_passwords_tests.erl b/test/couchdb/couch_passwords_tests.erl
deleted file mode 100644
index 116265c..0000000
--- a/test/couchdb/couch_passwords_tests.erl
+++ /dev/null
@@ -1,54 +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(couch_passwords_tests).
-
--include("couch_eunit.hrl").
-
-
-pbkdf2_test_()->
-    {"PBKDF2",
-     [
-         {"Iterations: 1, length: 20",
-          ?_assertEqual(
-              {ok, <<"0c60c80f961f0e71f3a9b524af6012062fe037a6">>},
-              couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 1, 20))},
-
-         {"Iterations: 2, length: 20",
-          ?_assertEqual(
-              {ok, <<"ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957">>},
-              couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 2, 20))},
-
-         {"Iterations: 4096, length: 20",
-          ?_assertEqual(
-              {ok, <<"4b007901b765489abead49d926f721d065a429c1">>},
-              couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 4096, 20))},
-
-         {"Iterations: 4096, length: 25",
-          ?_assertEqual(
-              {ok, <<"3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038">>},
-              couch_passwords:pbkdf2(<<"passwordPASSWORDpassword">>,
-                                     <<"saltSALTsaltSALTsaltSALTsaltSALTsalt">>,
-                                     4096, 25))},
-         {"Null byte",
-          ?_assertEqual(
-              {ok, <<"56fa6aa75548099dcc37d7f03425e0c3">>},
-              couch_passwords:pbkdf2(<<"pass\0word">>,
-                                     <<"sa\0lt">>,
-                                     4096, 16))},
-
-         {timeout, 180,  %% this may runs too long on slow hosts
-          {"Iterations: 16777216 - this may take some time",
-           ?_assertEqual(
-               {ok, <<"eefe3d61cd4da4e4e9945b3d6ba2158c2634e984">>},
-               couch_passwords:pbkdf2(<<"password">>, <<"salt">>, 16777216, 20)
-           )}}]}.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_ref_counter_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_ref_counter_tests.erl b/test/couchdb/couch_ref_counter_tests.erl
deleted file mode 100644
index b7e97b4..0000000
--- a/test/couchdb/couch_ref_counter_tests.erl
+++ /dev/null
@@ -1,107 +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(couch_ref_counter_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(TIMEOUT, 1000).
-
-
-setup() ->
-    {ok, RefCtr} = couch_ref_counter:start([]),
-    ChildPid = spawn(fun() -> loop() end),
-    {RefCtr, ChildPid}.
-
-teardown({_, ChildPid}) ->
-    erlang:monitor(process, ChildPid),
-    ChildPid ! close,
-    wait().
-
-
-couch_ref_counter_test_() ->
-    {
-        "CouchDB reference counter tests",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                fun should_initialize_with_calling_process_as_referrer/1,
-                fun should_ignore_unknown_pid/1,
-                fun should_increment_counter_on_pid_add/1,
-                fun should_not_increase_counter_on_readding_same_pid/1,
-                fun should_drop_ref_for_double_added_pid/1,
-                fun should_decrement_counter_on_pid_drop/1,
-                fun should_add_after_drop/1,
-                fun should_decrement_counter_on_process_exit/1
-
-            ]
-        }
-    }.
-
-
-should_initialize_with_calling_process_as_referrer({RefCtr, _}) ->
-    ?_assertEqual(1, couch_ref_counter:count(RefCtr)).
-
-should_ignore_unknown_pid({RefCtr, ChildPid}) ->
-    ?_assertEqual(ok, couch_ref_counter:drop(RefCtr, ChildPid)).
-
-should_increment_counter_on_pid_add({RefCtr, ChildPid}) ->
-    couch_ref_counter:add(RefCtr, ChildPid),
-    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
-
-should_not_increase_counter_on_readding_same_pid({RefCtr, ChildPid}) ->
-    couch_ref_counter:add(RefCtr, ChildPid),
-    couch_ref_counter:add(RefCtr, ChildPid),
-    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
-
-should_drop_ref_for_double_added_pid({RefCtr, ChildPid}) ->
-    couch_ref_counter:add(RefCtr, ChildPid),
-    couch_ref_counter:add(RefCtr, ChildPid),
-    couch_ref_counter:drop(RefCtr, ChildPid),
-    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
-
-should_decrement_counter_on_pid_drop({RefCtr, ChildPid}) ->
-    couch_ref_counter:add(RefCtr, ChildPid),
-    couch_ref_counter:drop(RefCtr, ChildPid),
-    ?_assertEqual(1, couch_ref_counter:count(RefCtr)).
-
-should_add_after_drop({RefCtr, ChildPid}) ->
-    couch_ref_counter:add(RefCtr, ChildPid),
-    couch_ref_counter:drop(RefCtr, ChildPid),
-    couch_ref_counter:add(RefCtr, ChildPid),
-    ?_assertEqual(2, couch_ref_counter:count(RefCtr)).
-
-should_decrement_counter_on_process_exit({RefCtr, ChildPid}) ->
-    ?_assertEqual(1,
-        begin
-            couch_ref_counter:add(RefCtr, ChildPid),
-            erlang:monitor(process, ChildPid),
-            ChildPid ! close,
-            wait(),
-            couch_ref_counter:count(RefCtr)
-        end).
-
-
-loop() ->
-    receive
-        close -> ok
-    end.
-
-wait() ->
-    receive
-        {'DOWN', _, _, _, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw(timeout_error)
-    end.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_stats_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_stats_tests.erl b/test/couchdb/couch_stats_tests.erl
deleted file mode 100644
index d156449..0000000
--- a/test/couchdb/couch_stats_tests.erl
+++ /dev/null
@@ -1,412 +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(couch_stats_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(STATS_CFG_FIXTURE,
-    filename:join([?FIXTURESDIR, "couch_stats_aggregates.cfg"])).
--define(STATS_INI_FIXTURE,
-    filename:join([?FIXTURESDIR, "couch_stats_aggregates.ini"])).
--define(TIMEOUT, 1000).
--define(TIMEWAIT, 500).
-
-
-setup_collector() ->
-    couch_stats_collector:start(),
-    ok.
-
-setup_aggregator(_) ->
-    {ok, Pid} = couch_config:start_link([?STATS_INI_FIXTURE]),
-    {ok, _} = couch_stats_collector:start(),
-    {ok, _} = couch_stats_aggregator:start(?STATS_CFG_FIXTURE),
-    Pid.
-
-teardown_collector(_) ->
-    couch_stats_collector:stop(),
-    ok.
-
-teardown_aggregator(_, Pid) ->
-    couch_stats_aggregator:stop(),
-    couch_stats_collector:stop(),
-    erlang:monitor(process, Pid),
-    couch_config:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw({timeout, config_stop})
-    end,
-    ok.
-
-
-couch_stats_collector_test_() ->
-    {
-        "CouchDB stats collector tests",
-        {
-            foreach,
-            fun setup_collector/0, fun teardown_collector/1,
-            [
-                should_increment_counter(),
-                should_decrement_counter(),
-                should_increment_and_decrement_counter(),
-                should_record_absolute_values(),
-                should_clear_absolute_values(),
-                should_track_process_count(),
-                should_increment_counter_multiple_times_per_pid(),
-                should_decrement_counter_on_process_exit(),
-                should_decrement_for_each_track_process_count_call_on_exit(),
-                should_return_all_counters_and_absolute_values(),
-                should_return_incremental_counters(),
-                should_return_absolute_values()
-            ]
-        }
-    }.
-
-couch_stats_aggregator_test_() ->
-    Funs = [
-        fun should_init_empty_aggregate/2,
-        fun should_get_empty_aggregate/2,
-        fun should_change_stats_on_values_add/2,
-        fun should_change_stats_for_all_times_on_values_add/2,
-        fun should_change_stats_on_values_change/2,
-        fun should_change_stats_for_all_times_on_values_change/2,
-        fun should_not_remove_data_after_some_time_for_0_sample/2,
-        fun should_remove_data_after_some_time_for_other_samples/2
-    ],
-    {
-        "CouchDB stats aggregator tests",
-        [
-            {
-                "Absolute values",
-                {
-                    foreachx,
-                    fun setup_aggregator/1, fun teardown_aggregator/2,
-                    [{absolute, Fun} || Fun <- Funs]
-                }
-            },
-            {
-                "Counters",
-                {
-                    foreachx,
-                    fun setup_aggregator/1, fun teardown_aggregator/2,
-                    [{counter, Fun} || Fun <- Funs]
-                }
-            }
-        ]
-    }.
-
-
-should_increment_counter() ->
-    ?_assertEqual(100,
-        begin
-            AddCount = fun() -> couch_stats_collector:increment(foo) end,
-            repeat(AddCount, 100),
-            couch_stats_collector:get(foo)
-        end).
-
-should_decrement_counter() ->
-    ?_assertEqual(67,
-        begin
-            AddCount = fun() -> couch_stats_collector:increment(foo) end,
-            RemCount = fun() -> couch_stats_collector:decrement(foo) end,
-            repeat(AddCount, 100),
-            repeat(RemCount, 33),
-            couch_stats_collector:get(foo)
-        end).
-
-should_increment_and_decrement_counter() ->
-    ?_assertEqual(0,
-        begin
-            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),
-            repeat(RemCount, 80),
-            couch_stats_collector:get(foo)
-        end).
-
-should_record_absolute_values() ->
-    ?_assertEqual(lists:seq(1, 15),
-        begin
-            lists:map(fun(Val) ->
-                couch_stats_collector:record(bar, Val)
-            end, lists:seq(1, 15)),
-            couch_stats_collector:get(bar)
-        end).
-
-should_clear_absolute_values() ->
-    ?_assertEqual(nil,
-        begin
-            lists:map(fun(Val) ->
-                couch_stats_collector:record(bar, Val)
-            end, lists:seq(1, 15)),
-            couch_stats_collector:clear(bar),
-            couch_stats_collector:get(bar)
-        end).
-
-should_track_process_count() ->
-    ?_assertMatch({_, 1}, spawn_and_count(1)).
-
-should_increment_counter_multiple_times_per_pid() ->
-    ?_assertMatch({_, 3}, spawn_and_count(3)).
-
-should_decrement_counter_on_process_exit() ->
-    ?_assertEqual(2,
-        begin
-            {Pid, 1} = spawn_and_count(1),
-            spawn_and_count(2),
-            RefMon = erlang:monitor(process, Pid),
-            Pid ! sepuku,
-            receive
-                {'DOWN', RefMon, _, _, _} -> ok
-            after ?TIMEOUT ->
-                throw(timeout)
-            end,
-            % sleep for awhile to let collector handle the updates
-            % suddenly, it couldn't notice process death instantly
-            timer:sleep(?TIMEWAIT),
-            couch_stats_collector:get(hoopla)
-        end).
-
-should_decrement_for_each_track_process_count_call_on_exit() ->
-    ?_assertEqual(2,
-        begin
-            {_, 2} = spawn_and_count(2),
-            {Pid, 6} = spawn_and_count(4),
-            RefMon = erlang:monitor(process, Pid),
-            Pid ! sepuku,
-            receive
-                {'DOWN', RefMon, _, _, _} -> ok
-            after ?TIMEOUT ->
-                throw(timeout)
-            end,
-            timer:sleep(?TIMEWAIT),
-            couch_stats_collector:get(hoopla)
-        end).
-
-should_return_all_counters_and_absolute_values() ->
-    ?_assertEqual([{bar,[1.0,0.0]}, {foo,1}],
-        begin
-            couch_stats_collector:record(bar, 0.0),
-            couch_stats_collector:record(bar, 1.0),
-            couch_stats_collector:increment(foo),
-            lists:sort(couch_stats_collector:all())
-        end).
-
-should_return_incremental_counters() ->
-    ?_assertEqual([{foo,1}],
-        begin
-            couch_stats_collector:record(bar, 0.0),
-            couch_stats_collector:record(bar, 1.0),
-            couch_stats_collector:increment(foo),
-            lists:sort(couch_stats_collector:all(incremental))
-        end).
-
-should_return_absolute_values() ->
-    ?_assertEqual([{bar,[1.0,0.0]}, {zing, "Z"}],
-        begin
-            couch_stats_collector:record(bar, 0.0),
-            couch_stats_collector:record(bar, 1.0),
-            couch_stats_collector:record(zing, 90),
-            couch_stats_collector:increment(foo),
-            lists:sort(couch_stats_collector:all(absolute))
-        end).
-
-should_init_empty_aggregate(absolute, _) ->
-    {Aggs} = couch_stats_aggregator:all(),
-    ?_assertEqual({[{'11', make_agg(<<"randomosity">>,
-                                    null, null, null, null, null)}]},
-                  couch_util:get_value(number, Aggs));
-should_init_empty_aggregate(counter, _) ->
-    {Aggs} = couch_stats_aggregator:all(),
-    ?_assertEqual({[{stuff, make_agg(<<"yay description">>,
-                                     null, null, null, null, null)}]},
-                  couch_util:get_value(testing, Aggs)).
-
-should_get_empty_aggregate(absolute, _) ->
-    ?_assertEqual(make_agg(<<"randomosity">>, null, null, null, null, null),
-             couch_stats_aggregator:get_json({number, '11'}));
-should_get_empty_aggregate(counter, _) ->
-    ?_assertEqual(make_agg(<<"yay description">>, null, null, null, null, null),
-             couch_stats_aggregator:get_json({testing, stuff})).
-
-should_change_stats_on_values_add(absolute, _) ->
-    lists:foreach(fun(X) ->
-        couch_stats_collector:record({number, 11}, X)
-    end, lists:seq(0, 10)),
-    couch_stats_aggregator:collect_sample(),
-    ?_assertEqual(make_agg(<<"randomosity">>, 5.0, 5.0, null, 5.0, 5.0),
-                  couch_stats_aggregator:get_json({number, 11}));
-should_change_stats_on_values_add(counter, _) ->
-    lists:foreach(fun(_) ->
-        couch_stats_collector:increment({testing, stuff})
-    end, lists:seq(1, 100)),
-    couch_stats_aggregator:collect_sample(),
-    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 100.0, null, 100, 100),
-                  couch_stats_aggregator:get_json({testing, stuff})).
-
-should_change_stats_for_all_times_on_values_add(absolute, _) ->
-    lists:foreach(fun(X) ->
-        couch_stats_collector:record({number, 11}, X)
-    end, lists:seq(0, 10)),
-    couch_stats_aggregator:collect_sample(),
-    ?_assertEqual(make_agg(<<"randomosity">>, 5.0, 5.0, null, 5.0, 5.0),
-                  couch_stats_aggregator:get_json({number, 11}, 1));
-should_change_stats_for_all_times_on_values_add(counter, _) ->
-    lists:foreach(fun(_) ->
-        couch_stats_collector:increment({testing, stuff})
-    end, lists:seq(1, 100)),
-    couch_stats_aggregator:collect_sample(),
-    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 100.0, null, 100, 100),
-                  couch_stats_aggregator:get_json({testing, stuff}, 1)).
-
-should_change_stats_on_values_change(absolute, _) ->
-    ?_assertEqual(make_agg(<<"randomosity">>, 20.0, 10.0, 7.071, 5.0, 15.0),
-        begin
-            lists:foreach(fun(X) ->
-                couch_stats_collector:record({number, 11}, X)
-            end, lists:seq(0, 10)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_collector:record({number, 11}, 15),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({number, 11})
-        end);
-should_change_stats_on_values_change(counter, _) ->
-    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 50.0, 70.711, 0, 100),
-        begin
-            lists:foreach(fun(_) ->
-                couch_stats_collector:increment({testing, stuff})
-            end, lists:seq(1, 100)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({testing, stuff})
-        end).
-
-should_change_stats_for_all_times_on_values_change(absolute, _) ->
-    ?_assertEqual(make_agg(<<"randomosity">>, 20.0, 10.0, 7.071, 5.0, 15.0),
-        begin
-            lists:foreach(fun(X) ->
-                couch_stats_collector:record({number, 11}, X)
-            end, lists:seq(0, 10)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_collector:record({number, 11}, 15),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({number, 11}, 1)
-        end);
-should_change_stats_for_all_times_on_values_change(counter, _) ->
-    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 50.0, 70.711, 0, 100),
-        begin
-            lists:foreach(fun(_) ->
-                couch_stats_collector:increment({testing, stuff})
-            end, lists:seq(1, 100)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({testing, stuff}, 1)
-        end).
-
-should_not_remove_data_after_some_time_for_0_sample(absolute, _) ->
-    ?_assertEqual(make_agg(<<"randomosity">>, 20.0, 10.0, 7.071, 5.0, 15.0),
-        begin
-            lists:foreach(fun(X) ->
-                couch_stats_collector:record({number, 11}, X)
-            end, lists:seq(0, 10)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_collector:record({number, 11}, 15),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({number, 11})
-        end);
-should_not_remove_data_after_some_time_for_0_sample(counter, _) ->
-    ?_assertEqual(make_agg(<<"yay description">>, 100.0, 33.333, 57.735, 0, 100),
-        begin
-            lists:foreach(fun(_) ->
-                couch_stats_collector:increment({testing, stuff})
-            end, lists:seq(1, 100)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({testing, stuff})
-        end).
-
-should_remove_data_after_some_time_for_other_samples(absolute, _) ->
-    ?_assertEqual(make_agg(<<"randomosity">>, 15.0, 15.0, null, 15.0, 15.0),
-        begin
-            lists:foreach(fun(X) ->
-                couch_stats_collector:record({number, 11}, X)
-            end, lists:seq(0, 10)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_collector:record({number, 11}, 15),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({number, 11}, 1)
-        end);
-should_remove_data_after_some_time_for_other_samples(counter, _) ->
-    ?_assertEqual(make_agg(<<"yay description">>, 0, 0.0, 0.0, 0, 0),
-        begin
-            lists:foreach(fun(_) ->
-                couch_stats_collector:increment({testing, stuff})
-            end, lists:seq(1, 100)),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            timer:sleep(?TIMEWAIT),
-            couch_stats_aggregator:collect_sample(),
-            couch_stats_aggregator:get_json({testing, stuff}, 1)
-        end).
-
-
-spawn_and_count(N) ->
-    Self = self(),
-    Pid = spawn(fun() ->
-        lists:foreach(
-            fun(_) ->
-                couch_stats_collector:track_process_count(hoopla)
-            end, lists:seq(1,N)),
-        Self ! reporting,
-        receive
-            sepuku -> ok
-        end
-    end),
-    receive reporting -> ok end,
-    {Pid, couch_stats_collector:get(hoopla)}.
-
-repeat(_, 0) ->
-    ok;
-repeat(Fun, Count) ->
-    Fun(),
-    repeat(Fun, Count-1).
-
-make_agg(Desc, Sum, Mean, StdDev, Min, Max) ->
-    {[
-        {description, Desc},
-        {current, Sum},
-        {sum, Sum},
-        {mean, Mean},
-        {stddev, StdDev},
-        {min, Min},
-        {max, Max}
-    ]}.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_stream_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_stream_tests.erl b/test/couchdb/couch_stream_tests.erl
deleted file mode 100644
index 335a2fe..0000000
--- a/test/couchdb/couch_stream_tests.erl
+++ /dev/null
@@ -1,100 +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(couch_stream_tests).
-
--include("couch_eunit.hrl").
-
-
-setup() ->
-    {ok, Fd} = couch_file:open(?tempfile(), [create, overwrite]),
-    {ok, Stream} = couch_stream:open(Fd),
-    {Fd, Stream}.
-
-teardown({Fd, _}) ->
-    ok = couch_file:close(Fd).
-
-
-stream_test_() ->
-    {
-        "CouchDB stream tests",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                fun should_write/1,
-                fun should_write_consecutive/1,
-                fun should_write_empty_binary/1,
-                fun should_return_file_pointers_on_close/1,
-                fun should_return_stream_size_on_close/1,
-                fun should_return_valid_pointers/1,
-                fun should_recall_last_pointer_position/1,
-                fun should_stream_more_with_4K_chunk_size/1
-            ]
-        }
-    }.
-
-
-should_write({_, Stream}) ->
-    ?_assertEqual(ok, couch_stream:write(Stream, <<"food">>)).
-
-should_write_consecutive({_, Stream}) ->
-    couch_stream:write(Stream, <<"food">>),
-    ?_assertEqual(ok, couch_stream:write(Stream, <<"foob">>)).
-
-should_write_empty_binary({_, Stream}) ->
-    ?_assertEqual(ok, couch_stream:write(Stream, <<>>)).
-
-should_return_file_pointers_on_close({_, Stream}) ->
-    couch_stream:write(Stream, <<"foodfoob">>),
-    {Ptrs, _, _, _, _} = couch_stream:close(Stream),
-    ?_assertEqual([{0, 8}], Ptrs).
-
-should_return_stream_size_on_close({_, Stream}) ->
-    couch_stream:write(Stream, <<"foodfoob">>),
-    {_, Length, _, _, _} = couch_stream:close(Stream),
-    ?_assertEqual(8, Length).
-
-should_return_valid_pointers({Fd, Stream}) ->
-    couch_stream:write(Stream, <<"foodfoob">>),
-    {Ptrs, _, _, _, _} = couch_stream:close(Stream),
-    ?_assertEqual(<<"foodfoob">>, read_all(Fd, Ptrs)).
-
-should_recall_last_pointer_position({Fd, Stream}) ->
-    couch_stream:write(Stream, <<"foodfoob">>),
-    {_, _, _, _, _} = couch_stream:close(Stream),
-    {ok, ExpPtr} = couch_file:bytes(Fd),
-    {ok, Stream2} = couch_stream:open(Fd),
-    ZeroBits = <<0:(8 * 10)>>,
-    OneBits = <<1:(8 * 10)>>,
-    ok = couch_stream:write(Stream2, OneBits),
-    ok = couch_stream:write(Stream2, ZeroBits),
-    {Ptrs, 20, _, _, _} = couch_stream:close(Stream2),
-    [{ExpPtr, 20}] = Ptrs,
-    AllBits = iolist_to_binary([OneBits, ZeroBits]),
-    ?_assertEqual(AllBits, read_all(Fd, Ptrs)).
-
-should_stream_more_with_4K_chunk_size({Fd, _}) ->
-    {ok, Stream} = couch_stream:open(Fd, [{buffer_size, 4096}]),
-    lists:foldl(
-        fun(_, Acc) ->
-            Data = <<"a1b2c">>,
-            couch_stream:write(Stream, Data),
-            [Data | Acc]
-        end, [], lists:seq(1, 1024)),
-    ?_assertMatch({[{0, 4100}, {4106, 1020}], 5120, _, _, _},
-                  couch_stream:close(Stream)).
-
-
-read_all(Fd, PosList) ->
-    Data = couch_stream:foldl(Fd, PosList, fun(Bin, Acc) -> [Bin, Acc] end, []),
-    iolist_to_binary(Data).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_task_status_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_task_status_tests.erl b/test/couchdb/couch_task_status_tests.erl
deleted file mode 100644
index f71ad2b..0000000
--- a/test/couchdb/couch_task_status_tests.erl
+++ /dev/null
@@ -1,225 +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(couch_task_status_tests).
-
--include("couch_eunit.hrl").
--include_lib("couchdb/couch_db.hrl").
-
--define(TIMEOUT, 1000).
-
-
-setup() ->
-    {ok, TaskStatusPid} = couch_task_status:start_link(),
-    TaskUpdaterPid = spawn(fun() -> loop() end),
-    {TaskStatusPid, TaskUpdaterPid}.
-
-teardown({TaskStatusPid, _}) ->
-    erlang:monitor(process, TaskStatusPid),
-    couch_task_status:stop(),
-    receive
-        {'DOWN', _, _, TaskStatusPid, _} ->
-            ok
-    after ?TIMEOUT ->
-        throw(timeout_error)
-    end.
-
-
-couch_task_status_test_() ->
-    {
-        "CouchDB task status updates",
-        {
-            foreach,
-            fun setup/0, fun teardown/1,
-            [
-                fun should_register_task/1,
-                fun should_set_task_startup_time/1,
-                fun should_have_update_time_as_startup_before_any_progress/1,
-                fun should_set_task_type/1,
-                fun should_not_register_multiple_tasks_for_same_pid/1,
-                fun should_set_task_progress/1,
-                fun should_update_task_progress/1,
-                fun should_update_time_changes_on_task_progress/1,
-                fun should_control_update_frequency/1,
-                fun should_reset_control_update_frequency/1,
-                fun should_track_multiple_tasks/1,
-                fun should_finish_task/1
-
-            ]
-        }
-    }.
-
-
-should_register_task({_, Pid}) ->
-    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
-    ?_assertEqual(1, length(couch_task_status:all())).
-
-should_set_task_startup_time({_, Pid}) ->
-    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
-    ?_assert(is_integer(get_task_prop(Pid, started_on))).
-
-should_have_update_time_as_startup_before_any_progress({_, Pid}) ->
-    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
-    StartTime = get_task_prop(Pid, started_on),
-    ?_assertEqual(StartTime, get_task_prop(Pid, updated_on)).
-
-should_set_task_type({_, Pid}) ->
-    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
-    ?_assertEqual(replication, get_task_prop(Pid, type)).
-
-should_not_register_multiple_tasks_for_same_pid({_, Pid}) ->
-    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
-    ?_assertEqual({add_task_error, already_registered},
-                  call(Pid, add, [{type, compaction}, {progress, 0}])).
-
-should_set_task_progress({_, Pid}) ->
-    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
-    ?_assertEqual(0, get_task_prop(Pid, progress)).
-
-should_update_task_progress({_, Pid}) ->
-    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
-    call(Pid, update, [{progress, 25}]),
-    ?_assertEqual(25, get_task_prop(Pid, progress)).
-
-should_update_time_changes_on_task_progress({_, Pid}) ->
-    ?_assert(
-        begin
-            ok = call(Pid, add, [{type, replication}, {progress, 0}]),
-            ok = timer:sleep(1000),  % sleep awhile to customize update time
-            call(Pid, update, [{progress, 25}]),
-            get_task_prop(Pid, updated_on) > get_task_prop(Pid, started_on)
-        end).
-
-should_control_update_frequency({_, Pid}) ->
-    ?_assertEqual(66,
-        begin
-            ok = call(Pid, add, [{type, replication}, {progress, 0}]),
-            call(Pid, update, [{progress, 50}]),
-            call(Pid, update_frequency, 500),
-            call(Pid, update, [{progress, 66}]),
-            call(Pid, update, [{progress, 77}]),
-            get_task_prop(Pid, progress)
-        end).
-
-should_reset_control_update_frequency({_, Pid}) ->
-    ?_assertEqual(87,
-        begin
-            ok = call(Pid, add, [{type, replication}, {progress, 0}]),
-            call(Pid, update, [{progress, 50}]),
-            call(Pid, update_frequency, 500),
-            call(Pid, update, [{progress, 66}]),
-            call(Pid, update, [{progress, 77}]),
-            call(Pid, update_frequency, 0),
-            call(Pid, update, [{progress, 87}]),
-            get_task_prop(Pid, progress)
-        end).
-
-should_track_multiple_tasks(_) ->
-    ?_assert(run_multiple_tasks()).
-
-should_finish_task({_, Pid}) ->
-    ok = call(Pid, add, [{type, replication}, {progress, 0}]),
-    ?assertEqual(1, length(couch_task_status:all())),
-    ok = call(Pid, done),
-    ?_assertEqual(0, length(couch_task_status:all())).
-
-
-run_multiple_tasks() ->
-    Pid1 = spawn(fun() -> loop() end),
-    Pid2 = spawn(fun() -> loop() end),
-    Pid3 = spawn(fun() -> loop() end),
-    call(Pid1, add, [{type, replication}, {progress, 0}]),
-    call(Pid2, add, [{type, compaction}, {progress, 0}]),
-    call(Pid3, add, [{type, indexer}, {progress, 0}]),
-
-    ?assertEqual(3, length(couch_task_status:all())),
-    ?assertEqual(replication, get_task_prop(Pid1, type)),
-    ?assertEqual(compaction, get_task_prop(Pid2, type)),
-    ?assertEqual(indexer, get_task_prop(Pid3, type)),
-
-    call(Pid2, update, [{progress, 33}]),
-    call(Pid3, update, [{progress, 42}]),
-    call(Pid1, update, [{progress, 11}]),
-    ?assertEqual(42, get_task_prop(Pid3, progress)),
-    call(Pid1, update, [{progress, 72}]),
-    ?assertEqual(72, get_task_prop(Pid1, progress)),
-    ?assertEqual(33, get_task_prop(Pid2, progress)),
-
-    call(Pid1, done),
-    ?assertEqual(2, length(couch_task_status:all())),
-    call(Pid3, done),
-    ?assertEqual(1, length(couch_task_status:all())),
-    call(Pid2, done),
-    ?assertEqual(0, length(couch_task_status:all())),
-
-    true.
-
-
-loop() ->
-    receive
-        {add, Props, From} ->
-            Resp = couch_task_status:add_task(Props),
-            From ! {ok, self(), Resp},
-            loop();
-        {update, Props, From} ->
-            Resp = couch_task_status:update(Props),
-            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 ?TIMEOUT ->
-        throw(timeout_error)
-    end.
-
-get_task_prop(Pid, Prop) ->
-    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];
-                _ ->
-                    Acc
-            end
-        end,
-        [], couch_task_status:all()
-    ),
-    case couch_util:get_value(Prop, hd(Element), nil) of
-        nil ->
-            erlang:error({assertion_failed,
-                         [{module, ?MODULE},
-                          {line, ?LINE},
-                          {reason, "Could not get property '"
-                                   ++ couch_util:to_list(Prop)
-                                   ++ "' for task "
-                                   ++ pid_to_list(Pid)}]});
-        Value ->
-            Value
-    end.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_util_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_util_tests.erl b/test/couchdb/couch_util_tests.erl
deleted file mode 100644
index 8e24e72..0000000
--- a/test/couchdb/couch_util_tests.erl
+++ /dev/null
@@ -1,136 +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(couch_util_tests).
-
--include("couch_eunit.hrl").
-
-
-setup() ->
-    %% We cannot start driver from here since it becomes bounded to eunit
-    %% master process and the next couch_server_sup:start_link call will
-    %% fail because server couldn't load driver since it already is.
-    %%
-    %% On other hand, we cannot unload driver here due to
-    %% {error, not_loaded_by_this_process} while it is. Any ideas is welcome.
-    %%
-    couch_server_sup:start_link(?CONFIG_CHAIN),
-    %% couch_config:start_link(?CONFIG_CHAIN),
-    %% {ok, _} = couch_drv:start_link(),
-    ok.
-
-teardown(_) ->
-    couch_server_sup:stop(),
-    %% couch_config:stop(),
-    %% erl_ddll:unload_driver(couch_icu_driver),
-    ok.
-
-
-collation_test_() ->
-    {
-        "Collation tests",
-        [
-            {
-                setup,
-                fun setup/0, fun teardown/1,
-                [
-                    should_collate_ascii(),
-                    should_collate_non_ascii()
-                ]
-            }
-        ]
-    }.
-
-should_collate_ascii() ->
-    ?_assertEqual(1, couch_util:collate(<<"foo">>, <<"bar">>)).
-
-should_collate_non_ascii() ->
-    ?_assertEqual(-1, couch_util:collate(<<"A">>, <<"aa">>)).
-
-to_existed_atom_test() ->
-    ?assert(couch_util:to_existing_atom(true)),
-    ?assertMatch(foo, couch_util:to_existing_atom(<<"foo">>)),
-    ?assertMatch(foobarbaz, couch_util:to_existing_atom("foobarbaz")).
-
-implode_test() ->
-    ?assertEqual([1, 38, 2, 38, 3], couch_util:implode([1, 2, 3], "&")).
-
-trim_test() ->
-    lists:map(fun(S) -> ?assertEqual("foo", couch_util:trim(S)) end,
-              [" foo", "foo ", "\tfoo", " foo ", "foo\t", "foo\n", "\nfoo"]).
-
-abs_pathname_test() ->
-    {ok, Cwd} = file:get_cwd(),
-    ?assertEqual(Cwd ++ "/foo", couch_util:abs_pathname("./foo")).
-
-flush_test() ->
-    ?assertNot(couch_util:should_flush()),
-    AcquireMem = fun() ->
-        _IntsToAGazillion = lists:seq(1, 200000),
-        _LotsOfData = lists:map(fun(_) -> <<"foobar">> end,
-                                lists:seq(1, 500000)),
-        _BigBin = list_to_binary(_LotsOfData),
-
-        %% Allocation 200K tuples puts us above the memory threshold
-        %% Originally, there should be:
-        %%      ?assertNot(should_flush())
-        %% however, unlike for etap test, GC collects all allocated bits
-        %% making this conditions fail. So we have to invert the condition
-        %% since GC works, cleans the memory and everything is fine.
-        ?assertNot(couch_util:should_flush())
-    end,
-    AcquireMem(),
-
-    %% Checking to flush invokes GC
-    ?assertNot(couch_util:should_flush()).
-
-verify_test() ->
-    ?assert(couch_util:verify("It4Vooya", "It4Vooya")),
-    ?assertNot(couch_util:verify("It4VooyaX", "It4Vooya")),
-    ?assert(couch_util:verify(<<"ahBase3r">>, <<"ahBase3r">>)),
-    ?assertNot(couch_util:verify(<<"ahBase3rX">>, <<"ahBase3r">>)),
-    ?assertNot(couch_util:verify(nil, <<"ahBase3r">>)).
-
-find_in_binary_test_() ->
-    Cases = [
-        {<<"foo">>, <<"foobar">>, {exact, 0}},
-        {<<"foo">>, <<"foofoo">>, {exact, 0}},
-        {<<"foo">>, <<"barfoo">>, {exact, 3}},
-        {<<"foo">>, <<"barfo">>, {partial, 3}},
-        {<<"f">>, <<"fobarfff">>, {exact, 0}},
-        {<<"f">>, <<"obarfff">>, {exact, 4}},
-        {<<"f">>, <<"obarggf">>, {exact, 6}},
-        {<<"f">>, <<"f">>, {exact, 0}},
-        {<<"f">>, <<"g">>, not_found},
-        {<<"foo">>, <<"f">>, {partial, 0}},
-        {<<"foo">>, <<"g">>, not_found},
-        {<<"foo">>, <<"">>, not_found},
-        {<<"fofo">>, <<"foofo">>, {partial, 3}},
-        {<<"foo">>, <<"gfobarfo">>, {partial, 6}},
-        {<<"foo">>, <<"gfobarf">>, {partial, 6}},
-        {<<"foo">>, <<"gfobar">>, not_found},
-        {<<"fog">>, <<"gbarfogquiz">>, {exact, 4}},
-        {<<"ggg">>, <<"ggg">>, {exact, 0}},
-        {<<"ggg">>, <<"ggggg">>, {exact, 0}},
-        {<<"ggg">>, <<"bggg">>, {exact, 1}},
-        {<<"ggg">>, <<"bbgg">>, {partial, 2}},
-        {<<"ggg">>, <<"bbbg">>, {partial, 3}},
-        {<<"ggg">>, <<"bgbggbggg">>, {exact, 6}},
-        {<<"ggg">>, <<"bgbggb">>, not_found}
-    ],
-    lists:map(
-        fun({Needle, Haystack, Result}) ->
-            Msg = lists:flatten(io_lib:format("Looking for ~s in ~s",
-                                              [Needle, Haystack])),
-            {Msg, ?_assertMatch(Result,
-                                couch_util:find_in_binary(Needle, Haystack))}
-        end, Cases).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_uuids_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_uuids_tests.erl b/test/couchdb/couch_uuids_tests.erl
deleted file mode 100644
index ea1d034..0000000
--- a/test/couchdb/couch_uuids_tests.erl
+++ /dev/null
@@ -1,161 +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(couch_uuids_tests).
-
--include("couch_eunit.hrl").
-
--define(TIMEOUT_S, 20).
-
-
-setup() ->
-    {ok, Pid} = couch_config:start_link(?CONFIG_CHAIN),
-    erlang:monitor(process, Pid),
-    couch_uuids:start(),
-    Pid.
-
-setup(Opts) ->
-    Pid = setup(),
-    lists:foreach(
-        fun({Option, Value}) ->
-            couch_config:set("uuids", Option, Value, false)
-        end, Opts),
-    Pid.
-
-teardown(Pid) ->
-    couch_uuids:stop(),
-    couch_config:stop(),
-    receive
-        {'DOWN', _, _, Pid, _} -> ok
-    after
-        1000 -> throw({timeout_error, config_stop})
-    end.
-
-teardown(_, Pid) ->
-    teardown(Pid).
-
-
-default_test_() ->
-    {
-        "Default UUID algorithm",
-        {
-            setup,
-            fun setup/0, fun teardown/1,
-            fun should_be_unique/1
-        }
-    }.
-
-sequential_test_() ->
-    Opts = [{"algorithm", "sequential"}],
-    Cases = [
-        fun should_be_unique/2,
-        fun should_increment_monotonically/2,
-        fun should_rollover/2
-    ],
-    {
-        "UUID algorithm: sequential",
-        {
-            foreachx,
-            fun setup/1, fun teardown/2,
-            [{Opts, Fun} || Fun <- Cases]
-        }
-    }.
-
-utc_test_() ->
-    Opts = [{"algorithm", "utc_random"}],
-    Cases = [
-        fun should_be_unique/2,
-        fun should_increment_monotonically/2
-    ],
-    {
-        "UUID algorithm: utc_random",
-        {
-            foreachx,
-            fun setup/1, fun teardown/2,
-            [{Opts, Fun} || Fun <- Cases]
-        }
-    }.
-
-utc_id_suffix_test_() ->
-    Opts = [{"algorithm", "utc_id"}, {"utc_id_suffix", "bozo"}],
-    Cases = [
-        fun should_be_unique/2,
-        fun should_increment_monotonically/2,
-        fun should_preserve_suffix/2
-    ],
-    {
-        "UUID algorithm: utc_id",
-        {
-            foreachx,
-            fun setup/1, fun teardown/2,
-            [{Opts, Fun} || Fun <- Cases]
-        }
-    }.
-
-
-should_be_unique() ->
-    %% this one may really runs for too long on slow hosts
-    {timeout, ?TIMEOUT_S, ?_assert(test_unique(10000, [couch_uuids:new()]))}.
-should_be_unique(_) ->
-    should_be_unique().
-should_be_unique(_, _) ->
-    should_be_unique().
-
-should_increment_monotonically(_, _) ->
-    ?_assert(couch_uuids:new() < couch_uuids:new()).
-
-should_rollover(_, _) ->
-    ?_test(begin
-        UUID = binary_to_list(couch_uuids:new()),
-        Prefix = element(1, lists:split(26, UUID)),
-        N = gen_until_pref_change(Prefix, 0),
-        ?assert(N >= 5000 andalso N =< 11000)
-    end).
-
-should_preserve_suffix(_, _) ->
-    ?_test(begin
-        UUID = binary_to_list(couch_uuids:new()),
-        Suffix = get_suffix(UUID),
-        ?assert(test_same_suffix(10000, Suffix))
-    end).
-
-
-test_unique(0, _) ->
-    true;
-test_unique(N, UUIDs) ->
-    UUID = couch_uuids:new(),
-    ?assertNot(lists:member(UUID, UUIDs)),
-    test_unique(N - 1, [UUID| UUIDs]).
-
-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.
-
-get_suffix(UUID) when is_binary(UUID) ->
-    get_suffix(binary_to_list(UUID));
-get_suffix(UUID) ->
-    element(2, lists:split(14, UUID)).
-
-test_same_suffix(0, _) ->
-    true;
-test_same_suffix(N, Suffix) ->
-    case get_suffix(couch_uuids:new()) of
-        Suffix -> test_same_suffix(N - 1, Suffix);
-        _ -> false
-    end.

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/dfad673e/test/couchdb/couch_work_queue_tests.erl
----------------------------------------------------------------------
diff --git a/test/couchdb/couch_work_queue_tests.erl b/test/couchdb/couch_work_queue_tests.erl
deleted file mode 100644
index 8a463b5..0000000
--- a/test/couchdb/couch_work_queue_tests.erl
+++ /dev/null
@@ -1,393 +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(couch_work_queue_tests).
-
--include("couch_eunit.hrl").
-
--define(TIMEOUT, 100).
-
-
-setup(Opts) ->
-    {ok, Q} = couch_work_queue:new(Opts),
-    Producer = spawn_producer(Q),
-    Consumer = spawn_consumer(Q),
-    {Q, Producer, Consumer}.
-
-setup_max_items() ->
-    setup([{max_items, 3}]).
-
-setup_max_size() ->
-    setup([{max_size, 160}]).
-
-setup_max_items_and_size() ->
-    setup([{max_size, 160}, {max_items, 3}]).
-
-setup_multi_workers() ->
-    {Q, Producer, Consumer1} = setup([{max_size, 160},
-                                      {max_items, 3},
-                                      {multi_workers, true}]),
-    Consumer2 = spawn_consumer(Q),
-    Consumer3 = spawn_consumer(Q),
-    {Q, Producer, [Consumer1, Consumer2, Consumer3]}.
-
-teardown({Q, Producer, Consumers}) when is_list(Consumers) ->
-    % consume all to unblock and let producer/consumer stop without timeout
-    [consume(Consumer, all) || Consumer <- Consumers],
-
-    ok = close_queue(Q),
-    ok = stop(Producer, "producer"),
-    R = [stop(Consumer, "consumer") || Consumer <- Consumers],
-    R = [ok || _ <- Consumers],
-    ok;
-teardown({Q, Producer, Consumer}) ->
-    teardown({Q, Producer, [Consumer]}).
-
-
-single_consumer_test_() ->
-    {
-        "Single producer and consumer",
-        [
-            {
-                "Queue with 3 max items",
-                {
-                    foreach,
-                    fun setup_max_items/0, fun teardown/1,
-                    single_consumer_max_item_count() ++ common_cases()
-                }
-            },
-            {
-                "Queue with max size of 160 bytes",
-                {
-                    foreach,
-                    fun setup_max_size/0, fun teardown/1,
-                    single_consumer_max_size() ++ common_cases()
-                }
-            },
-            {
-                "Queue with max size of 160 bytes and 3 max items",
-                {
-                    foreach,
-                    fun setup_max_items_and_size/0, fun teardown/1,
-                    single_consumer_max_items_and_size() ++ common_cases()
-                }
-            }
-        ]
-    }.
-
-multiple_consumers_test_() ->
-    {
-        "Single producer and multiple consumers",
-        [
-            {
-                "Queue with max size of 160 bytes and 3 max items",
-                {
-                    foreach,
-                    fun setup_multi_workers/0, fun teardown/1,
-                    common_cases() ++ multiple_consumers()
-                }
-
-            }
-        ]
-    }.
-
-common_cases()->
-    [
-        fun should_block_consumer_on_dequeue_from_empty_queue/1,
-        fun should_consume_right_item/1,
-        fun should_timeout_on_close_non_empty_queue/1,
-        fun should_not_block_producer_for_non_empty_queue_after_close/1,
-        fun should_be_closed/1
-    ].
-
-single_consumer_max_item_count()->
-    [
-        fun should_have_no_items_for_new_queue/1,
-        fun should_block_producer_on_full_queue_count/1,
-        fun should_receive_first_queued_item/1,
-        fun should_consume_multiple_items/1,
-        fun should_consume_all/1
-    ].
-
-single_consumer_max_size()->
-    [
-        fun should_have_zero_size_for_new_queue/1,
-        fun should_block_producer_on_full_queue_size/1,
-        fun should_increase_queue_size_on_produce/1,
-        fun should_receive_first_queued_item/1,
-        fun should_consume_multiple_items/1,
-        fun should_consume_all/1
-    ].
-
-single_consumer_max_items_and_size() ->
-    single_consumer_max_item_count() ++ single_consumer_max_size().
-
-multiple_consumers() ->
-    [
-        fun should_have_zero_size_for_new_queue/1,
-        fun should_have_no_items_for_new_queue/1,
-        fun should_increase_queue_size_on_produce/1
-    ].
-
-
-should_have_no_items_for_new_queue({Q, _, _}) ->
-    ?_assertEqual(0, couch_work_queue:item_count(Q)).
-
-should_have_zero_size_for_new_queue({Q, _, _}) ->
-    ?_assertEqual(0, couch_work_queue:size(Q)).
-
-should_block_consumer_on_dequeue_from_empty_queue({_, _, Consumers}) when is_list(Consumers) ->
-    [consume(C, 2) || C <- Consumers],
-    Pongs = [ping(C) || C <- Consumers],
-    ?_assertEqual([timeout, timeout, timeout], Pongs);
-should_block_consumer_on_dequeue_from_empty_queue({_, _, Consumer}) ->
-    consume(Consumer, 1),
-    Pong = ping(Consumer),
-    ?_assertEqual(timeout, Pong).
-
-should_consume_right_item({Q, Producer, Consumers}) when is_list(Consumers) ->
-    [consume(C, 3) || C <- Consumers],
-
-    Item1 = produce(Producer, 10),
-    ok = ping(Producer),
-    ?assertEqual(0, couch_work_queue:item_count(Q)),
-    ?assertEqual(0, couch_work_queue:size(Q)),
-
-    Item2 = produce(Producer, 10),
-    ok = ping(Producer),
-    ?assertEqual(0, couch_work_queue:item_count(Q)),
-    ?assertEqual(0, couch_work_queue:size(Q)),
-
-    Item3 = produce(Producer, 10),
-    ok = ping(Producer),
-    ?assertEqual(0, couch_work_queue:item_count(Q)),
-    ?assertEqual(0, couch_work_queue:size(Q)),
-
-    R = [{ping(C), Item}
-         || {C, Item} <- lists:zip(Consumers, [Item1, Item2, Item3])],
-
-    ?_assertEqual([{ok, Item1}, {ok, Item2}, {ok, Item3}], R);
-should_consume_right_item({_, Producer, Consumer}) ->
-    consume(Consumer, 1),
-    Item = produce(Producer, 10),
-    produce(Producer, 20),
-    ok = ping(Producer),
-    ok = ping(Consumer),
-    {ok, Items} = last_consumer_items(Consumer),
-    ?_assertEqual([Item], Items).
-
-should_increase_queue_size_on_produce({Q, Producer, _}) ->
-    produce(Producer, 50),
-    ok = ping(Producer),
-    Count1 = couch_work_queue:item_count(Q),
-    Size1 = couch_work_queue:size(Q),
-
-    produce(Producer, 10),
-    Count2 = couch_work_queue:item_count(Q),
-    Size2 = couch_work_queue:size(Q),
-
-    ?_assertEqual([{Count1, Size1}, {Count2, Size2}], [{1, 50}, {2, 60}]).
-
-should_block_producer_on_full_queue_count({Q, Producer, _}) ->
-    produce(Producer, 10),
-    ?assertEqual(1, couch_work_queue:item_count(Q)),
-    ok = ping(Producer),
-
-    produce(Producer, 15),
-    ?assertEqual(2, couch_work_queue:item_count(Q)),
-    ok = ping(Producer),
-
-    produce(Producer, 20),
-    ?assertEqual(3, couch_work_queue:item_count(Q)),
-    Pong = ping(Producer),
-
-    ?_assertEqual(timeout, Pong).
-
-should_block_producer_on_full_queue_size({Q, Producer, _}) ->
-    produce(Producer, 100),
-    ok = ping(Producer),
-    ?assertEqual(1, couch_work_queue:item_count(Q)),
-    ?assertEqual(100, couch_work_queue:size(Q)),
-
-    produce(Producer, 110),
-    Pong = ping(Producer),
-    ?assertEqual(2, couch_work_queue:item_count(Q)),
-    ?assertEqual(210, couch_work_queue:size(Q)),
-
-    ?_assertEqual(timeout, Pong).
-
-should_consume_multiple_items({_, Producer, Consumer}) ->
-    Item1 = produce(Producer, 10),
-    ok = ping(Producer),
-
-    Item2 = produce(Producer, 15),
-    ok = ping(Producer),
-
-    consume(Consumer, 2),
-
-    {ok, Items} = last_consumer_items(Consumer),
-    ?_assertEqual([Item1, Item2], Items).
-
-should_receive_first_queued_item({Q, Producer, Consumer}) ->
-    consume(Consumer, 100),
-    timeout = ping(Consumer),
-
-    Item = produce(Producer, 11),
-    ok = ping(Producer),
-
-    ok = ping(Consumer),
-    ?assertEqual(0, couch_work_queue:item_count(Q)),
-
-    {ok, Items} = last_consumer_items(Consumer),
-    ?_assertEqual([Item], Items).
-
-should_consume_all({_, Producer, Consumer}) ->
-    Item1 = produce(Producer, 10),
-    Item2 = produce(Producer, 15),
-    Item3 = produce(Producer, 20),
-
-    consume(Consumer, all),
-
-    {ok, Items} = last_consumer_items(Consumer),
-    ?_assertEqual([Item1, Item2, Item3], Items).
-
-should_timeout_on_close_non_empty_queue({Q, Producer, _}) ->
-    produce(Producer, 1),
-    Status = close_queue(Q),
-
-    ?_assertEqual(timeout, Status).
-
-should_not_block_producer_for_non_empty_queue_after_close({Q, Producer, _}) ->
-    produce(Producer, 1),
-    close_queue(Q),
-    Pong = ping(Producer),
-    Size = couch_work_queue:size(Q),
-    Count = couch_work_queue:item_count(Q),
-
-    ?_assertEqual({ok, 1, 1}, {Pong, Size, Count}).
-
-should_be_closed({Q, _, Consumers}) when is_list(Consumers) ->
-    ok = close_queue(Q),
-
-    [consume(C, 1) || C <- Consumers],
-
-    LastConsumerItems = [last_consumer_items(C) || C <- Consumers],
-    ItemsCount = couch_work_queue:item_count(Q),
-    Size = couch_work_queue:size(Q),
-
-    ?_assertEqual({[closed, closed, closed], closed, closed},
-                  {LastConsumerItems, ItemsCount, Size});
-should_be_closed({Q, _, Consumer}) ->
-    ok = close_queue(Q),
-
-    consume(Consumer, 1),
-
-    LastConsumerItems = last_consumer_items(Consumer),
-    ItemsCount = couch_work_queue:item_count(Q),
-    Size = couch_work_queue:size(Q),
-
-    ?_assertEqual({closed, closed, closed},
-                  {LastConsumerItems, ItemsCount, Size}).
-
-
-close_queue(Q) ->
-    ok = couch_work_queue:close(Q),
-    MonRef = erlang:monitor(process, Q),
-    receive
-        {'DOWN', MonRef, process, Q, _Reason} -> ok
-    after ?TIMEOUT ->
-        erlang:demonitor(MonRef),
-        timeout
-    end.
-
-spawn_consumer(Q) ->
-    Parent = self(),
-    spawn(fun() -> consumer_loop(Parent, Q, nil) end).
-
-consumer_loop(Parent, Q, PrevItem) ->
-    receive
-        {stop, Ref} ->
-            Parent ! {ok, Ref};
-        {ping, Ref} ->
-            Parent ! {pong, Ref},
-            consumer_loop(Parent, Q, PrevItem);
-        {last_item, Ref} ->
-            Parent ! {item, Ref, PrevItem},
-            consumer_loop(Parent, Q, PrevItem);
-        {consume, N} ->
-            Result = couch_work_queue:dequeue(Q, N),
-            consumer_loop(Parent, Q, Result)
-    end.
-
-spawn_producer(Q) ->
-    Parent = self(),
-    spawn(fun() -> producer_loop(Parent, Q) end).
-
-producer_loop(Parent, Q) ->
-    receive
-        {stop, Ref} ->
-            Parent ! {ok, Ref};
-        {ping, Ref} ->
-            Parent ! {pong, Ref},
-            producer_loop(Parent, Q);
-        {produce, Ref, Size} ->
-            Item = crypto:rand_bytes(Size),
-            Parent ! {item, Ref, Item},
-            ok = couch_work_queue:queue(Q, Item),
-            producer_loop(Parent, Q)
-    end.
-
-consume(Consumer, N) ->
-    Consumer ! {consume, N}.
-
-last_consumer_items(Consumer) ->
-    Ref = make_ref(),
-    Consumer ! {last_item, Ref},
-    receive
-        {item, Ref, Items} ->
-            Items
-    after ?TIMEOUT ->
-        timeout
-    end.
-
-produce(Producer, Size) ->
-    Ref = make_ref(),
-    Producer ! {produce, Ref, Size},
-    receive
-        {item, Ref, Item} ->
-            Item
-    after ?TIMEOUT ->
-        erlang:error({assertion_failed,
-                      [{module, ?MODULE},
-                       {line, ?LINE},
-                       {reason, "Timeout asking producer to produce an item"}]})
-    end.
-
-ping(Pid) ->
-    Ref = make_ref(),
-    Pid ! {ping, Ref},
-    receive
-        {pong, Ref} ->
-            ok
-    after ?TIMEOUT ->
-        timeout
-    end.
-
-stop(Pid, Name) ->
-    Ref = make_ref(),
-    Pid ! {stop, Ref},
-    receive
-        {ok, Ref} -> ok
-    after ?TIMEOUT ->
-        ?debugMsg("Timeout stopping " ++ Name),
-        timeout
-    end.