Merge lp:~allenap/maas/kill-other-database-connections-in-tests into lp:~maas-committers/maas/trunk

Proposed by Gavin Panella
Status: Merged
Approved by: Gavin Panella
Approved revision: no longer in the source branch.
Merged at revision: 5856
Proposed branch: lp:~allenap/maas/kill-other-database-connections-in-tests
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 41 lines (+24/-5)
1 file modified
src/maasserver/testing/resources.py (+24/-5)
To merge this branch: bzr merge lp:~allenap/maas/kill-other-database-connections-in-tests
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Review via email: mp+320863@code.launchpad.net

Commit message

Kill other connections when about to drop a database in the test database resource manager.

To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) wrote :

This affects only tests so I'm going to self-review it.

FWIW, this improves feedback when a test leaks database connections, and appears to make things more predictable when writing new tests (especially when you accidentally leak database connections).

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/testing/resources.py'
2--- src/maasserver/testing/resources.py 2017-01-24 16:13:50 +0000
3+++ src/maasserver/testing/resources.py 2017-03-23 20:03:22 +0000
4@@ -245,13 +245,32 @@
5 for database in databases:
6 dbname = database["NAME"]
7 template = re.search(r"^(.+)_\d+_\d+$", dbname).group(1)
8- stmt = "DROP DATABASE %s" % dbname
9- cursor.execute(stmt)
10- debug(
11- "Dropped {dbname}; statement: {stmt}",
12- dbname=dbname, stmt=stmt)
13+ self._stopOtherActivity(cursor, dbname)
14+ self._dropDatabase(cursor, dbname)
15 database["NAME"] = template
16
17+ @staticmethod
18+ def _stopOtherActivity(cursor, dbname):
19+ """Terminate other connections to the given database."""
20+ cursor.execute(
21+ "SELECT pg_terminate_backend(pid) FROM pg_stat_activity "
22+ "WHERE pid != pg_backend_pid() AND datname = %s", [dbname])
23+ count = sum(
24+ (1 if success else 0)
25+ for [success] in cursor.fetchall())
26+ debug(
27+ "Killed {count} other backends in {dbname}",
28+ count=count, dbname=dbname)
29+
30+ @staticmethod
31+ def _dropDatabase(cursor, dbname):
32+ """Drop the given database."""
33+ stmt = "DROP DATABASE %s" % dbname
34+ cursor.execute(stmt)
35+ debug(
36+ "Dropped {dbname}; statement: {stmt}",
37+ dbname=dbname, stmt=stmt)
38+
39 def isDirty(self):
40 from django.db import connections
41 in_transaction = any(