Add tests for process pool

This adds tests for re-use of procs,
proper waiters dequeue and idle pool reduction


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

Branch: refs/heads/master
Commit: b4c05798e8e0ce3012156dd82e83905b8e4f581b
Parents: f0b8451
Author: Eric Avdey <[email protected]>
Authored: Mon Aug 15 13:45:20 2016 -0300
Committer: Eric Avdey <[email protected]>
Committed: Tue Aug 16 12:06:15 2016 -0300

----------------------------------------------------------------------
 src/couch_query_servers.erl   |   2 +-
 test/couchdb_os_proc_pool.erl | 146 ++++++++++++++++++++++++++++++++++---
 2 files changed, 136 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/b4c05798/src/couch_query_servers.erl
----------------------------------------------------------------------
diff --git a/src/couch_query_servers.erl b/src/couch_query_servers.erl
index a3d7a47..ea7628e 100644
--- a/src/couch_query_servers.erl
+++ b/src/couch_query_servers.erl
@@ -22,7 +22,7 @@
 -export([with_ddoc_proc/2, proc_prompt/2, ddoc_prompt/3, ddoc_proc_prompt/3, 
json_doc/1]).
 
 % For 210-os-proc-pool.t
--export([get_os_process/1, ret_os_process/1]).
+-export([get_os_process/1, get_ddoc_process/2, ret_os_process/1]).
 
 -include_lib("couch/include/couch_db.hrl").
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/b4c05798/test/couchdb_os_proc_pool.erl
----------------------------------------------------------------------
diff --git a/test/couchdb_os_proc_pool.erl b/test/couchdb_os_proc_pool.erl
index a698070..54d19f0 100644
--- a/test/couchdb_os_proc_pool.erl
+++ b/test/couchdb_os_proc_pool.erl
@@ -15,26 +15,33 @@
 -include_lib("couch/include/couch_eunit.hrl").
 -include_lib("couch/include/couch_db.hrl").
 
--define(TIMEOUT, 3000).
+-define(TIMEOUT, 1000).
 
 
-start() ->
-    Ctx = test_util:start_couch(),
-    config:set("query_server_config", "os_process_limit", "3", false),
-    timer:sleep(100), %% we need to wait to let gen_server:cast finish
-    Ctx.
+setup() ->
+    ok = couch_proc_manager:reload(),
+    ok = setup_config().
 
+teardown(_) ->
+    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()
-            ]
+            fun test_util:start_couch/0, fun test_util:stop_couch/1,
+            {
+                foreach,
+                fun setup/0, fun teardown/1,
+                [
+                    should_block_new_proc_on_full_pool(),
+                    should_free_slot_on_proc_unexpected_exit(),
+                    should_reuse_known_proc(),
+                    should_process_waiting_queue_as_fifo(),
+                    should_reduce_pool_on_idle_os_procs()
+                ]
+            }
         }
     }.
 
@@ -115,6 +122,112 @@ should_free_slot_on_proc_unexpected_exit() ->
     end).
 
 
+should_reuse_known_proc() ->
+    ?_test(begin
+        Client1 = spawn_client(<<"ddoc1">>),
+        Client2 = spawn_client(<<"ddoc2">>),
+
+        ?assertEqual(ok, ping_client(Client1)),
+        ?assertEqual(ok, ping_client(Client2)),
+
+        Proc1 = get_client_proc(Client1, "1"),
+        Proc2 = get_client_proc(Client2, "2"),
+        ?assertNotEqual(Proc1#proc.pid, Proc2#proc.pid),
+
+        ?assertEqual(ok, stop_client(Client1)),
+        ?assertEqual(ok, stop_client(Client2)),
+        ?assert(is_process_alive(Proc1#proc.pid)),
+        ?assert(is_process_alive(Proc2#proc.pid)),
+
+        Client1Again = spawn_client(<<"ddoc1">>),
+        ?assertEqual(ok, ping_client(Client1Again)),
+        Proc1Again = get_client_proc(Client1Again, "1-again"),
+        ?assertEqual(Proc1#proc.pid, Proc1Again#proc.pid),
+        ?assertNotEqual(Proc1#proc.client, Proc1Again#proc.client),
+        ?assertEqual(ok, stop_client(Client1Again))
+    end).
+
+
+should_process_waiting_queue_as_fifo() ->
+    ?_test(begin
+        Client1 = spawn_client(<<"ddoc1">>),
+        Client2 = spawn_client(<<"ddoc2">>),
+        Client3 = spawn_client(<<"ddoc3">>),
+        Client4 = spawn_client(<<"ddoc4">>),
+        Client5 = spawn_client(<<"ddoc5">>),
+
+        ?assertEqual(ok, ping_client(Client1)),
+        ?assertEqual(ok, ping_client(Client2)),
+        ?assertEqual(ok, ping_client(Client3)),
+        ?assertEqual(timeout, ping_client(Client4)),
+        ?assertEqual(timeout, ping_client(Client5)),
+
+        Proc1 = get_client_proc(Client1, "1"),
+        ?assertEqual(ok, stop_client(Client1)),
+        ?assertEqual(ok, ping_client(Client4)),
+        Proc4 = get_client_proc(Client4, "4"),
+
+        ?assertNotEqual(Proc4#proc.client, Proc1#proc.client),
+        ?assertEqual(Proc1#proc.pid, Proc4#proc.pid),
+        ?assertEqual(timeout, ping_client(Client5)),
+
+        ?assertEqual(ok, stop_client(Client2)),
+        ?assertEqual(ok, stop_client(Client3)),
+        ?assertEqual(ok, stop_client(Client4)),
+        ?assertEqual(ok, stop_client(Client5))
+    end).
+
+
+should_reduce_pool_on_idle_os_procs() ->
+    ?_test(begin
+        %% os_process_idle_limit is in sec
+        config:set("query_server_config",
+            "os_process_idle_limit", "1", false),
+        ok = confirm_config("os_process_idle_limit", "1"),
+
+        Client1 = spawn_client(<<"ddoc1">>),
+        Client2 = spawn_client(<<"ddoc2">>),
+        Client3 = spawn_client(<<"ddoc3">>),
+
+        ?assertEqual(ok, ping_client(Client1)),
+        ?assertEqual(ok, ping_client(Client2)),
+        ?assertEqual(ok, ping_client(Client3)),
+
+        ?assertEqual(3, couch_proc_manager:get_proc_count()),
+
+        ?assertEqual(ok, stop_client(Client1)),
+        ?assertEqual(ok, stop_client(Client2)),
+        ?assertEqual(ok, stop_client(Client3)),
+
+        timer:sleep(1200),
+        ?assertEqual(1, couch_proc_manager:get_proc_count())
+    end).
+
+
+setup_config() ->
+    config:set("query_server_config", "os_process_limit", "3", false),
+    config:set("query_server_config", "os_process_soft_limit", "2", false),
+    ok = confirm_config("os_process_soft_limit", "2").
+
+confirm_config(Key, Value) ->
+    confirm_config(Key, Value, 0).
+
+confirm_config(Key, Value, Count) ->
+    case config:get("query_server_config", Key) of
+        Value ->
+            ok;
+        _ when Count > 10 ->
+            erlang:error({config_setup, [
+                {module, ?MODULE},
+                {line, ?LINE},
+                {value, timeout}
+            ]});
+        _ ->
+            %% we need to wait to let gen_server:cast finish
+            timer:sleep(10),
+            confirm_config(Key, Value, Count + 1)
+    end.
+
 spawn_client() ->
     Parent = self(),
     Ref = make_ref(),
@@ -124,6 +237,17 @@ spawn_client() ->
     end),
     {Pid, Ref}.
 
+spawn_client(DDocId) ->
+    Parent = self(),
+    Ref = make_ref(),
+    Pid = spawn(fun() ->
+        DDocKey = {DDocId, <<"1-abcdefgh">>},
+        DDoc = #doc{body={[]}},
+        Proc = couch_query_servers:get_ddoc_process(DDoc, DDocKey),
+        loop(Parent, Ref, Proc)
+    end),
+    {Pid, Ref}.
+
 ping_client({Pid, Ref}) ->
     Pid ! ping,
     receive

Reply via email to