Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fix merge conflict and be verbose when running tests

  • Loading branch information...
commit a71e5220e1b393baff0887d4eb52b3bd6c3fcb7a 2 parents b901dc6 + e038af9
Devin Torres authored
View
0  .eunit/cover.log
No changes.
View
13 .eunit/index.html
@@ -0,0 +1,13 @@
+<html><head><title>Coverage Summary</title></head>
+<body><h1>Source Summary</h1>
+<h3>Total: 83%</h3>
+<table><tr><th>Module</th><th>Coverage %</th></tr>
+<tr><td><a href='poolboy.COVER.html'>poolboy</a></td><td>82%</td>
+<tr><td><a href='poolboy_sup.COVER.html'>poolboy_sup</a></td><td>100%</td>
+</table>
+<body><h1>Test Summary</h1>
+<h3>Total: 55%</h3>
+<table><tr><th>Module</th><th>Coverage %</th></tr>
+<tr><td><a href='poolboy_test_worker.COVER.html'>poolboy_test_worker</a></td><td>55%</td>
+</table>
+</body></html>
View
251 .eunit/poolboy.COVER.html
@@ -0,0 +1,251 @@
+<html>
+<head><title>.eunit/poolboy.COVER.html</title></head><body bgcolor=white text=black>
+<pre>
+File generated from /Users/devin/Projects/poolboy/.eunit/poolboy.erl by COVER 2011-08-25 at 12:43:42
+
+****************************************************************************
+
+ | %% Poolboy - A hunky Erlang worker pool factory
+ |
+ | -module(poolboy).
+ | -behaviour(gen_fsm).
+ |
+ | -export([checkout/1, checkin/2, start_link/1, init/1, ready/2, ready/3,
+ | overflow/2, overflow/3, full/2, full/3, handle_event/3,
+ | handle_sync_event/4, handle_info/3, terminate/3, code_change/4]).
+ |
+ | -record(state, {workers, worker_sup, waiting=queue:new(), monitors=[],
+ | size=5, overflow=0, max_overflow=10, checkout_blocks=true}).
+ |
+ | checkin(Pool, Worker) -&gt;
+ 24..| gen_fsm:send_event(Pool, {checkin, Worker}).
+ |
+ | checkout(Pool) -&gt;
+ 68..| gen_fsm:sync_send_event(Pool, checkout).
+ |
+ | start_link(Args) -&gt;
+ 9..| case proplists:get_value(name, Args) of
+ | undefined -&gt;
+<font color=red> 0..| gen_fsm:start_link(?MODULE, Args, []);</font>
+ | Name -&gt;
+ 9..| gen_fsm:start_link(Name, ?MODULE, Args, [])
+ | end.
+ |
+ | init(Args) -&gt;
+ 9..| process_flag(trap_exit, true),
+ 9..| init(Args, #state{}).
+ |
+ | init([{worker_module, Mod} | Rest], State) -&gt;
+ 9..| {ok, Sup} = poolboy_sup:start_link(Mod, Rest),
+ 9..| init(Rest, State#state{worker_sup=Sup});
+ | init([{size, PoolSize} | Rest], State) -&gt;
+ 9..| init(Rest, State#state{size=PoolSize});
+ | init([{max_overflow, MaxOverflow} | Rest], State) -&gt;
+ 9..| init(Rest, State#state{max_overflow=MaxOverflow});
+ | init([{checkout_blocks, CheckoutBlocks} | Rest], State) -&gt;
+ 2..| init(Rest, State#state{checkout_blocks=CheckoutBlocks});
+ | init([_ | Rest], State) -&gt;
+ 9..| init(Rest, State);
+ | init([], #state{size=Size, worker_sup=Sup}=State) -&gt;
+ 9..| Workers = prepopulate(Size, Sup),
+ 9..| {ok, ready, State#state{workers=Workers}}.
+ |
+ | ready({checkin, Pid}, State) -&gt;
+ 15..| Workers = queue:in(Pid, State#state.workers),
+ 15..| Monitors = case lists:keytake(Pid, 1, State#state.monitors) of
+ 15..| {value, {_, Ref}, Left} -&gt; erlang:demonitor(Ref), Left;
+<font color=red> 0..| false -&gt; []</font>
+ | end,
+ 15..| {next_state, ready, State#state{workers=Workers, monitors=Monitors}};
+ | ready(_Event, State) -&gt;
+<font color=red> 0..| {next_state, ready, State}.</font>
+ |
+ | ready(checkout, {FromPid, _} = From, #state{workers=Workers, worker_sup=Sup,
+ | max_overflow=MaxOverflow,
+ | checkout_blocks=Blocks}=State) -&gt;
+ 54..| case queue:out(Workers) of
+ | {{value, Pid}, Left} -&gt;
+ 46..| Ref = erlang:monitor(process, FromPid),
+ 46..| Monitors = [{Pid, Ref} | State#state.monitors],
+ 46..| {reply, Pid, ready, State#state{workers=Left,
+ | monitors=Monitors}};
+ | {empty, Empty} when MaxOverflow &gt; 0 -&gt;
+ 5..| {Pid, Ref} = new_worker(Sup, FromPid),
+ 5..| Monitors = [{Pid, Ref} | State#state.monitors],
+ 5..| {reply, Pid, overflow, State#state{workers=Empty,
+ | monitors=Monitors,
+ | overflow=1}};
+ | {empty, Empty} when Blocks == false -&gt;
+ | %% don't block the calling process
+ 1..| {reply, full, full, State#state{workers=Empty}};
+ | {empty, Empty} -&gt;
+ 2..| Waiting = State#state.waiting,
+ 2..| {next_state, full, State#state{workers=Empty,
+ | waiting=queue:in(From, Waiting)}}
+ | end;
+ | ready(_Event, _From, State) -&gt;
+<font color=red> 0..| {reply, ok, ready, State}.</font>
+ |
+ | overflow({checkin, Pid}, #state{overflow=1}=State) -&gt;
+ 2..| dismiss_worker(Pid),
+ 2..| {next_state, ready, State#state{overflow=0}};
+ | overflow({checkin, Pid}, #state{overflow=Overflow}=State) -&gt;
+ 1..| dismiss_worker(Pid),
+ 1..| {next_state, overflow, State#state{overflow=Overflow-1}};
+ | overflow(_Event, State) -&gt;
+<font color=red> 0..| {next_state, overflow, State}.</font>
+ |
+ | overflow(checkout, From, #state{overflow=Overflow,
+ | max_overflow=MaxOverflow,
+ | checkout_blocks=Blocks}=State) when Overflow &gt;= MaxOverflow -&gt;
+ 4..| case Blocks of
+ | false -&gt;
+ 2..| {reply, full, full, State};
+ | _ -&gt;
+ 2..| Waiting = State#state.waiting,
+ 2..| {next_state, full, State#state{waiting=queue:in(From, Waiting)}}
+ | end;
+ | overflow(checkout, {From, _}, #state{worker_sup=Sup,
+ | overflow=Overflow}=State) -&gt;
+ 9..| {Pid, Ref} = new_worker(Sup, From),
+ 9..| Monitors = [{Pid, Ref} | State#state.monitors],
+ 9..| {reply, Pid, overflow, State#state{monitors=Monitors,
+ | overflow=Overflow+1}};
+ | overflow(_Event, _From, State) -&gt;
+<font color=red> 0..| {reply, ok, overflow, State}.</font>
+ |
+ | full({checkin, Pid}, #state{waiting=Waiting, max_overflow=MaxOverflow,
+ | overflow=Overflow}=State) -&gt;
+ 6..| case queue:out(Waiting) of
+ | {{value, {FromPid, _}=From}, Left} -&gt;
+ 2..| Ref = erlang:monitor(process, FromPid),
+ 2..| Monitors = [{Pid, Ref} | State#state.monitors],
+ 2..| gen_fsm:reply(From, Pid),
+ 2..| {next_state, full, State#state{waiting=Left,
+ | monitors=Monitors}};
+ | {empty, Empty} when MaxOverflow &lt; 1 -&gt;
+ 2..| Workers = queue:in(Pid, State#state.workers),
+ 2..| Monitors = case lists:keytake(Pid, 1, State#state.monitors) of
+ 2..| {value, {_, Ref}, Left} -&gt; erlang:demonitor(Ref), Left;
+<font color=red> 0..| false -&gt; []</font>
+ | end,
+ 2..| {next_state, ready, State#state{workers=Workers, waiting=Empty,
+ | monitors=Monitors}};
+ | {empty, Empty} -&gt;
+ 2..| dismiss_worker(Pid),
+ 2..| {next_state, overflow, State#state{waiting=Empty,
+ | overflow=Overflow-1}}
+ | end;
+ | full(_Event, State) -&gt;
+<font color=red> 0..| {next_state, full, State}.</font>
+ |
+ | full(checkout, _From, #state{checkout_blocks=false}=State) -&gt;
+ 1..| {reply, full, full, State};
+ | full(checkout, From, #state{waiting=Waiting}=State) -&gt;
+<font color=red> 0..| {next_state, full, State#state{waiting=queue:in(From, Waiting)}};</font>
+ | full(_Event, _From, State) -&gt;
+<font color=red> 0..| {reply, ok, full, State}.</font>
+ |
+ | handle_event(_Event, StateName, State) -&gt;
+<font color=red> 0..| {next_state, StateName, State}.</font>
+ |
+ | handle_sync_event(get_avail_workers, _From, StateName, #state{workers=Workers}=State) -&gt;
+ 31..| WorkerList = queue:to_list(Workers),
+ 31..| {reply, WorkerList, StateName, State};
+ | handle_sync_event(get_all_workers, _From, StateName, #state{worker_sup=Sup}=State) -&gt;
+ 24..| WorkerList = supervisor:which_children(Sup),
+ 24..| {reply, WorkerList, StateName, State};
+ | handle_sync_event(stop, _From, _StateName, State) -&gt;
+ 9..| {stop, normal, ok, State};
+ | handle_sync_event(_Event, _From, StateName, State) -&gt;
+<font color=red> 0..| Reply = {error, invalid_message},</font>
+<font color=red> 0..| {reply, Reply, StateName, State}.</font>
+ |
+ | handle_info({'DOWN', Ref, _, _, _}, StateName, State) -&gt;
+ 3..| case lists:keytake(Ref, 2, State#state.monitors) of
+ 3..| {value, {Pid, _}, _} -&gt; dismiss_worker(Pid);
+<font color=red> 0..| false -&gt; false</font>
+ | end,
+ 3..| {next_state, StateName, State};
+ | handle_info({'EXIT', Pid, _}, StateName, #state{worker_sup=Sup,
+ | overflow=Overflow,
+ | waiting=Waiting,
+ | max_overflow=MaxOverflow}=State) -&gt;
+ 11..| Monitors = case lists:keytake(Pid, 1, State#state.monitors) of
+ 11..| {value, {_, Ref}, Left} -&gt; erlang:demonitor(Ref), Left;
+<font color=red> 0..| false -&gt; []</font>
+ | end,
+ 11..| case StateName of
+ | ready -&gt;
+ 5..| W = queue:filter(fun (P) -&gt; P =/= Pid end, State#state.workers),
+ 5..| {next_state, ready, State#state{workers=queue:in(new_worker(Sup), W),
+ | monitors=Monitors}};
+ | overflow when Overflow =&lt; 1 -&gt;
+ 1..| {next_state, ready, State#state{monitors=Monitors, overflow=0}};
+ | overflow -&gt;
+ 1..| {next_state, overflow, State#state{monitors=Monitors,
+ | overflow=Overflow-1}};
+ | full when MaxOverflow &lt; 1 -&gt;
+ 2..| case queue:out(Waiting) of
+ | {{value, {FromPid, _} = From}, LeftWaiting} -&gt;
+ 1..| MonitorRef = erlang:monitor(process, FromPid),
+ 1..| Monitors2 = [{FromPid, MonitorRef} | Monitors],
+ 1..| NewWorker = new_worker(Sup),
+ 1..| gen_fsm:reply(From, NewWorker),
+ 1..| {next_state, full, State#state{waiting=LeftWaiting,
+ | monitors=Monitors2}};
+ | {empty, Empty} -&gt;
+ 1..| {next_state, ready, State#state{monitors=Monitors,waiting=Empty,
+ | workers=queue:in(new_worker(Sup), State#state.workers)}}
+ | end;
+ | full when Overflow =&lt; MaxOverflow -&gt;
+ 2..| case queue:out(Waiting) of
+ | {{value, {FromPid, _} = From}, LeftWaiting} -&gt;
+ 1..| MonitorRef = erlang:monitor(process, FromPid),
+ 1..| Monitors2 = [{FromPid, MonitorRef} | Monitors],
+ 1..| NewWorker = new_worker(Sup),
+ 1..| gen_fsm:reply(From, NewWorker),
+ 1..| {next_state, full, State#state{waiting=LeftWaiting,
+ | monitors=Monitors2}};
+ | {empty, Empty} -&gt;
+ 1..| {next_state, overflow, State#state{monitors=Monitors,
+ | overflow=Overflow-1, waiting=Empty}}
+ | end;
+ | full -&gt;
+<font color=red> 0..| {next_state, full, State#state{monitors=Monitors,</font>
+ | overflow=Overflow-1}}
+ | end;
+ | handle_info(_Info, StateName, State) -&gt;
+<font color=red> 0..| {next_state, StateName, State}.</font>
+ |
+ 9..| terminate(_Reason, _StateName, _State) -&gt; ok.
+ |
+ | code_change(_OldVsn, StateName, State, _Extra) -&gt;
+<font color=red> 0..| {ok, StateName, State}.</font>
+ |
+ | new_worker(Sup) -&gt;
+ 72..| {ok, Pid} = supervisor:start_child(Sup, []),
+ 72..| link(Pid),
+ 72..| Pid.
+ |
+ | new_worker(Sup, FromPid) -&gt;
+ 14..| Pid = new_worker(Sup),
+ 14..| Ref = erlang:monitor(process, FromPid),
+ 14..| {Pid, Ref}.
+ |
+ | dismiss_worker(Pid) -&gt;
+ 8..| unlink(Pid),
+ 8..| Pid ! stop.
+ |
+ | prepopulate(0, _Sup) -&gt;
+<font color=red> 0..| queue:new();</font>
+ | prepopulate(N, Sup) -&gt;
+ 9..| prepopulate(N, Sup, queue:new()).
+ |
+ | prepopulate(0, _Sup, Workers) -&gt;
+ 9..| Workers;
+ | prepopulate(N, Sup, Workers) -&gt;
+ 50..| prepopulate(N-1, Sup, queue:in(new_worker(Sup), Workers)).
+</pre>
+</body>
+</html>
View
241 .eunit/poolboy.erl
@@ -0,0 +1,241 @@
+%% Poolboy - A hunky Erlang worker pool factory
+
+-module(poolboy).
+-behaviour(gen_fsm).
+
+-export([checkout/1, checkin/2, start_link/1, init/1, ready/2, ready/3,
+ overflow/2, overflow/3, full/2, full/3, handle_event/3,
+ handle_sync_event/4, handle_info/3, terminate/3, code_change/4]).
+
+-record(state, {workers, worker_sup, waiting=queue:new(), monitors=[],
+ size=5, overflow=0, max_overflow=10, checkout_blocks=true}).
+
+checkin(Pool, Worker) ->
+ gen_fsm:send_event(Pool, {checkin, Worker}).
+
+checkout(Pool) ->
+ gen_fsm:sync_send_event(Pool, checkout).
+
+start_link(Args) ->
+ case proplists:get_value(name, Args) of
+ undefined ->
+ gen_fsm:start_link(?MODULE, Args, []);
+ Name ->
+ gen_fsm:start_link(Name, ?MODULE, Args, [])
+ end.
+
+init(Args) ->
+ process_flag(trap_exit, true),
+ init(Args, #state{}).
+
+init([{worker_module, Mod} | Rest], State) ->
+ {ok, Sup} = poolboy_sup:start_link(Mod, Rest),
+ init(Rest, State#state{worker_sup=Sup});
+init([{size, PoolSize} | Rest], State) ->
+ init(Rest, State#state{size=PoolSize});
+init([{max_overflow, MaxOverflow} | Rest], State) ->
+ init(Rest, State#state{max_overflow=MaxOverflow});
+init([{checkout_blocks, CheckoutBlocks} | Rest], State) ->
+ init(Rest, State#state{checkout_blocks=CheckoutBlocks});
+init([_ | Rest], State) ->
+ init(Rest, State);
+init([], #state{size=Size, worker_sup=Sup}=State) ->
+ Workers = prepopulate(Size, Sup),
+ {ok, ready, State#state{workers=Workers}}.
+
+ready({checkin, Pid}, State) ->
+ Workers = queue:in(Pid, State#state.workers),
+ Monitors = case lists:keytake(Pid, 1, State#state.monitors) of
+ {value, {_, Ref}, Left} -> erlang:demonitor(Ref), Left;
+ false -> []
+ end,
+ {next_state, ready, State#state{workers=Workers, monitors=Monitors}};
+ready(_Event, State) ->
+ {next_state, ready, State}.
+
+ready(checkout, {FromPid, _} = From, #state{workers=Workers, worker_sup=Sup,
+ max_overflow=MaxOverflow,
+ checkout_blocks=Blocks}=State) ->
+ case queue:out(Workers) of
+ {{value, Pid}, Left} ->
+ Ref = erlang:monitor(process, FromPid),
+ Monitors = [{Pid, Ref} | State#state.monitors],
+ {reply, Pid, ready, State#state{workers=Left,
+ monitors=Monitors}};
+ {empty, Empty} when MaxOverflow > 0 ->
+ {Pid, Ref} = new_worker(Sup, FromPid),
+ Monitors = [{Pid, Ref} | State#state.monitors],
+ {reply, Pid, overflow, State#state{workers=Empty,
+ monitors=Monitors,
+ overflow=1}};
+ {empty, Empty} when Blocks == false ->
+ %% don't block the calling process
+ {reply, full, full, State#state{workers=Empty}};
+ {empty, Empty} ->
+ Waiting = State#state.waiting,
+ {next_state, full, State#state{workers=Empty,
+ waiting=queue:in(From, Waiting)}}
+ end;
+ready(_Event, _From, State) ->
+ {reply, ok, ready, State}.
+
+overflow({checkin, Pid}, #state{overflow=1}=State) ->
+ dismiss_worker(Pid),
+ {next_state, ready, State#state{overflow=0}};
+overflow({checkin, Pid}, #state{overflow=Overflow}=State) ->
+ dismiss_worker(Pid),
+ {next_state, overflow, State#state{overflow=Overflow-1}};
+overflow(_Event, State) ->
+ {next_state, overflow, State}.
+
+overflow(checkout, From, #state{overflow=Overflow,
+ max_overflow=MaxOverflow,
+ checkout_blocks=Blocks}=State) when Overflow >= MaxOverflow ->
+ case Blocks of
+ false ->
+ {reply, full, full, State};
+ _ ->
+ Waiting = State#state.waiting,
+ {next_state, full, State#state{waiting=queue:in(From, Waiting)}}
+ end;
+overflow(checkout, {From, _}, #state{worker_sup=Sup,
+ overflow=Overflow}=State) ->
+ {Pid, Ref} = new_worker(Sup, From),
+ Monitors = [{Pid, Ref} | State#state.monitors],
+ {reply, Pid, overflow, State#state{monitors=Monitors,
+ overflow=Overflow+1}};
+overflow(_Event, _From, State) ->
+ {reply, ok, overflow, State}.
+
+full({checkin, Pid}, #state{waiting=Waiting, max_overflow=MaxOverflow,
+ overflow=Overflow}=State) ->
+ case queue:out(Waiting) of
+ {{value, {FromPid, _}=From}, Left} ->
+ Ref = erlang:monitor(process, FromPid),
+ Monitors = [{Pid, Ref} | State#state.monitors],
+ gen_fsm:reply(From, Pid),
+ {next_state, full, State#state{waiting=Left,
+ monitors=Monitors}};
+ {empty, Empty} when MaxOverflow < 1 ->
+ Workers = queue:in(Pid, State#state.workers),
+ Monitors = case lists:keytake(Pid, 1, State#state.monitors) of
+ {value, {_, Ref}, Left} -> erlang:demonitor(Ref), Left;
+ false -> []
+ end,
+ {next_state, ready, State#state{workers=Workers, waiting=Empty,
+ monitors=Monitors}};
+ {empty, Empty} ->
+ dismiss_worker(Pid),
+ {next_state, overflow, State#state{waiting=Empty,
+ overflow=Overflow-1}}
+ end;
+full(_Event, State) ->
+ {next_state, full, State}.
+
+full(checkout, _From, #state{checkout_blocks=false}=State) ->
+ {reply, full, full, State};
+full(checkout, From, #state{waiting=Waiting}=State) ->
+ {next_state, full, State#state{waiting=queue:in(From, Waiting)}};
+full(_Event, _From, State) ->
+ {reply, ok, full, State}.
+
+handle_event(_Event, StateName, State) ->
+ {next_state, StateName, State}.
+
+handle_sync_event(get_avail_workers, _From, StateName, #state{workers=Workers}=State) ->
+ WorkerList = queue:to_list(Workers),
+ {reply, WorkerList, StateName, State};
+handle_sync_event(get_all_workers, _From, StateName, #state{worker_sup=Sup}=State) ->
+ WorkerList = supervisor:which_children(Sup),
+ {reply, WorkerList, StateName, State};
+handle_sync_event(stop, _From, _StateName, State) ->
+ {stop, normal, ok, State};
+handle_sync_event(_Event, _From, StateName, State) ->
+ Reply = {error, invalid_message},
+ {reply, Reply, StateName, State}.
+
+handle_info({'DOWN', Ref, _, _, _}, StateName, State) ->
+ case lists:keytake(Ref, 2, State#state.monitors) of
+ {value, {Pid, _}, _} -> dismiss_worker(Pid);
+ false -> false
+ end,
+ {next_state, StateName, State};
+handle_info({'EXIT', Pid, _}, StateName, #state{worker_sup=Sup,
+ overflow=Overflow,
+ waiting=Waiting,
+ max_overflow=MaxOverflow}=State) ->
+ Monitors = case lists:keytake(Pid, 1, State#state.monitors) of
+ {value, {_, Ref}, Left} -> erlang:demonitor(Ref), Left;
+ false -> []
+ end,
+ case StateName of
+ ready ->
+ W = queue:filter(fun (P) -> P =/= Pid end, State#state.workers),
+ {next_state, ready, State#state{workers=queue:in(new_worker(Sup), W),
+ monitors=Monitors}};
+ overflow when Overflow =< 1 ->
+ {next_state, ready, State#state{monitors=Monitors, overflow=0}};
+ overflow ->
+ {next_state, overflow, State#state{monitors=Monitors,
+ overflow=Overflow-1}};
+ full when MaxOverflow < 1 ->
+ case queue:out(Waiting) of
+ {{value, {FromPid, _} = From}, LeftWaiting} ->
+ MonitorRef = erlang:monitor(process, FromPid),
+ Monitors2 = [{FromPid, MonitorRef} | Monitors],
+ NewWorker = new_worker(Sup),
+ gen_fsm:reply(From, NewWorker),
+ {next_state, full, State#state{waiting=LeftWaiting,
+ monitors=Monitors2}};
+ {empty, Empty} ->
+ {next_state, ready, State#state{monitors=Monitors,waiting=Empty,
+ workers=queue:in(new_worker(Sup), State#state.workers)}}
+ end;
+ full when Overflow =< MaxOverflow ->
+ case queue:out(Waiting) of
+ {{value, {FromPid, _} = From}, LeftWaiting} ->
+ MonitorRef = erlang:monitor(process, FromPid),
+ Monitors2 = [{FromPid, MonitorRef} | Monitors],
+ NewWorker = new_worker(Sup),
+ gen_fsm:reply(From, NewWorker),
+ {next_state, full, State#state{waiting=LeftWaiting,
+ monitors=Monitors2}};
+ {empty, Empty} ->
+ {next_state, overflow, State#state{monitors=Monitors,
+ overflow=Overflow-1, waiting=Empty}}
+ end;
+ full ->
+ {next_state, full, State#state{monitors=Monitors,
+ overflow=Overflow-1}}
+ end;
+handle_info(_Info, StateName, State) ->
+ {next_state, StateName, State}.
+
+terminate(_Reason, _StateName, _State) -> ok.
+
+code_change(_OldVsn, StateName, State, _Extra) ->
+ {ok, StateName, State}.
+
+new_worker(Sup) ->
+ {ok, Pid} = supervisor:start_child(Sup, []),
+ link(Pid),
+ Pid.
+
+new_worker(Sup, FromPid) ->
+ Pid = new_worker(Sup),
+ Ref = erlang:monitor(process, FromPid),
+ {Pid, Ref}.
+
+dismiss_worker(Pid) ->
+ unlink(Pid),
+ Pid ! stop.
+
+prepopulate(0, _Sup) ->
+ queue:new();
+prepopulate(N, Sup) ->
+ prepopulate(N, Sup, queue:new()).
+
+prepopulate(0, _Sup, Workers) ->
+ Workers;
+prepopulate(N, Sup, Workers) ->
+ prepopulate(N-1, Sup, queue:in(new_worker(Sup), Workers)).
View
24 .eunit/poolboy_sup.COVER.html
@@ -0,0 +1,24 @@
+<html>
+<head><title>.eunit/poolboy_sup.COVER.html</title></head><body bgcolor=white text=black>
+<pre>
+File generated from /Users/devin/Projects/poolboy/.eunit/poolboy_sup.erl by COVER 2011-08-25 at 12:43:42
+
+****************************************************************************
+
+ | %% Poolboy - A hunky Erlang worker pool factory
+ |
+ | -module(poolboy_sup).
+ | -behaviour(supervisor).
+ |
+ | -export([start_link/2, init/1]).
+ |
+ | start_link(Mod, Args) -&gt;
+ 9..| supervisor:start_link(?MODULE, {Mod, Args}).
+ |
+ | init({Mod, Args}) -&gt;
+ 9..| {ok, {{simple_one_for_one, 0, 1},
+ | [{Mod, {Mod, start_link, [Args]},
+ | temporary, brutal_kill, worker, [Mod]}]}}.
+</pre>
+</body>
+</html>
View
14 .eunit/poolboy_sup.erl
@@ -0,0 +1,14 @@
+%% Poolboy - A hunky Erlang worker pool factory
+
+-module(poolboy_sup).
+-behaviour(supervisor).
+
+-export([start_link/2, init/1]).
+
+start_link(Mod, Args) ->
+ supervisor:start_link(?MODULE, {Mod, Args}).
+
+init({Mod, Args}) ->
+ {ok, {{simple_one_for_one, 0, 1},
+ [{Mod, {Mod, start_link, [Args]},
+ temporary, brutal_kill, worker, [Mod]}]}}.
View
47 .eunit/poolboy_test_worker.COVER.html
@@ -0,0 +1,47 @@
+<html>
+<head><title>.eunit/poolboy_test_worker.COVER.html</title></head><body bgcolor=white text=black>
+<pre>
+File generated from /Users/devin/Projects/poolboy/.eunit/poolboy_test_worker.erl by COVER 2011-08-25 at 12:43:42
+
+****************************************************************************
+
+ | -module(poolboy_test_worker).
+ |
+ | -behaviour(gen_server).
+ |
+ | -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
+ | code_change/3]).
+ | -export([start_link/1]).
+ |
+ | -record(state, {
+ | }).
+ |
+ | -include_lib("eunit/include/eunit.hrl").
+ |
+ | start_link(_Args) -&gt;
+ 72..| gen_server:start_link(?MODULE, [], []).
+ |
+ | init([]) -&gt;
+ 72..| {ok, #state{}}.
+ |
+ | handle_call(die, _From, State) -&gt;
+ 11..| {stop, {error, died}, dead, State};
+ | handle_call(_Event, _From, State) -&gt;
+<font color=red> 0..| {reply, ok, State}.</font>
+ |
+ | handle_cast(_Event, State) -&gt;
+<font color=red> 0..| {noreply, State}.</font>
+ |
+ | handle_info(stop, State) -&gt;
+ 5..| {stop, normal, State};
+ | handle_info(_Info, State) -&gt;
+<font color=red> 0..| {noreply, State}.</font>
+ |
+ | terminate(_Reason, _State) -&gt;
+ 16..| ok.
+ |
+ | code_change(_OldVsn, State, _Extra) -&gt;
+<font color=red> 0..| {ok, State}.</font>
+</pre>
+</body>
+</html>
View
37 .eunit/poolboy_test_worker.erl
@@ -0,0 +1,37 @@
+-module(poolboy_test_worker).
+
+-behaviour(gen_server).
+
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
+ code_change/3]).
+-export([start_link/1]).
+
+-record(state, {
+ }).
+
+-include_lib("eunit/include/eunit.hrl").
+
+start_link(_Args) ->
+ gen_server:start_link(?MODULE, [], []).
+
+init([]) ->
+ {ok, #state{}}.
+
+handle_call(die, _From, State) ->
+ {stop, {error, died}, dead, State};
+handle_call(_Event, _From, State) ->
+ {reply, ok, State}.
+
+handle_cast(_Event, State) ->
+ {noreply, State}.
+
+handle_info(stop, State) ->
+ {stop, normal, State};
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
View
380 .eunit/poolboy_tests.erl
@@ -0,0 +1,380 @@
+-module(poolboy_tests).
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+pool_test_() ->
+ {foreach,
+ fun() ->
+ error_logger:tty(false)
+ end,
+ fun(_) ->
+ case whereis(poolboy_test) of
+ undefined -> ok;
+ Pid -> gen_fsm:sync_send_all_state_event(Pid, stop)
+ end,
+ error_logger:tty(true)
+ end,
+ [
+ {"Basic pool operations",
+ fun pool_startup/0
+ },
+ {"Pool overflow should work",
+ fun pool_overflow/0
+ },
+ {"Pool behaves right when its empty",
+ fun pool_empty/0
+ },
+ {"Pool behaves right when its empty and oveflow is disabled",
+ fun pool_empty_no_overflow/0
+ },
+ {"Pool behaves right on worker death",
+ fun worker_death/0
+ },
+ {"Pool behaves right when its full and a worker dies",
+ fun worker_death_while_full/0
+ },
+ {"Pool behaves right when its full, a worker dies and overflow is disabled",
+ fun worker_death_while_full_no_overflow/0
+ },
+ {"Non-blocking pool behaves when its full and overflow is disabled",
+ fun pool_full_nonblocking_no_overflow/0
+ },
+ {"Non-blocking pool behaves when its full",
+ fun pool_full_nonblocking/0
+ }
+ ]
+ }.
+
+
+%% tell a worker to exit and await its impending doom
+kill_worker(Pid) ->
+ erlang:monitor(process, Pid),
+ gen_server:call(Pid, die),
+ receive
+ {'DOWN', _, process, Pid, _} ->
+ ok
+ end.
+
+checkin_worker(Pid, Worker) ->
+ %% there's no easy way to wait for a checkin to complete, because its
+ %% async and the supervisor may kill the process if it was an overflow
+ %% worker. Yhe only solution seems to be a nasty hardcoded sleep.
+ poolboy:checkin(Pid, Worker),
+ timer:sleep(500).
+
+pool_startup() ->
+ %% check basic pool operation
+ {ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}}, {worker_module, poolboy_test_worker},
+ {size, 10}, {max_overflow, 5}]),
+ ?assertEqual(10, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ poolboy:checkout(Pid),
+ ?assertEqual(9, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ Worker = poolboy:checkout(Pid),
+ ?assertEqual(8, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ checkin_worker(Pid, Worker),
+ ?assertEqual(9, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ok = gen_fsm:sync_send_all_state_event(Pid, stop).
+
+pool_overflow() ->
+ %% check that the pool overflows properly
+ {ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}}, {worker_module, poolboy_test_worker},
+ {size, 5}, {max_overflow, 5}]),
+ Workers = [poolboy:checkout(Pid) || _ <- lists:seq(0, 6)],
+ ?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(7, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ [A, B, C, D, E, F, G] = Workers,
+ checkin_worker(Pid, A),
+ checkin_worker(Pid, B),
+ ?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ checkin_worker(Pid, C),
+ checkin_worker(Pid, D),
+ ?assertEqual(2, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ checkin_worker(Pid, E),
+ checkin_worker(Pid, F),
+ ?assertEqual(4, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ checkin_worker(Pid, G),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ ok = gen_fsm:sync_send_all_state_event(Pid, stop).
+
+pool_empty() ->
+ %% checks the pool handles the empty condition correctly when overflow is
+ %% enabled.
+ {ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}}, {worker_module, poolboy_test_worker},
+ {size, 5}, {max_overflow, 2}]),
+ Workers = [poolboy:checkout(Pid) || _ <- lists:seq(0, 6)],
+ ?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(7, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ [A, B, C, D, E, F, G] = Workers,
+ Self = self(),
+ spawn(fun() ->
+ Worker = poolboy:checkout(Pid),
+ Self ! got_worker,
+ checkin_worker(Pid, Worker)
+ end),
+ %% spawned process should block waiting for worker to be available
+ receive
+ got_worker -> ?assert(false)
+ after
+ 500 -> ?assert(true)
+ end,
+ checkin_worker(Pid, A),
+ checkin_worker(Pid, B),
+ %% spawned process should have been able to obtain a worker
+ receive
+ got_worker -> ?assert(true)
+ after
+ 500 -> ?assert(false)
+ end,
+ ?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ checkin_worker(Pid, C),
+ checkin_worker(Pid, D),
+ ?assertEqual(2, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ checkin_worker(Pid, E),
+ checkin_worker(Pid, F),
+ ?assertEqual(4, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ checkin_worker(Pid, G),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ ok = gen_fsm:sync_send_all_state_event(Pid, stop).
+
+pool_empty_no_overflow() ->
+ %% checks the pool handles the empty condition properly when overflow is
+ %% disabled
+ {ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}}, {worker_module, poolboy_test_worker},
+ {size, 5}, {max_overflow, 0}]),
+ Workers = [poolboy:checkout(Pid) || _ <- lists:seq(0, 4)],
+ ?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ [A, B, C, D, E] = Workers,
+ Self = self(),
+ spawn(fun() ->
+ Worker = poolboy:checkout(Pid),
+ Self ! got_worker,
+ checkin_worker(Pid, Worker)
+ end),
+ %% spawned process should block waiting for worker to be available
+ receive
+ got_worker -> ?assert(false)
+ after
+ 500 -> ?assert(true)
+ end,
+ checkin_worker(Pid, A),
+ checkin_worker(Pid, B),
+ %% spawned process should have been able to obtain a worker
+ receive
+ got_worker -> ?assert(true)
+ after
+ 500 -> ?assert(false)
+ end,
+ ?assertEqual(2, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ checkin_worker(Pid, C),
+ checkin_worker(Pid, D),
+ ?assertEqual(4, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ checkin_worker(Pid, E),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ ok = gen_fsm:sync_send_all_state_event(Pid, stop).
+
+
+worker_death() ->
+ %% this test checks that dead workers are only restarted when the pool is
+ %% not full if the overflow count is 0. Meaning, don't restart overflow
+ %% workers.
+ {ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}}, {worker_module, poolboy_test_worker},
+ {size, 5}, {max_overflow, 2}]),
+ Worker = poolboy:checkout(Pid),
+ kill_worker(Worker),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ [A, B, C|_Workers] = [poolboy:checkout(Pid) || _ <- lists:seq(0, 6)],
+ ?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(7, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ kill_worker(A),
+ ?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(6, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ kill_worker(B),
+ kill_worker(C),
+ ?assertEqual(1, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ ok = gen_fsm:sync_send_all_state_event(Pid, stop).
+
+worker_death_while_full() ->
+ %% this test checks that if a worker dies while the pool is full and there
+ %% is a queued checkout, a new worker is started and the checkout
+ %serviced. If there are no queued checkouts, a new worker is not started.
+ {ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}}, {worker_module, poolboy_test_worker},
+ {size, 5}, {max_overflow, 2}]),
+ Worker = poolboy:checkout(Pid),
+ kill_worker(Worker),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ [A, B|_Workers] = [poolboy:checkout(Pid) || _ <- lists:seq(0, 6)],
+ ?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(7, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ Self = self(),
+ spawn(fun() ->
+ poolboy:checkout(Pid),
+ Self ! got_worker
+ %% XXX don't release the worker. we want to also test
+ %% what happens when the worker pool is full and a worker
+ %% dies with no queued checkouts.
+ end),
+ %% spawned process should block waiting for worker to be available
+ receive
+ got_worker -> ?assert(false)
+ after
+ 500 -> ?assert(true)
+ end,
+ kill_worker(A),
+ %% spawned process should have been able to obtain a worker
+ receive
+ got_worker -> ?assert(true)
+ after
+ 1000 -> ?assert(false)
+ end,
+ kill_worker(B),
+ ?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(6, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ ok = gen_fsm:sync_send_all_state_event(Pid, stop).
+
+
+worker_death_while_full_no_overflow() ->
+ %% this test tests that if a worker dies while the pool is full AND
+ %% there's no overflow, a new worker is started unconditionally and any
+ %% queued checkouts are serviced
+ {ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}}, {worker_module, poolboy_test_worker},
+ {size, 5}, {max_overflow, 0}]),
+ Worker = poolboy:checkout(Pid),
+ kill_worker(Worker),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ [A, B, C|_Workers] = [poolboy:checkout(Pid) || _ <- lists:seq(0, 4)],
+ ?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ Self = self(),
+ spawn(fun() ->
+ poolboy:checkout(Pid),
+ Self ! got_worker
+ %% XXX do not release, need to also test when worker dies
+ %% and no checkouts queued
+ end),
+ %% spawned process should block waiting for worker to be available
+ receive
+ got_worker -> ?assert(false)
+ after
+ 500 -> ?assert(true)
+ end,
+ kill_worker(A),
+ %% spawned process should have been able to obtain a worker
+ receive
+ got_worker -> ?assert(true)
+ after
+ 1000 -> ?assert(false)
+ end,
+ kill_worker(B),
+ ?assertEqual(1, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ kill_worker(C),
+ ?assertEqual(2, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+
+ ok = gen_fsm:sync_send_all_state_event(Pid, stop).
+
+pool_full_nonblocking_no_overflow() ->
+ %% check that when the pool is full, checkouts return 'full' when the
+ %% option to checkouts nonblocking is enabled.
+ {ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}},
+ {worker_module, poolboy_test_worker},
+ {size, 5}, {max_overflow, 0}, {checkout_blocks, false}]),
+ Workers = [poolboy:checkout(Pid) || _ <- lists:seq(0, 4)],
+ ?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ ?assertEqual(full, poolboy:checkout(Pid)),
+ ?assertEqual(full, poolboy:checkout(Pid)),
+ A = hd(Workers),
+ checkin_worker(Pid, A),
+ ?assertEqual(A, poolboy:checkout(Pid)),
+ ok = gen_fsm:sync_send_all_state_event(Pid, stop).
+
+pool_full_nonblocking() ->
+ %% check that when the pool is full, checkouts return 'full' when the
+ %% option to checkouts nonblocking is enabled.
+ {ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}},
+ {worker_module, poolboy_test_worker},
+ {size, 5}, {max_overflow, 5}, {checkout_blocks, false}]),
+ Workers = [poolboy:checkout(Pid) || _ <- lists:seq(0, 9)],
+ ?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_avail_workers))),
+ ?assertEqual(10, length(gen_fsm:sync_send_all_state_event(Pid,
+ get_all_workers))),
+ ?assertEqual(full, poolboy:checkout(Pid)),
+ A = hd(Workers),
+ checkin_worker(Pid, A),
+ NewWorker = poolboy:checkout(Pid),
+ ?assertEqual(false, is_process_alive(A)), %% overflow workers get shut down
+ ?assert(is_pid(NewWorker)),
+ ?assertEqual(full, poolboy:checkout(Pid)),
+ ok = gen_fsm:sync_send_all_state_event(Pid, stop).
+
+-endif.
+
View
3  rebar.config
@@ -1,2 +1,3 @@
-{cover_enabled, true}.
{erl_opts, [debug_info, warnings_as_errors]}.
+{eunit_opts, [verbose]}.
+{cover_enabled, true}.
View
169 test/poolboy_tests.erl
@@ -3,7 +3,67 @@
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-pool_startup_test() ->
+pool_test_() ->
+ {foreach,
+ fun() ->
+ error_logger:tty(false)
+ end,
+ fun(_) ->
+ case whereis(poolboy_test) of
+ undefined -> ok;
+ Pid -> gen_fsm:sync_send_all_state_event(Pid, stop)
+ end,
+ error_logger:tty(true)
+ end,
+ [
+ {"Basic pool operations",
+ fun pool_startup/0
+ },
+ {"Pool overflow should work",
+ fun pool_overflow/0
+ },
+ {"Pool behaves right when its empty",
+ fun pool_empty/0
+ },
+ {"Pool behaves right when its empty and oveflow is disabled",
+ fun pool_empty_no_overflow/0
+ },
+ {"Pool behaves right on worker death",
+ fun worker_death/0
+ },
+ {"Pool behaves right when its full and a worker dies",
+ fun worker_death_while_full/0
+ },
+ {"Pool behaves right when its full, a worker dies and overflow is disabled",
+ fun worker_death_while_full_no_overflow/0
+ },
+ {"Non-blocking pool behaves when its full and overflow is disabled",
+ fun pool_full_nonblocking_no_overflow/0
+ },
+ {"Non-blocking pool behaves when its full",
+ fun pool_full_nonblocking/0
+ }
+ ]
+ }.
+
+
+%% tell a worker to exit and await its impending doom
+kill_worker(Pid) ->
+ erlang:monitor(process, Pid),
+ gen_server:call(Pid, die),
+ receive
+ {'DOWN', _, process, Pid, _} ->
+ ok
+ end.
+
+checkin_worker(Pid, Worker) ->
+ %% there's no easy way to wait for a checkin to complete, because its
+ %% async and the supervisor may kill the process if it was an overflow
+ %% worker. Yhe only solution seems to be a nasty hardcoded sleep.
+ poolboy:checkin(Pid, Worker),
+ timer:sleep(500).
+
+pool_startup() ->
%% check basic pool operation
{ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}}, {worker_module, poolboy_test_worker},
{size, 10}, {max_overflow, 5}]),
@@ -15,12 +75,12 @@ pool_startup_test() ->
Worker = poolboy:checkout(Pid),
?assertEqual(8, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
- poolboy:checkin(Pid, Worker),
+ checkin_worker(Pid, Worker),
?assertEqual(9, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
ok = gen_fsm:sync_send_all_state_event(Pid, stop).
-pool_overflow_test() ->
+pool_overflow() ->
%% check that the pool overflows properly
{ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}}, {worker_module, poolboy_test_worker},
{size, 5}, {max_overflow, 5}]),
@@ -30,36 +90,32 @@ pool_overflow_test() ->
?assertEqual(7, length(gen_fsm:sync_send_all_state_event(Pid,
get_all_workers))),
[A, B, C, D, E, F, G] = Workers,
- poolboy:checkin(Pid, A),
- poolboy:checkin(Pid, B),
- timer:sleep(500),
+ checkin_worker(Pid, A),
+ checkin_worker(Pid, B),
?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_all_workers))),
- poolboy:checkin(Pid, C),
- poolboy:checkin(Pid, D),
- timer:sleep(500),
+ checkin_worker(Pid, C),
+ checkin_worker(Pid, D),
?assertEqual(2, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_all_workers))),
- poolboy:checkin(Pid, E),
- poolboy:checkin(Pid, F),
- timer:sleep(500),
+ checkin_worker(Pid, E),
+ checkin_worker(Pid, F),
?assertEqual(4, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_all_workers))),
- poolboy:checkin(Pid, G),
- timer:sleep(500),
+ checkin_worker(Pid, G),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_all_workers))),
ok = gen_fsm:sync_send_all_state_event(Pid, stop).
-pool_empty_test() ->
+pool_empty() ->
%% checks the pool handles the empty condition correctly when overflow is
%% enabled.
{ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}}, {worker_module, poolboy_test_worker},
@@ -74,8 +130,7 @@ pool_empty_test() ->
spawn(fun() ->
Worker = poolboy:checkout(Pid),
Self ! got_worker,
- poolboy:checkin(Pid, Worker),
- timer:sleep(500)
+ checkin_worker(Pid, Worker)
end),
%% spawned process should block waiting for worker to be available
receive
@@ -83,42 +138,38 @@ pool_empty_test() ->
after
500 -> ?assert(true)
end,
- poolboy:checkin(Pid, A),
- poolboy:checkin(Pid, B),
+ checkin_worker(Pid, A),
+ checkin_worker(Pid, B),
%% spawned process should have been able to obtain a worker
receive
got_worker -> ?assert(true)
after
500 -> ?assert(false)
end,
- timer:sleep(500),
?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_all_workers))),
- poolboy:checkin(Pid, C),
- poolboy:checkin(Pid, D),
- timer:sleep(500),
+ checkin_worker(Pid, C),
+ checkin_worker(Pid, D),
?assertEqual(2, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_all_workers))),
- poolboy:checkin(Pid, E),
- poolboy:checkin(Pid, F),
- timer:sleep(500),
+ checkin_worker(Pid, E),
+ checkin_worker(Pid, F),
?assertEqual(4, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_all_workers))),
- poolboy:checkin(Pid, G),
- timer:sleep(500),
+ checkin_worker(Pid, G),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_all_workers))),
ok = gen_fsm:sync_send_all_state_event(Pid, stop).
-pool_empty_no_overflow_test() ->
+pool_empty_no_overflow() ->
%% checks the pool handles the empty condition properly when overflow is
%% disabled
{ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}}, {worker_module, poolboy_test_worker},
@@ -133,8 +184,7 @@ pool_empty_no_overflow_test() ->
spawn(fun() ->
Worker = poolboy:checkout(Pid),
Self ! got_worker,
- poolboy:checkin(Pid, Worker),
- timer:sleep(500)
+ checkin_worker(Pid, Worker)
end),
%% spawned process should block waiting for worker to be available
receive
@@ -142,28 +192,25 @@ pool_empty_no_overflow_test() ->
after
500 -> ?assert(true)
end,
- poolboy:checkin(Pid, A),
- poolboy:checkin(Pid, B),
+ checkin_worker(Pid, A),
+ checkin_worker(Pid, B),
%% spawned process should have been able to obtain a worker
receive
got_worker -> ?assert(true)
after
500 -> ?assert(false)
end,
- timer:sleep(500),
?assertEqual(2, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_all_workers))),
- poolboy:checkin(Pid, C),
- poolboy:checkin(Pid, D),
- timer:sleep(500),
+ checkin_worker(Pid, C),
+ checkin_worker(Pid, D),
?assertEqual(4, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_all_workers))),
- poolboy:checkin(Pid, E),
- timer:sleep(500),
+ checkin_worker(Pid, E),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
@@ -171,49 +218,45 @@ pool_empty_no_overflow_test() ->
ok = gen_fsm:sync_send_all_state_event(Pid, stop).
-worker_death_test() ->
+worker_death() ->
%% this test checks that dead workers are only restarted when the pool is
%% not full if the overflow count is 0. Meaning, don't restart overflow
%% workers.
{ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}}, {worker_module, poolboy_test_worker},
{size, 5}, {max_overflow, 2}]),
Worker = poolboy:checkout(Pid),
- gen_server:call(Worker, die),
+ kill_worker(Worker),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
[A, B, C|_Workers] = [poolboy:checkout(Pid) || _ <- lists:seq(0, 6)],
- timer:sleep(500),
?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(7, length(gen_fsm:sync_send_all_state_event(Pid,
get_all_workers))),
- gen_server:call(A, die),
- timer:sleep(500),
+ kill_worker(A),
?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(6, length(gen_fsm:sync_send_all_state_event(Pid,
get_all_workers))),
- gen_server:call(B, die),
- gen_server:call(C, die),
- timer:sleep(500),
+ kill_worker(B),
+ kill_worker(C),
?assertEqual(1, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_all_workers))),
ok = gen_fsm:sync_send_all_state_event(Pid, stop).
-worker_death_while_full_test() ->
+worker_death_while_full() ->
%% this test checks that if a worker dies while the pool is full and there
%% is a queued checkout, a new worker is started and the checkout
%serviced. If there are no queued checkouts, a new worker is not started.
{ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}}, {worker_module, poolboy_test_worker},
{size, 5}, {max_overflow, 2}]),
Worker = poolboy:checkout(Pid),
- gen_server:call(Worker, die),
+ kill_worker(Worker),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
[A, B|_Workers] = [poolboy:checkout(Pid) || _ <- lists:seq(0, 6)],
- timer:sleep(500),
?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(7, length(gen_fsm:sync_send_all_state_event(Pid,
@@ -232,15 +275,14 @@ worker_death_while_full_test() ->
after
500 -> ?assert(true)
end,
- gen_server:call(A, die),
+ kill_worker(A),
%% spawned process should have been able to obtain a worker
receive
got_worker -> ?assert(true)
after
1000 -> ?assert(false)
end,
- gen_server:call(B, die),
- timer:sleep(500),
+ kill_worker(B),
?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(6, length(gen_fsm:sync_send_all_state_event(Pid,
@@ -248,18 +290,17 @@ worker_death_while_full_test() ->
ok = gen_fsm:sync_send_all_state_event(Pid, stop).
-worker_death_while_full_no_overflow_test() ->
+worker_death_while_full_no_overflow() ->
%% this test tests that if a worker dies while the pool is full AND
%% there's no overflow, a new worker is started unconditionally and any
%% queued checkouts are serviced
{ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}}, {worker_module, poolboy_test_worker},
{size, 5}, {max_overflow, 0}]),
Worker = poolboy:checkout(Pid),
- gen_server:call(Worker, die),
+ kill_worker(Worker),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
[A, B, C|_Workers] = [poolboy:checkout(Pid) || _ <- lists:seq(0, 4)],
- timer:sleep(500),
?assertEqual(0, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
@@ -277,21 +318,19 @@ worker_death_while_full_no_overflow_test() ->
after
500 -> ?assert(true)
end,
- gen_server:call(A, die),
+ kill_worker(A),
%% spawned process should have been able to obtain a worker
receive
got_worker -> ?assert(true)
after
1000 -> ?assert(false)
end,
- gen_server:call(B, die),
- timer:sleep(500),
+ kill_worker(B),
?assertEqual(1, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
get_all_workers))),
- gen_server:call(C, die),
- timer:sleep(500),
+ kill_worker(C),
?assertEqual(2, length(gen_fsm:sync_send_all_state_event(Pid,
get_avail_workers))),
?assertEqual(5, length(gen_fsm:sync_send_all_state_event(Pid,
@@ -299,7 +338,7 @@ worker_death_while_full_no_overflow_test() ->
ok = gen_fsm:sync_send_all_state_event(Pid, stop).
-pool_full_nonblocking_no_overflow_test() ->
+pool_full_nonblocking_no_overflow() ->
%% check that when the pool is full, checkouts return 'full' when the
%% option to checkouts nonblocking is enabled.
{ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}},
@@ -313,11 +352,11 @@ pool_full_nonblocking_no_overflow_test() ->
?assertEqual(full, poolboy:checkout(Pid)),
?assertEqual(full, poolboy:checkout(Pid)),
A = hd(Workers),
- poolboy:checkin(Pid, A),
+ checkin_worker(Pid, A),
?assertEqual(A, poolboy:checkout(Pid)),
ok = gen_fsm:sync_send_all_state_event(Pid, stop).
-pool_full_nonblocking_test() ->
+pool_full_nonblocking() ->
%% check that when the pool is full, checkouts return 'full' when the
%% option to checkouts nonblocking is enabled.
{ok, Pid} = poolboy:start_link([{name, {local, poolboy_test}},
@@ -330,7 +369,7 @@ pool_full_nonblocking_test() ->
get_all_workers))),
?assertEqual(full, poolboy:checkout(Pid)),
A = hd(Workers),
- poolboy:checkin(Pid, A),
+ checkin_worker(Pid, A),
NewWorker = poolboy:checkout(Pid),
?assertEqual(false, is_process_alive(A)), %% overflow workers get shut down
?assert(is_pid(NewWorker)),
Please sign in to comment.
Something went wrong with that request. Please try again.