|
13 | 13 | from queue import Empty, Queue |
14 | 14 | from threading import Thread |
15 | 15 |
|
| 16 | +import pg |
16 | 17 | import pytest |
17 | 18 |
|
18 | 19 | from dbutils.pooled_pg import ( |
@@ -122,6 +123,62 @@ def test_close_connection(): |
122 | 123 | del db |
123 | 124 |
|
124 | 125 |
|
| 126 | +def test_close_all(): |
| 127 | + """Check that closing the pool keeps the connections accounted for.""" |
| 128 | + pool = PooledPg(0, 1, 1, False, None, None, False, 'PooledPgTestDB') |
| 129 | + assert pool._cache.qsize() == 0 |
| 130 | + assert pool._connections._value == 1 |
| 131 | + db = pool.connection() |
| 132 | + db_con = db._con |
| 133 | + db.close() |
| 134 | + # the cached connection has already given back its share of the |
| 135 | + # generally allowed connections when it was returned to the pool |
| 136 | + assert pool._cache.qsize() == 1 |
| 137 | + assert pool._connections._value == 1 |
| 138 | + pool.close() |
| 139 | + # closing the pool discards the cached connection, |
| 140 | + # but it must not give back its share a second time |
| 141 | + assert pool._cache.qsize() == 0 |
| 142 | + assert pool._connections._value == 1 |
| 143 | + assert db_con._closed |
| 144 | + # so the pool still hands out only one connection at a time |
| 145 | + db = pool.connection() |
| 146 | + assert db._con is not db_con |
| 147 | + assert pool._connections._value == 0 |
| 148 | + with pytest.raises(TooManyConnectionsError): |
| 149 | + pool.connection() |
| 150 | + # closing the pool again (this also happens when it is deleted) |
| 151 | + # must not change the accounting while a connection is still in use |
| 152 | + pool.close() |
| 153 | + assert pool._connections._value == 0 |
| 154 | + # the connection in use gives back its share when it is returned |
| 155 | + db.close() |
| 156 | + assert pool._cache.qsize() == 1 |
| 157 | + assert pool._connections._value == 1 |
| 158 | + |
| 159 | + |
| 160 | +def test_connection_error_does_not_use_up_a_connection(): |
| 161 | + """Check that a failing connection attempt is properly accounted for.""" |
| 162 | + pool = PooledPg(0, 0, 1, False, None, None, False, dbname='ok') |
| 163 | + assert pool._cache.qsize() == 0 |
| 164 | + assert pool._connections._value == 1 |
| 165 | + # the mock database raises an error when the database is named 'error' |
| 166 | + pool._kwargs['dbname'] = 'error' |
| 167 | + with pytest.raises(pg.InternalError): |
| 168 | + pool.connection() |
| 169 | + pool._kwargs['dbname'] = 'ok' |
| 170 | + # the failed attempt must not have used up the allowed connection |
| 171 | + assert pool._connections._value == 1 |
| 172 | + db = pool.connection() |
| 173 | + assert db.dbname == 'ok' |
| 174 | + assert pool._connections._value == 0 |
| 175 | + # but the connection that could be established still counts |
| 176 | + with pytest.raises(TooManyConnectionsError): |
| 177 | + pool.connection() |
| 178 | + db.close() |
| 179 | + assert pool._connections._value == 1 |
| 180 | + |
| 181 | + |
125 | 182 | @pytest.mark.parametrize(("mincached", "maxcached", "cached", "rounds"), [ |
126 | 183 | # every round takes the given number of connections out of the pool |
127 | 184 | # and expects the given number of cached connections after closing them |
|
0 commit comments