Subversion Repositories SE.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6 7u83 1
-module(poolboy_tests).
2
 
3
-include_lib("eunit/include/eunit.hrl").
4
 
5
pool_test_() ->
6
    {foreach,
7
        fun() ->
8
            error_logger:tty(false)
9
        end,
10
        fun(_) ->
11
            case whereis(poolboy_test) of
12
                undefined -> ok;
13
                Pid -> pool_call(Pid, stop)
14
            end,
15
            error_logger:tty(true)
16
        end,
17
        [
18
            {<<"Basic pool operations">>,
19
                fun pool_startup/0
20
            },
21
            {<<"Pool overflow should work">>,
22
                fun pool_overflow/0
23
            },
24
            {<<"Pool behaves when empty">>,
25
                fun pool_empty/0
26
            },
27
            {<<"Pool behaves when empty and oveflow is disabled">>,
28
                fun pool_empty_no_overflow/0
29
            },
30
            {<<"Pool behaves on worker death">>,
31
                fun worker_death/0
32
            },
33
            {<<"Pool behaves when full and a worker dies">>,
34
                fun worker_death_while_full/0
35
            },
36
            {<<"Pool behaves when full, a worker dies and overflow disabled">>,
37
                fun worker_death_while_full_no_overflow/0
38
            },
39
            {<<"Non-blocking pool behaves when full and overflow disabled">>,
40
                fun pool_full_nonblocking_no_overflow/0
41
            },
42
            {<<"Non-blocking pool behaves when full">>,
43
                fun pool_full_nonblocking/0
44
            },
45
            {<<"Pool behaves on owner death">>,
46
                fun owner_death/0
47
            },
48
            {<<"Worker checked-in after an exception in a transaction">>,
49
                fun checkin_after_exception_in_transaction/0
50
            },
51
            {<<"Pool returns status">>,
52
                fun pool_returns_status/0
53
            },
54
            {<<"Pool demonitors previously waiting processes">>,
55
                fun demonitors_previously_waiting_processes/0
56
            },
57
            {<<"Pool demonitors when a checkout is cancelled">>,
58
                fun demonitors_when_checkout_cancelled/0
59
            },
60
            {<<"Check that LIFO is the default strategy">>,
61
                fun default_strategy_lifo/0
62
            },
63
            {<<"Check LIFO strategy">>,
64
                fun lifo_strategy/0
65
            },
66
            {<<"Check FIFO strategy">>,
67
                fun fifo_strategy/0
68
            },
69
            {<<"Pool reuses waiting monitor when a worker exits">>,
70
                fun reuses_waiting_monitor_on_worker_exit/0
71
            },
72
            {<<"Recover from timeout without exit handling">>,
73
                fun transaction_timeout_without_exit/0},
74
            {<<"Recover from transaction timeout">>,
75
                fun transaction_timeout/0}
76
        ]
77
    }.
78
 
79
%% Tell a worker to exit and await its impending doom.
80
kill_worker(Pid) ->
81
    erlang:monitor(process, Pid),
82
    pool_call(Pid, die),
83
    receive
84
        {'DOWN', _, process, Pid, _} ->
85
            ok
86
    end.
87
 
88
checkin_worker(Pid, Worker) ->
89
    %% There's no easy way to wait for a checkin to complete, because it's
90
    %% async and the supervisor may kill the process if it was an overflow
91
    %% worker. The only solution seems to be a nasty hardcoded sleep.
92
    poolboy:checkin(Pid, Worker),
93
    timer:sleep(500).
94
 
95
 
96
transaction_timeout_without_exit() ->
97
    {ok, Pid} = new_pool(1, 0),
98
    ?assertEqual({ready,1,0,0}, pool_call(Pid, status)),
99
    WorkerList = pool_call(Pid, get_all_workers),
100
    ?assertMatch([_], WorkerList),
101
    spawn(poolboy, transaction, [Pid,
102
        fun(Worker) ->
103
            ok = pool_call(Worker, work)
104
        end,
105
        0]),
106
    timer:sleep(100),
107
    ?assertEqual(WorkerList, pool_call(Pid, get_all_workers)),
108
    ?assertEqual({ready,1,0,0}, pool_call(Pid, status)).
109
 
110
 
111
transaction_timeout() ->
112
    {ok, Pid} = new_pool(1, 0),
113
    ?assertEqual({ready,1,0,0}, pool_call(Pid, status)),
114
    WorkerList = pool_call(Pid, get_all_workers),
115
    ?assertMatch([_], WorkerList),
116
    ?assertExit(
117
        {timeout, _},
118
        poolboy:transaction(Pid,
119
            fun(Worker) ->
120
                ok = pool_call(Worker, work)
121
            end,
122
            0)),
123
    ?assertEqual(WorkerList, pool_call(Pid, get_all_workers)),
124
    ?assertEqual({ready,1,0,0}, pool_call(Pid, status)).
125
 
126
 
127
pool_startup() ->
128
    %% Check basic pool operation.
129
    {ok, Pid} = new_pool(10, 5),
130
    ?assertEqual(10, length(pool_call(Pid, get_avail_workers))),
131
    poolboy:checkout(Pid),
132
    ?assertEqual(9, length(pool_call(Pid, get_avail_workers))),
133
    Worker = poolboy:checkout(Pid),
134
    ?assertEqual(8, length(pool_call(Pid, get_avail_workers))),
135
    checkin_worker(Pid, Worker),
136
    ?assertEqual(9, length(pool_call(Pid, get_avail_workers))),
137
    ?assertEqual(1, length(pool_call(Pid, get_all_monitors))),
138
    ok = pool_call(Pid, stop).
139
 
140
pool_overflow() ->
141
    %% Check that the pool overflows properly.
142
    {ok, Pid} = new_pool(5, 5),
143
    Workers = [poolboy:checkout(Pid) || _ <- lists:seq(0, 6)],
144
    ?assertEqual(0, length(pool_call(Pid, get_avail_workers))),
145
    ?assertEqual(7, length(pool_call(Pid, get_all_workers))),
146
    [A, B, C, D, E, F, G] = Workers,
147
    checkin_worker(Pid, A),
148
    checkin_worker(Pid, B),
149
    ?assertEqual(0, length(pool_call(Pid, get_avail_workers))),
150
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
151
    checkin_worker(Pid, C),
152
    checkin_worker(Pid, D),
153
    ?assertEqual(2, length(pool_call(Pid, get_avail_workers))),
154
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
155
    checkin_worker(Pid, E),
156
    checkin_worker(Pid, F),
157
    ?assertEqual(4, length(pool_call(Pid, get_avail_workers))),
158
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
159
    checkin_worker(Pid, G),
160
    ?assertEqual(5, length(pool_call(Pid, get_avail_workers))),
161
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
162
    ?assertEqual(0, length(pool_call(Pid, get_all_monitors))),
163
    ok = pool_call(Pid, stop).
164
 
165
pool_empty() ->
166
    %% Checks that the the pool handles the empty condition correctly when
167
    %% overflow is enabled.
168
    {ok, Pid} = new_pool(5, 2),
169
    Workers = [poolboy:checkout(Pid) || _ <- lists:seq(0, 6)],
170
    ?assertEqual(0, length(pool_call(Pid, get_avail_workers))),
171
    ?assertEqual(7, length(pool_call(Pid, get_all_workers))),
172
    [A, B, C, D, E, F, G] = Workers,
173
    Self = self(),
174
    spawn(fun() ->
175
        Worker = poolboy:checkout(Pid),
176
        Self ! got_worker,
177
        checkin_worker(Pid, Worker)
178
    end),
179
 
180
    %% Spawned process should block waiting for worker to be available.
181
    receive
182
        got_worker -> ?assert(false)
183
    after
184
        500 -> ?assert(true)
185
    end,
186
    checkin_worker(Pid, A),
187
    checkin_worker(Pid, B),
188
 
189
    %% Spawned process should have been able to obtain a worker.
190
    receive
191
        got_worker -> ?assert(true)
192
    after
193
        500 -> ?assert(false)
194
    end,
195
    ?assertEqual(0, length(pool_call(Pid, get_avail_workers))),
196
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
197
    checkin_worker(Pid, C),
198
    checkin_worker(Pid, D),
199
    ?assertEqual(2, length(pool_call(Pid, get_avail_workers))),
200
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
201
    checkin_worker(Pid, E),
202
    checkin_worker(Pid, F),
203
    ?assertEqual(4, length(pool_call(Pid, get_avail_workers))),
204
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
205
    checkin_worker(Pid, G),
206
    ?assertEqual(5, length(pool_call(Pid, get_avail_workers))),
207
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
208
    ?assertEqual(0, length(pool_call(Pid, get_all_monitors))),
209
    ok = pool_call(Pid, stop).
210
 
211
pool_empty_no_overflow() ->
212
    %% Checks the pool handles the empty condition properly when overflow is
213
    %% disabled.
214
    {ok, Pid} = new_pool(5, 0),
215
    Workers = [poolboy:checkout(Pid) || _ <- lists:seq(0, 4)],
216
    ?assertEqual(0, length(pool_call(Pid, get_avail_workers))),
217
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
218
    [A, B, C, D, E] = Workers,
219
    Self = self(),
220
    spawn(fun() ->
221
        Worker = poolboy:checkout(Pid),
222
        Self ! got_worker,
223
        checkin_worker(Pid, Worker)
224
    end),
225
 
226
    %% Spawned process should block waiting for worker to be available.
227
    receive
228
        got_worker -> ?assert(false)
229
    after
230
        500 -> ?assert(true)
231
    end,
232
    checkin_worker(Pid, A),
233
    checkin_worker(Pid, B),
234
 
235
    %% Spawned process should have been able to obtain a worker.
236
    receive
237
        got_worker -> ?assert(true)
238
    after
239
        500 -> ?assert(false)
240
    end,
241
    ?assertEqual(2, length(pool_call(Pid, get_avail_workers))),
242
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
243
    checkin_worker(Pid, C),
244
    checkin_worker(Pid, D),
245
    ?assertEqual(4, length(pool_call(Pid, get_avail_workers))),
246
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
247
    checkin_worker(Pid, E),
248
    ?assertEqual(5, length(pool_call(Pid, get_avail_workers))),
249
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
250
    ?assertEqual(0, length(pool_call(Pid, get_all_monitors))),
251
    ok = pool_call(Pid, stop).
252
 
253
worker_death() ->
254
    %% Check that dead workers are only restarted when the pool is not full
255
    %% and the overflow count is 0. Meaning, don't restart overflow workers.
256
    {ok, Pid} = new_pool(5, 2),
257
    Worker = poolboy:checkout(Pid),
258
    kill_worker(Worker),
259
    ?assertEqual(5, length(pool_call(Pid, get_avail_workers))),
260
    [A, B, C|_Workers] = [poolboy:checkout(Pid) || _ <- lists:seq(0, 6)],
261
    ?assertEqual(0, length(pool_call(Pid, get_avail_workers))),
262
    ?assertEqual(7, length(pool_call(Pid, get_all_workers))),
263
    kill_worker(A),
264
    ?assertEqual(0, length(pool_call(Pid, get_avail_workers))),
265
    ?assertEqual(6, length(pool_call(Pid, get_all_workers))),
266
    kill_worker(B),
267
    kill_worker(C),
268
    ?assertEqual(1, length(pool_call(Pid, get_avail_workers))),
269
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
270
    ?assertEqual(4, length(pool_call(Pid, get_all_monitors))),
271
    ok = pool_call(Pid, stop).
272
 
273
worker_death_while_full() ->
274
    %% Check that if a worker dies while the pool is full and there is a
275
    %% queued checkout, a new worker is started and the checkout serviced.
276
    %% If there are no queued checkouts, a new worker is not started.
277
    {ok, Pid} = new_pool(5, 2),
278
    Worker = poolboy:checkout(Pid),
279
    kill_worker(Worker),
280
    ?assertEqual(5, length(pool_call(Pid, get_avail_workers))),
281
    [A, B|_Workers] = [poolboy:checkout(Pid) || _ <- lists:seq(0, 6)],
282
    ?assertEqual(0, length(pool_call(Pid, get_avail_workers))),
283
    ?assertEqual(7, length(pool_call(Pid, get_all_workers))),
284
    Self = self(),
285
    spawn(fun() ->
286
        poolboy:checkout(Pid),
287
        Self ! got_worker,
288
        %% XXX: Don't release the worker. We want to also test what happens
289
        %% when the worker pool is full and a worker dies with no queued
290
        %% checkouts.
291
        timer:sleep(5000)
292
    end),
293
 
294
    %% Spawned process should block waiting for worker to be available.
295
    receive
296
        got_worker -> ?assert(false)
297
    after
298
        500 -> ?assert(true)
299
    end,
300
    kill_worker(A),
301
 
302
    %% Spawned process should have been able to obtain a worker.
303
    receive
304
        got_worker -> ?assert(true)
305
    after
306
        1000 -> ?assert(false)
307
    end,
308
    kill_worker(B),
309
    ?assertEqual(0, length(pool_call(Pid, get_avail_workers))),
310
    ?assertEqual(6, length(pool_call(Pid, get_all_workers))),
311
    ?assertEqual(6, length(pool_call(Pid, get_all_monitors))),
312
    ok = pool_call(Pid, stop).
313
 
314
worker_death_while_full_no_overflow() ->
315
    %% Check that if a worker dies while the pool is full and there's no
316
    %% overflow, a new worker is started unconditionally and any queued
317
    %% checkouts are serviced.
318
    {ok, Pid} = new_pool(5, 0),
319
    Worker = poolboy:checkout(Pid),
320
    kill_worker(Worker),
321
    ?assertEqual(5, length(pool_call(Pid, get_avail_workers))),
322
    [A, B, C|_Workers] = [poolboy:checkout(Pid) || _ <- lists:seq(0, 4)],
323
    ?assertEqual(0, length(pool_call(Pid, get_avail_workers))),
324
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
325
    Self = self(),
326
    spawn(fun() ->
327
        poolboy:checkout(Pid),
328
        Self ! got_worker,
329
        %% XXX: Do not release, need to also test when worker dies and no
330
        %% checkouts queued.
331
        timer:sleep(5000)
332
    end),
333
 
334
    %% Spawned process should block waiting for worker to be available.
335
    receive
336
        got_worker -> ?assert(false)
337
    after
338
        500 -> ?assert(true)
339
    end,
340
    kill_worker(A),
341
 
342
    %% Spawned process should have been able to obtain a worker.
343
    receive
344
        got_worker -> ?assert(true)
345
    after
346
        1000 -> ?assert(false)
347
    end,
348
    kill_worker(B),
349
    ?assertEqual(1, length(pool_call(Pid, get_avail_workers))),
350
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
351
    kill_worker(C),
352
    ?assertEqual(2, length(pool_call(Pid, get_avail_workers))),
353
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
354
    ?assertEqual(3, length(pool_call(Pid, get_all_monitors))),
355
    ok = pool_call(Pid, stop).
356
 
357
pool_full_nonblocking_no_overflow() ->
358
    %% Check that when the pool is full, checkouts return 'full' when the
359
    %% option to use non-blocking checkouts is used.
360
    {ok, Pid} = new_pool(5, 0),
361
    Workers = [poolboy:checkout(Pid) || _ <- lists:seq(0, 4)],
362
    ?assertEqual(0, length(pool_call(Pid, get_avail_workers))),
363
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
364
    ?assertEqual(full, poolboy:checkout(Pid, false)),
365
    ?assertEqual(full, poolboy:checkout(Pid, false)),
366
    A = hd(Workers),
367
    checkin_worker(Pid, A),
368
    ?assertEqual(A, poolboy:checkout(Pid)),
369
    ?assertEqual(5, length(pool_call(Pid, get_all_monitors))),
370
    ok = pool_call(Pid, stop).
371
 
372
pool_full_nonblocking() ->
373
    %% Check that when the pool is full, checkouts return 'full' when the
374
    %% option to use non-blocking checkouts is used.
375
    {ok, Pid} = new_pool(5, 5),
376
    Workers = [poolboy:checkout(Pid) || _ <- lists:seq(0, 9)],
377
    ?assertEqual(0, length(pool_call(Pid, get_avail_workers))),
378
    ?assertEqual(10, length(pool_call(Pid, get_all_workers))),
379
    ?assertEqual(full, poolboy:checkout(Pid, false)),
380
    A = hd(Workers),
381
    checkin_worker(Pid, A),
382
    NewWorker = poolboy:checkout(Pid, false),
383
    ?assertEqual(false, is_process_alive(A)), %% Overflow workers get shutdown
384
    ?assert(is_pid(NewWorker)),
385
    ?assertEqual(full, poolboy:checkout(Pid, false)),
386
    ?assertEqual(10, length(pool_call(Pid, get_all_monitors))),
387
    ok = pool_call(Pid, stop).
388
 
389
owner_death() ->
390
    %% Check that a dead owner (a process that dies with a worker checked out)
391
    %% causes the pool to dismiss the worker and prune the state space.
392
    {ok, Pid} = new_pool(5, 5),
393
    spawn(fun() ->
394
        poolboy:checkout(Pid),
395
        receive after 500 -> exit(normal) end
396
    end),
397
    timer:sleep(1000),
398
    ?assertEqual(5, length(pool_call(Pid, get_avail_workers))),
399
    ?assertEqual(5, length(pool_call(Pid, get_all_workers))),
400
    ?assertEqual(0, length(pool_call(Pid, get_all_monitors))),
401
    ok = pool_call(Pid, stop).
402
 
403
checkin_after_exception_in_transaction() ->
404
    {ok, Pool} = new_pool(2, 0),
405
    ?assertEqual(2, length(pool_call(Pool, get_avail_workers))),
406
    Tx = fun(Worker) ->
407
        ?assert(is_pid(Worker)),
408
        ?assertEqual(1, length(pool_call(Pool, get_avail_workers))),
409
        throw(it_on_the_ground),
410
        ?assert(false)
411
    end,
412
    try
413
        poolboy:transaction(Pool, Tx)
414
    catch
415
        throw:it_on_the_ground -> ok
416
    end,
417
    ?assertEqual(2, length(pool_call(Pool, get_avail_workers))),
418
    ok = pool_call(Pool, stop).
419
 
420
pool_returns_status() ->
421
    {ok, Pool} = new_pool(2, 0),
422
    ?assertEqual({ready, 2, 0, 0}, poolboy:status(Pool)),
423
    poolboy:checkout(Pool),
424
    ?assertEqual({ready, 1, 0, 1}, poolboy:status(Pool)),
425
    poolboy:checkout(Pool),
426
    ?assertEqual({full, 0, 0, 2}, poolboy:status(Pool)),
427
    ok = pool_call(Pool, stop),
428
 
429
    {ok, Pool2} = new_pool(1, 1),
430
    ?assertEqual({ready, 1, 0, 0}, poolboy:status(Pool2)),
431
    poolboy:checkout(Pool2),
432
    ?assertEqual({overflow, 0, 0, 1}, poolboy:status(Pool2)),
433
    poolboy:checkout(Pool2),
434
    ?assertEqual({full, 0, 1, 2}, poolboy:status(Pool2)),
435
    ok = pool_call(Pool2, stop),
436
 
437
    {ok, Pool3} = new_pool(0, 2),
438
    ?assertEqual({overflow, 0, 0, 0}, poolboy:status(Pool3)),
439
    poolboy:checkout(Pool3),
440
    ?assertEqual({overflow, 0, 1, 1}, poolboy:status(Pool3)),
441
    poolboy:checkout(Pool3),
442
    ?assertEqual({full, 0, 2, 2}, poolboy:status(Pool3)),
443
    ok = pool_call(Pool3, stop),
444
 
445
    {ok, Pool4} = new_pool(0, 0),
446
    ?assertEqual({full, 0, 0, 0}, poolboy:status(Pool4)),
447
    ok = pool_call(Pool4, stop).
448
 
449
demonitors_previously_waiting_processes() ->
450
    {ok, Pool} = new_pool(1,0),
451
    Self = self(),
452
    Pid = spawn(fun() ->
453
        W = poolboy:checkout(Pool),
454
        Self ! ok,
455
        timer:sleep(500),
456
        poolboy:checkin(Pool, W),
457
        receive ok -> ok end
458
    end),
459
    receive ok -> ok end,
460
    Worker = poolboy:checkout(Pool),
461
    ?assertEqual(1, length(get_monitors(Pool))),
462
    poolboy:checkin(Pool, Worker),
463
    timer:sleep(500),
464
    ?assertEqual(0, length(get_monitors(Pool))),
465
    Pid ! ok,
466
    ok = pool_call(Pool, stop).
467
 
468
demonitors_when_checkout_cancelled() ->
469
    {ok, Pool} = new_pool(1,0),
470
    Self = self(),
471
    Pid = spawn(fun() ->
472
        poolboy:checkout(Pool),
473
        _ = (catch poolboy:checkout(Pool, true, 1000)),
474
        Self ! ok,
475
        receive ok -> ok end
476
    end),
477
    timer:sleep(500),
478
    ?assertEqual(2, length(get_monitors(Pool))),
479
    receive ok -> ok end,
480
    ?assertEqual(1, length(get_monitors(Pool))),
481
    Pid ! ok,
482
    ok = pool_call(Pool, stop).
483
 
484
default_strategy_lifo() ->
485
    %% Default strategy is LIFO
486
    {ok, Pid} = new_pool(2, 0),
487
    Worker1 = poolboy:checkout(Pid),
488
    ok = poolboy:checkin(Pid, Worker1),
489
    Worker1 = poolboy:checkout(Pid),
490
    poolboy:stop(Pid).
491
 
492
lifo_strategy() ->
493
    {ok, Pid} = new_pool(2, 0, lifo),
494
    Worker1 = poolboy:checkout(Pid),
495
    ok = poolboy:checkin(Pid, Worker1),
496
    Worker1 = poolboy:checkout(Pid),
497
    poolboy:stop(Pid).
498
 
499
fifo_strategy() ->
500
    {ok, Pid} = new_pool(2, 0, fifo),
501
    Worker1 = poolboy:checkout(Pid),
502
    ok = poolboy:checkin(Pid, Worker1),
503
    Worker2 = poolboy:checkout(Pid),
504
    ?assert(Worker1 =/= Worker2),
505
    Worker1 = poolboy:checkout(Pid),
506
    poolboy:stop(Pid).
507
 
508
reuses_waiting_monitor_on_worker_exit() ->
509
    {ok, Pool} = new_pool(1,0),
510
 
511
    Self = self(),
512
    Pid = spawn(fun() ->
513
        Worker = poolboy:checkout(Pool),
514
        Self ! {worker, Worker},
515
        poolboy:checkout(Pool),
516
        receive ok -> ok end
517
    end),
518
 
519
    Worker = receive {worker, Worker1} -> Worker1 end,
520
    Ref = monitor(process, Worker),
521
    exit(Worker, kill),
522
    receive
523
        {'DOWN', Ref, _, _, _} ->
524
            ok
525
    end,
526
 
527
    ?assertEqual(1, length(get_monitors(Pool))),
528
 
529
    Pid ! ok,
530
    ok = pool_call(Pool, stop).
531
 
532
get_monitors(Pid) ->
533
    %% Synchronise with the Pid to ensure it has handled all expected work.
534
    _ = sys:get_status(Pid),
535
    [{monitors, Monitors}] = erlang:process_info(Pid, [monitors]),
536
    Monitors.
537
 
538
new_pool(Size, MaxOverflow) ->
539
    poolboy:start_link([{name, {local, poolboy_test}},
540
                        {worker_module, poolboy_test_worker},
541
                        {size, Size}, {max_overflow, MaxOverflow}]).
542
 
543
new_pool(Size, MaxOverflow, Strategy) ->
544
    poolboy:start_link([{name, {local, poolboy_test}},
545
                        {worker_module, poolboy_test_worker},
546
                        {size, Size}, {max_overflow, MaxOverflow},
547
                        {strategy, Strategy}]).
548
 
549
pool_call(ServerRef, Request) ->
550
    gen_server:call(ServerRef, Request).