Skip to content

Commit 4280405

Browse files
committed
test: add basic connection pool test cases
1 parent fe735b9 commit 4280405

File tree

1 file changed

+302
-8
lines changed

1 file changed

+302
-8
lines changed

test/mysql.test.lua

Lines changed: 302 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,67 @@ function test_old_api(t, conn)
6868
t:ok(conn:close(), "close")
6969
end
7070

71-
function test_gc(t, p)
72-
t:plan(1)
73-
p:get()
74-
local c = p:get()
75-
c = nil
76-
collectgarbage('collect')
77-
t:is(p.queue:count(), p.size, 'gc connections')
71+
function test_gc(test, pool)
72+
test:plan(3)
73+
74+
-- Case: verify that a pool tracks connections that are not
75+
-- put back, but were collected by GC.
76+
test:test('loss a healthy connection', function(test)
77+
test:plan(1)
78+
79+
assert(pool.size >= 2, 'test case precondition fails')
80+
81+
-- Loss one connection.
82+
pool:get()
83+
84+
-- Loss another one.
85+
local conn = pool:get()
86+
conn = nil
87+
88+
-- Collect lost connections.
89+
collectgarbage('collect')
90+
91+
-- Verify that a pool is aware of collected connections.
92+
test:is(pool.queue:count(), pool.size, 'all connections are put back')
93+
end)
94+
95+
-- Case: the same, but for broken connection.
96+
test:test('loss a broken connection', function(test)
97+
test:plan(2)
98+
99+
assert(pool.size >= 1, 'test case precondition fails')
100+
101+
-- Get a connection, make a bad query and loss the
102+
-- connection.
103+
local conn = pool:get()
104+
local ok = pcall(conn.execute, conn, 'bad query')
105+
test:ok(not ok, 'a query actually fails')
106+
conn = nil
107+
108+
-- Collect the lost connection.
109+
collectgarbage('collect')
110+
111+
-- Verify that a pool is aware of collected connections.
112+
test:is(pool.queue:count(), pool.size, 'all connections are put back')
113+
end)
114+
115+
-- Case: the same, but for closed connection.
116+
test:test('loss a closed connection', function(test)
117+
test:plan(1)
118+
119+
assert(pool.size >= 1, 'test case precondition fails')
120+
121+
-- Get a connection, close it and loss the connection.
122+
local conn = pool:get()
123+
conn:close()
124+
conn = nil
125+
126+
-- Collect the lost connection.
127+
collectgarbage('collect')
128+
129+
-- Verify that a pool is aware of collected connections.
130+
test:is(pool.queue:count(), pool.size, 'all connections are put back')
131+
end)
78132
end
79133

80134
function test_conn_fiber1(c, q)
@@ -116,8 +170,247 @@ function test_mysql_int64(t, p)
116170
p:put(conn)
117171
end
118172

173+
local function test_connection_pool(test, pool)
174+
test:plan(5)
175+
176+
-- {{{ Case group: all connections are consumed initially.
177+
178+
assert(pool.queue:is_full(), 'case group precondition fails')
179+
180+
-- Grab all connections from a pool.
181+
local connections = {}
182+
for i = 1, pool.size do
183+
table.insert(connections, pool:get())
184+
end
185+
186+
-- Case: get and put connections from / to a pool.
187+
test:test('pool:get({}) and pool:put()', function(test)
188+
test:plan(2)
189+
assert(pool.queue:is_empty(), 'test case precondition fails')
190+
191+
-- Verify that we're unable to get one more connection.
192+
local latch = fiber.channel(1)
193+
local conn
194+
fiber.create(function()
195+
conn = pool:get()
196+
latch:put(true)
197+
end)
198+
local res = latch:get(1)
199+
test:is(res, nil, 'unable to get more connections then a pool size')
200+
201+
-- Give a connection back and verify that now the fiber
202+
-- above gets this connection.
203+
pool:put(table.remove(connections))
204+
latch:get()
205+
test:ok(conn ~= nil, 'able to get a connection when it was given back')
206+
207+
-- Restore everything as it was.
208+
table.insert(connections, conn)
209+
conn = nil
210+
211+
assert(pool.queue:is_empty(), 'test case postcondition fails')
212+
end)
213+
214+
-- Give all connections back to the poll.
215+
for _, conn in ipairs(connections) do
216+
pool:put(conn)
217+
end
218+
219+
assert(pool.queue:is_full(), 'case group postcondition fails')
220+
221+
-- }}}
222+
223+
-- {{{ Case group: all connections are ready initially.
224+
225+
assert(pool.queue:is_full(), 'case group precondition fails')
226+
227+
-- XXX: Maybe the cases below will look better if rewrite them
228+
-- in a declarative way, like so:
229+
--
230+
-- local cases = {
231+
-- {
232+
-- 'case name',
233+
-- after_get = function(test, context)
234+
-- -- * Do nothing.
235+
-- -- * Or make a bad query (and assert that
236+
-- -- :execute() fails).
237+
-- -- * Or close the connection.
238+
-- end,
239+
-- after_put = function(test, context)
240+
-- -- * Do nothing.
241+
-- -- * Or loss `context.conn` and trigger
242+
-- -- GC.
243+
-- end,
244+
-- }
245+
-- }
246+
--
247+
-- Or so:
248+
--
249+
-- local cases = {
250+
-- {
251+
-- 'case name',
252+
-- after_get = function(test, context)
253+
-- -- * Do nothing.
254+
-- -- * Or make a bad query (and assert that
255+
-- -- :execute() fails).
256+
-- -- * Or close the connection.
257+
-- end,
258+
-- loss_after_put = <boolean>,
259+
-- }
260+
-- }
261+
--
262+
-- `loss_after_put` will do the following after put (see
263+
-- comments in cases below):
264+
--
265+
-- context.conn = nil
266+
-- collectgarbage('collect')
267+
-- assert(pool.queue:is_full(), <...>)
268+
-- local item = pool.queue:get()
269+
-- pool.queue:put(item)
270+
-- test:ok(true, <...>)
271+
272+
-- Case: get a connection and put it back.
273+
test:test('get and put a connection', function(test)
274+
test:plan(1)
275+
276+
assert(pool.size >= 1, 'test case precondition fails')
277+
278+
-- Get a connection.
279+
local conn = pool:get()
280+
281+
-- Put the connection back and verify that the pool is full.
282+
pool:put(conn)
283+
test:ok(pool.queue:is_full(), 'a broken connection was given back')
284+
end)
285+
286+
-- Case: the same, but loss and collect a connection after
287+
-- put.
288+
test:test('get, put and loss a connection', function(test)
289+
test:plan(2)
290+
291+
assert(pool.size >= 1, 'test case precondition fails')
292+
293+
-- Get a connection.
294+
local conn = pool:get()
295+
296+
-- Put the connection back, loss it and trigger GC.
297+
pool:put(conn)
298+
conn = nil
299+
collectgarbage('collect')
300+
301+
-- Verify that the pool is full.
302+
test:ok(pool.queue:is_full(), 'a broken connection was given back')
303+
304+
-- Verify the pool will not be populated by a connection's
305+
-- GC callback. Otherwise :put() will hang.
306+
local item = pool.queue:get()
307+
pool.queue:put(item)
308+
test:ok(true, 'GC callback does not put back a connection that was ' ..
309+
'put manually')
310+
end)
311+
312+
-- Case: get a connection, broke it and put back.
313+
test:test('get, broke and put a connection', function(test)
314+
test:plan(2)
315+
316+
assert(pool.size >= 1, 'test case precondition fails')
317+
318+
-- Get a connection and make a bad query.
319+
local conn = pool:get()
320+
local ok = pcall(conn.execute, conn, 'bad query')
321+
test:ok(not ok, 'a query actually fails')
322+
323+
-- Put the connection back and verify that the pool is full.
324+
pool:put(conn)
325+
test:ok(pool.queue:is_full(), 'a broken connection was given back')
326+
end)
327+
328+
-- Case: the same, but loss and collect a connection after
329+
-- put.
330+
test:test('get, broke, put and loss a connection', function(test)
331+
test:plan(3)
332+
333+
assert(pool.size >= 1, 'test case precondition fails')
334+
335+
-- Get a connection and make a bad query.
336+
local conn = pool:get()
337+
local ok = pcall(conn.execute, conn, 'bad query')
338+
test:ok(not ok, 'a query actually fails')
339+
340+
-- Put the connection back, loss it and trigger GC.
341+
pool:put(conn)
342+
conn = nil
343+
collectgarbage('collect')
344+
345+
-- Verify that the pool is full
346+
test:ok(pool.queue:is_full(), 'a broken connection was given back')
347+
348+
-- Verify the pool will not be populated by a connection's
349+
-- GC callback. Otherwise :put() will hang.
350+
local item = pool.queue:get()
351+
pool.queue:put(item)
352+
test:ok(true, 'GC callback does not put back a connection that was ' ..
353+
'put manually')
354+
end)
355+
356+
--[[
357+
358+
-- It is unclear for now whether putting of closed connection
359+
-- should be allowed. The second case, where GC collects lost
360+
-- connection after :put(), does not work at the moment. See
361+
-- gh-33.
362+
363+
-- Case: get a connection, close it and put back.
364+
test:test('get, close and put a connection', function(test)
365+
test:plan(1)
366+
367+
assert(pool.size >= 1, 'test case precondition fails')
368+
369+
-- Get a connection and close it.
370+
local conn = pool:get()
371+
conn:close()
372+
373+
-- Put a connection back and verify that the pool is full.
374+
pool:put(conn)
375+
test:ok(pool.queue:is_full(), 'a broken connection was given back')
376+
end)
377+
378+
-- Case: the same, but loss and collect a connection after
379+
-- put.
380+
test:test('get, close, put and loss a connection', function(test)
381+
test:plan(2)
382+
383+
assert(pool.size >= 1, 'test case precondition fails')
384+
385+
-- Get a connection and close it.
386+
local conn = pool:get()
387+
conn:close()
388+
389+
-- Put the connection back, loss it and trigger GC.
390+
pool:put(conn)
391+
conn = nil
392+
collectgarbage('collect')
393+
394+
-- Verify that the pool is full
395+
test:ok(pool.queue:is_full(), 'a broken connection was given back')
396+
397+
-- Verify the pool will not be populated by a connection's
398+
-- GC callback. Otherwise :put() will hang.
399+
local item = pool.queue:get()
400+
pool.queue:put(item)
401+
test:ok(true, 'GC callback does not put back a connection that was ' ..
402+
'put manually')
403+
end)
404+
405+
--]]
406+
407+
assert(pool.queue:is_full(), 'case group postcondition fails')
408+
409+
-- }}}
410+
end
411+
119412
local test = tap.test('mysql connector')
120-
test:plan(5)
413+
test:plan(6)
121414

122415
test:test('connection old api', test_old_api, conn)
123416
local pool_conn = p:get()
@@ -126,6 +419,7 @@ p:put(pool_conn)
126419
test:test('garbage collection', test_gc, p)
127420
test:test('concurrent connections', test_conn_concurrent, p)
128421
test:test('int64', test_mysql_int64, p)
422+
test:test('connection pool', test_connection_pool, p)
129423
p:close()
130424

131425
os.exit(test:check() and 0 or 1)

0 commit comments

Comments
 (0)