14625.2.2
by Colin Watson
Add garbo job to clean up broken SPR.dsc_binaries values. |
1 |
# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
|
8687.15.18
by Karl Fogel
Add the copyright header block to files under lib/canonical/. |
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
3 |
|
4 |
"""Test the database garbage collector."""
|
|
5 |
||
6 |
__metaclass__ = type |
|
7 |
__all__ = [] |
|
8 |
||
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
9 |
from datetime import ( |
10 |
datetime, |
|
11 |
timedelta, |
|
12 |
)
|
|
8758.2.63
by Stuart Bishop
Fix tests to cope with the more complex logging environment |
13 |
import logging |
14 |
from StringIO import StringIO |
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
15 |
import time |
16 |
||
17 |
from pytz import UTC |
|
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
18 |
from storm.expr import ( |
13581.1.1
by Danilo Segan
Merge gmb's fix for 814576. |
19 |
In, |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
20 |
Min, |
13581.1.1
by Danilo Segan
Merge gmb's fix for 814576. |
21 |
Not, |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
22 |
SQL, |
23 |
)
|
|
4953.7.10
by Stuart Bishop
Format imports |
24 |
from storm.locals import ( |
25 |
Int, |
|
26 |
Storm, |
|
27 |
)
|
|
8303.10.7
by James Henstridge
Add a garbo task to remove stale mailing list subscriptions when the |
28 |
from storm.store import Store |
8758.3.20
by Stuart Bishop
Add garbo job to rollup BugSummaryJournal |
29 |
from testtools.matchers import ( |
30 |
Equals, |
|
31 |
GreaterThan, |
|
32 |
)
|
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
33 |
import transaction |
7675.177.6
by Stuart Bishop
Garbage collect OpenIDAssociations, allow scripts to correct to the auth store as the correct database user, ensure changing database connection settings in the test suite resets ZStorm so new credentials are used |
34 |
from zope.component import getUtility |
8697.25.1
by Guilherme Salgado
New task ran as part of garbo-daily to delete unlinked person entries. |
35 |
from zope.security.proxy import removeSecurityProxy |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
36 |
|
13635.1.1
by Ian Booth
Add garbo job to remove old answer contacts |
37 |
from lp.answers.model.answercontact import AnswerContact |
8758.2.9
by Stuart Bishop
Tests and fixes for BugNotificationPruner |
38 |
from lp.bugs.model.bugnotification import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
39 |
BugNotification, |
40 |
BugNotificationRecipient, |
|
41 |
)
|
|
42 |
from lp.code.bzr import ( |
|
43 |
BranchFormat, |
|
44 |
RepositoryFormat, |
|
45 |
)
|
|
46 |
from lp.code.enums import CodeImportResultStatus |
|
11703.1.4
by Tim Penhey
Prune the CodeImportEvents. |
47 |
from lp.code.interfaces.codeimportevent import ICodeImportEventSet |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
48 |
from lp.code.model.branchjob import ( |
49 |
BranchJob, |
|
50 |
BranchUpgradeJob, |
|
51 |
)
|
|
11703.1.4
by Tim Penhey
Prune the CodeImportEvents. |
52 |
from lp.code.model.codeimportevent import CodeImportEvent |
8758.2.9
by Stuart Bishop
Tests and fixes for BugNotificationPruner |
53 |
from lp.code.model.codeimportresult import CodeImportResult |
8758.7.3
by Stuart Bishop
Remove failing tests for edge cases that will no longer occur |
54 |
from lp.registry.interfaces.person import IPersonSet |
11768.1.2
by Curtis Hovey
Used the deglobber to fix imports in python tests, then formatted them using format-new-and-modified-imports. |
55 |
from lp.scripts.garbo import ( |
4953.7.10
by Stuart Bishop
Format imports |
56 |
AntiqueSessionPruner, |
8758.2.31
by Stuart Bishop
BulkPruner tests |
57 |
BulkPruner, |
11768.1.2
by Curtis Hovey
Used the deglobber to fix imports in python tests, then formatted them using format-new-and-modified-imports. |
58 |
DailyDatabaseGarbageCollector, |
4953.7.17
by Stuart Bishop
Keep only last 6 authenticated sessions for a user |
59 |
DuplicateSessionPruner, |
8758.3.16
by Stuart Bishop
Fix tests for garbo-frequently.py jobs |
60 |
FrequentDatabaseGarbageCollector, |
11768.1.2
by Curtis Hovey
Used the deglobber to fix imports in python tests, then formatted them using format-new-and-modified-imports. |
61 |
HourlyDatabaseGarbageCollector, |
8758.4.18
by Stuart Bishop
Remove LoginToken rows older than 1 year |
62 |
LoginTokenPruner, |
11768.1.2
by Curtis Hovey
Used the deglobber to fix imports in python tests, then formatted them using format-new-and-modified-imports. |
63 |
OpenIDConsumerAssociationPruner, |
4953.7.10
by Stuart Bishop
Format imports |
64 |
UnusedSessionPruner, |
11768.1.2
by Curtis Hovey
Used the deglobber to fix imports in python tests, then formatted them using format-new-and-modified-imports. |
65 |
)
|
14606.3.1
by William Grant
Merge canonical.database into lp.services.database. |
66 |
from lp.services.config import config |
14606.3.4
by William Grant
Replace canonical.database usage everywhere, and format-imports. |
67 |
from lp.services.database import sqlbase |
14606.3.1
by William Grant
Merge canonical.database into lp.services.database. |
68 |
from lp.services.database.constants import ( |
69 |
ONE_DAY_AGO, |
|
70 |
SEVEN_DAYS_AGO, |
|
71 |
THIRTY_DAYS_AGO, |
|
72 |
UTC_NOW, |
|
73 |
)
|
|
14578.2.1
by William Grant
Move librarian stuff from canonical.launchpad to lp.services.librarian. canonical.librarian remains untouched. |
74 |
from lp.services.database.lpstorm import IMasterStore |
14550.1.1
by Steve Kowalik
Run format-imports over lib/lp and lib/canonical/launchpad |
75 |
from lp.services.identity.interfaces.account import AccountStatus |
76 |
from lp.services.identity.interfaces.emailaddress import EmailAddressStatus |
|
13811.1.1
by Jeroen Vermeulen
More lint. |
77 |
from lp.services.job.model.job import Job |
14578.2.1
by William Grant
Move librarian stuff from canonical.launchpad to lp.services.librarian. canonical.librarian remains untouched. |
78 |
from lp.services.librarian.model import TimeLimitedToken |
8758.2.63
by Stuart Bishop
Fix tests to cope with the more complex logging environment |
79 |
from lp.services.log.logger import NullHandler |
13811.1.1
by Jeroen Vermeulen
More lint. |
80 |
from lp.services.messages.model.message import Message |
14452.3.1
by William Grant
Move oauth code to lp.services.oauth. |
81 |
from lp.services.oauth.model import ( |
82 |
OAuthAccessToken, |
|
83 |
OAuthNonce, |
|
84 |
)
|
|
14455.3.4
by William Grant
Move OpenID consumer stuff to lp.services.openid. |
85 |
from lp.services.openid.model.openidconsumer import OpenIDConsumerNonce |
14578.2.1
by William Grant
Move librarian stuff from canonical.launchpad to lp.services.librarian. canonical.librarian remains untouched. |
86 |
from lp.services.scripts.tests import run_script |
4953.7.10
by Stuart Bishop
Format imports |
87 |
from lp.services.session.model import ( |
88 |
SessionData, |
|
89 |
SessionPkgData, |
|
90 |
)
|
|
14578.2.1
by William Grant
Move librarian stuff from canonical.launchpad to lp.services.librarian. canonical.librarian remains untouched. |
91 |
from lp.services.verification.interfaces.authtoken import LoginTokenType |
92 |
from lp.services.verification.model.logintoken import LoginToken |
|
14606.3.1
by William Grant
Merge canonical.database into lp.services.database. |
93 |
from lp.services.webapp.interfaces import ( |
94 |
IStoreSelector, |
|
95 |
MAIN_STORE, |
|
96 |
MASTER_FLAVOR, |
|
97 |
)
|
|
13635.1.1
by Ian Booth
Add garbo job to remove old answer contacts |
98 |
from lp.services.worlddata.interfaces.language import ILanguageSet |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
99 |
from lp.testing import ( |
13635.1.1
by Ian Booth
Add garbo job to remove old answer contacts |
100 |
person_logged_in, |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
101 |
TestCase, |
102 |
TestCaseWithFactory, |
|
103 |
)
|
|
14606.3.1
by William Grant
Merge canonical.database into lp.services.database. |
104 |
from lp.testing.layers import ( |
105 |
DatabaseLayer, |
|
106 |
LaunchpadScriptLayer, |
|
107 |
LaunchpadZopelessLayer, |
|
108 |
ZopelessDatabaseLayer, |
|
109 |
)
|
|
13581.1.1
by Danilo Segan
Merge gmb's fix for 814576. |
110 |
from lp.translations.model.potmsgset import POTMsgSet |
111 |
from lp.translations.model.translationtemplateitem import ( |
|
112 |
TranslationTemplateItem, |
|
113 |
)
|
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
114 |
|
115 |
||
116 |
class TestGarboScript(TestCase): |
|
117 |
layer = LaunchpadScriptLayer |
|
118 |
||
119 |
def test_daily_script(self): |
|
120 |
"""Ensure garbo-daily.py actually runs."""
|
|
121 |
rv, out, err = run_script( |
|
122 |
"cronscripts/garbo-daily.py", ["-q"], expect_returncode=0) |
|
123 |
self.failIf(out.strip(), "Output to stdout: %s" % out) |
|
124 |
self.failIf(err.strip(), "Output to stderr: %s" % err) |
|
125 |
DatabaseLayer.force_dirty_database() |
|
126 |
||
127 |
def test_hourly_script(self): |
|
128 |
"""Ensure garbo-hourly.py actually runs."""
|
|
129 |
rv, out, err = run_script( |
|
130 |
"cronscripts/garbo-hourly.py", ["-q"], expect_returncode=0) |
|
131 |
self.failIf(out.strip(), "Output to stdout: %s" % out) |
|
132 |
self.failIf(err.strip(), "Output to stderr: %s" % err) |
|
133 |
||
134 |
||
8758.2.36
by Stuart Bishop
Don't use the Launchpad database to test the BulkPruner |
135 |
class BulkFoo(Storm): |
136 |
__storm_table__ = 'bulkfoo' |
|
137 |
id = Int(primary=True) |
|
138 |
||
139 |
||
140 |
class BulkFooPruner(BulkPruner): |
|
141 |
target_table_class = BulkFoo |
|
142 |
ids_to_prune_query = "SELECT id FROM BulkFoo WHERE id < 5" |
|
8758.2.31
by Stuart Bishop
BulkPruner tests |
143 |
maximum_chunk_size = 2 |
144 |
||
145 |
||
146 |
class TestBulkPruner(TestCase): |
|
8758.2.36
by Stuart Bishop
Don't use the Launchpad database to test the BulkPruner |
147 |
layer = ZopelessDatabaseLayer |
8758.2.31
by Stuart Bishop
BulkPruner tests |
148 |
|
8758.2.34
by Stuart Bishop
Improvements from review feedback |
149 |
def setUp(self): |
150 |
super(TestBulkPruner, self).setUp() |
|
8758.2.36
by Stuart Bishop
Don't use the Launchpad database to test the BulkPruner |
151 |
|
152 |
self.store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR) |
|
153 |
self.store.execute("CREATE TABLE BulkFoo (id serial PRIMARY KEY)") |
|
154 |
||
8758.2.34
by Stuart Bishop
Improvements from review feedback |
155 |
for i in range(10): |
8758.2.36
by Stuart Bishop
Don't use the Launchpad database to test the BulkPruner |
156 |
self.store.add(BulkFoo()) |
8758.2.34
by Stuart Bishop
Improvements from review feedback |
157 |
|
8758.2.63
by Stuart Bishop
Fix tests to cope with the more complex logging environment |
158 |
self.log = logging.getLogger('garbo') |
159 |
||
8758.2.31
by Stuart Bishop
BulkPruner tests |
160 |
def test_bulkpruner(self): |
8758.2.63
by Stuart Bishop
Fix tests to cope with the more complex logging environment |
161 |
pruner = BulkFooPruner(self.log) |
8758.2.31
by Stuart Bishop
BulkPruner tests |
162 |
|
8758.2.34
by Stuart Bishop
Improvements from review feedback |
163 |
# The loop thinks there is stuff to do. Confirm the initial
|
164 |
# state is sane.
|
|
8758.2.31
by Stuart Bishop
BulkPruner tests |
165 |
self.assertFalse(pruner.isDone()) |
166 |
||
8758.2.34
by Stuart Bishop
Improvements from review feedback |
167 |
# An arbitrary chunk size.
|
168 |
chunk_size = 2 |
|
169 |
||
8758.2.36
by Stuart Bishop
Don't use the Launchpad database to test the BulkPruner |
170 |
# Determine how many items to prune and to leave rather than
|
171 |
# hardcode these numbers.
|
|
172 |
num_to_prune = self.store.find( |
|
173 |
BulkFoo, BulkFoo.id < 5).count() |
|
174 |
num_to_leave = self.store.find( |
|
175 |
BulkFoo, BulkFoo.id >= 5).count() |
|
8758.2.34
by Stuart Bishop
Improvements from review feedback |
176 |
self.assertTrue(num_to_prune > chunk_size) |
8758.2.31
by Stuart Bishop
BulkPruner tests |
177 |
self.assertTrue(num_to_leave > 0) |
178 |
||
8758.2.36
by Stuart Bishop
Don't use the Launchpad database to test the BulkPruner |
179 |
# Run one loop. Make sure it committed by throwing away
|
180 |
# uncommitted changes.
|
|
8758.2.31
by Stuart Bishop
BulkPruner tests |
181 |
pruner(chunk_size) |
182 |
transaction.abort() |
|
183 |
||
8758.2.34
by Stuart Bishop
Improvements from review feedback |
184 |
# Confirm 'chunk_size' items where removed; no more, no less.
|
8758.2.36
by Stuart Bishop
Don't use the Launchpad database to test the BulkPruner |
185 |
num_remaining = self.store.find(BulkFoo).count() |
8758.2.31
by Stuart Bishop
BulkPruner tests |
186 |
expected_num_remaining = num_to_leave + num_to_prune - chunk_size |
187 |
self.assertEqual(num_remaining, expected_num_remaining) |
|
188 |
||
8758.2.34
by Stuart Bishop
Improvements from review feedback |
189 |
# The loop thinks there is more stuff to do.
|
8758.2.31
by Stuart Bishop
BulkPruner tests |
190 |
self.assertFalse(pruner.isDone()) |
191 |
||
8758.2.34
by Stuart Bishop
Improvements from review feedback |
192 |
# Run the loop to completion, removing the remaining targetted
|
193 |
# rows.
|
|
8758.2.31
by Stuart Bishop
BulkPruner tests |
194 |
while not pruner.isDone(): |
8758.2.34
by Stuart Bishop
Improvements from review feedback |
195 |
pruner(1000000) |
8758.2.31
by Stuart Bishop
BulkPruner tests |
196 |
transaction.abort() |
197 |
||
8758.2.34
by Stuart Bishop
Improvements from review feedback |
198 |
# Confirm we have removed all targetted rows.
|
8758.2.36
by Stuart Bishop
Don't use the Launchpad database to test the BulkPruner |
199 |
self.assertEqual(self.store.find(BulkFoo, BulkFoo.id < 5).count(), 0) |
8758.2.34
by Stuart Bishop
Improvements from review feedback |
200 |
|
201 |
# Confirm we have the expected number of remaining rows.
|
|
202 |
# With the previous check, this means no untargetted rows
|
|
203 |
# where removed.
|
|
8758.2.31
by Stuart Bishop
BulkPruner tests |
204 |
self.assertEqual( |
8758.2.36
by Stuart Bishop
Don't use the Launchpad database to test the BulkPruner |
205 |
self.store.find(BulkFoo, BulkFoo.id >= 5).count(), num_to_leave) |
8758.2.31
by Stuart Bishop
BulkPruner tests |
206 |
|
8758.2.35
by Stuart Bishop
Add optional cleanUp method to ITunableLoop |
207 |
# Cleanup clears up our resources.
|
208 |
pruner.cleanUp() |
|
209 |
||
8758.2.31
by Stuart Bishop
BulkPruner tests |
210 |
# We can run it again - temporary objects cleaned up.
|
8758.2.63
by Stuart Bishop
Fix tests to cope with the more complex logging environment |
211 |
pruner = BulkFooPruner(self.log) |
8758.2.31
by Stuart Bishop
BulkPruner tests |
212 |
while not pruner.isDone(): |
213 |
pruner(chunk_size) |
|
214 |
||
215 |
||
4953.7.7
by Stuart Bishop
Session model classes and session pruner tests |
216 |
class TestSessionPruner(TestCase): |
217 |
layer = ZopelessDatabaseLayer |
|
218 |
||
219 |
def setUp(self): |
|
220 |
super(TestCase, self).setUp() |
|
4953.7.12
by Stuart Bishop
Use addCleanup instead of tearDown |
221 |
|
222 |
# Session database isn't reset between tests. We need to do this
|
|
223 |
# manually.
|
|
224 |
nuke_all_sessions = IMasterStore(SessionData).find(SessionData).remove |
|
225 |
nuke_all_sessions() |
|
226 |
self.addCleanup(nuke_all_sessions) |
|
4953.7.7
by Stuart Bishop
Session model classes and session pruner tests |
227 |
|
4953.7.11
by Stuart Bishop
datetime.now(UTC) is clearer |
228 |
recent = datetime.now(UTC) |
4953.7.7
by Stuart Bishop
Session model classes and session pruner tests |
229 |
yesterday = recent - timedelta(days=1) |
230 |
ancient = recent - timedelta(days=61) |
|
231 |
||
4953.7.17
by Stuart Bishop
Keep only last 6 authenticated sessions for a user |
232 |
self.make_session(u'recent_auth', recent, 'auth1') |
233 |
self.make_session(u'recent_unauth', recent, False) |
|
234 |
self.make_session(u'yesterday_auth', yesterday, 'auth2') |
|
235 |
self.make_session(u'yesterday_unauth', yesterday, False) |
|
236 |
self.make_session(u'ancient_auth', ancient, 'auth3') |
|
237 |
self.make_session(u'ancient_unauth', ancient, False) |
|
238 |
||
8758.2.63
by Stuart Bishop
Fix tests to cope with the more complex logging environment |
239 |
self.log = logging.getLogger('garbo') |
240 |
||
4953.7.17
by Stuart Bishop
Keep only last 6 authenticated sessions for a user |
241 |
def make_session(self, client_id, accessed, authenticated=None): |
242 |
session_data = SessionData() |
|
243 |
session_data.client_id = client_id |
|
244 |
session_data.last_accessed = accessed |
|
245 |
IMasterStore(SessionData).add(session_data) |
|
246 |
||
247 |
if authenticated: |
|
248 |
# Add login time information.
|
|
249 |
session_pkg_data = SessionPkgData() |
|
250 |
session_pkg_data.client_id = client_id |
|
251 |
session_pkg_data.product_id = u'launchpad.authenticateduser' |
|
252 |
session_pkg_data.key = u'logintime' |
|
253 |
session_pkg_data.pickle = 'value is ignored' |
|
254 |
IMasterStore(SessionPkgData).add(session_pkg_data) |
|
255 |
||
256 |
# Add authenticated as information.
|
|
257 |
session_pkg_data = SessionPkgData() |
|
258 |
session_pkg_data.client_id = client_id |
|
259 |
session_pkg_data.product_id = u'launchpad.authenticateduser' |
|
260 |
session_pkg_data.key = u'accountid' |
|
261 |
# Normally Account.id, but the session pruning works
|
|
262 |
# at the SQL level and doesn't unpickle anything.
|
|
263 |
session_pkg_data.pickle = authenticated |
|
264 |
IMasterStore(SessionPkgData).add(session_pkg_data) |
|
4953.7.7
by Stuart Bishop
Session model classes and session pruner tests |
265 |
|
266 |
def sessionExists(self, client_id): |
|
267 |
store = IMasterStore(SessionData) |
|
4953.7.8
by Stuart Bishop
Fix tests |
268 |
return not store.find( |
269 |
SessionData, SessionData.client_id == client_id).is_empty() |
|
4953.7.7
by Stuart Bishop
Session model classes and session pruner tests |
270 |
|
271 |
def test_antique_session_pruner(self): |
|
272 |
chunk_size = 2 |
|
8758.2.63
by Stuart Bishop
Fix tests to cope with the more complex logging environment |
273 |
pruner = AntiqueSessionPruner(self.log) |
4953.7.7
by Stuart Bishop
Session model classes and session pruner tests |
274 |
try: |
275 |
while not pruner.isDone(): |
|
276 |
pruner(chunk_size) |
|
277 |
finally: |
|
278 |
pruner.cleanUp() |
|
279 |
||
4953.7.8
by Stuart Bishop
Fix tests |
280 |
expected_sessions = set([ |
281 |
u'recent_auth', |
|
282 |
u'recent_unauth', |
|
283 |
u'yesterday_auth', |
|
284 |
u'yesterday_unauth', |
|
285 |
# u'ancient_auth',
|
|
286 |
# u'ancient_unauth',
|
|
287 |
])
|
|
288 |
||
289 |
found_sessions = set( |
|
290 |
IMasterStore(SessionData).find(SessionData.client_id)) |
|
291 |
||
292 |
self.assertEqual(expected_sessions, found_sessions) |
|
4953.7.7
by Stuart Bishop
Session model classes and session pruner tests |
293 |
|
294 |
def test_unused_session_pruner(self): |
|
295 |
chunk_size = 2 |
|
8758.2.63
by Stuart Bishop
Fix tests to cope with the more complex logging environment |
296 |
pruner = UnusedSessionPruner(self.log) |
4953.7.7
by Stuart Bishop
Session model classes and session pruner tests |
297 |
try: |
298 |
while not pruner.isDone(): |
|
299 |
pruner(chunk_size) |
|
300 |
finally: |
|
301 |
pruner.cleanUp() |
|
302 |
||
4953.7.8
by Stuart Bishop
Fix tests |
303 |
expected_sessions = set([ |
304 |
u'recent_auth', |
|
305 |
u'recent_unauth', |
|
306 |
u'yesterday_auth', |
|
307 |
# u'yesterday_unauth',
|
|
308 |
u'ancient_auth', |
|
309 |
# u'ancient_unauth',
|
|
310 |
])
|
|
311 |
||
312 |
found_sessions = set( |
|
313 |
IMasterStore(SessionData).find(SessionData.client_id)) |
|
314 |
||
315 |
self.assertEqual(expected_sessions, found_sessions) |
|
4953.7.7
by Stuart Bishop
Session model classes and session pruner tests |
316 |
|
4953.7.17
by Stuart Bishop
Keep only last 6 authenticated sessions for a user |
317 |
def test_duplicate_session_pruner(self): |
318 |
# None of the sessions created in setUp() are duplicates, so
|
|
319 |
# they will all survive the pruning.
|
|
320 |
expected_sessions = set([ |
|
321 |
u'recent_auth', |
|
322 |
u'recent_unauth', |
|
323 |
u'yesterday_auth', |
|
324 |
u'yesterday_unauth', |
|
325 |
u'ancient_auth', |
|
326 |
u'ancient_unauth', |
|
327 |
])
|
|
328 |
||
329 |
now = datetime.now(UTC) |
|
330 |
||
331 |
# Make some duplicate logins from a few days ago.
|
|
332 |
# Only the most recent 6 will be kept. Oldest is 'old dupe 9',
|
|
333 |
# most recent 'old dupe 1'.
|
|
334 |
for count in range(1, 10): |
|
335 |
self.make_session( |
|
336 |
u'old dupe %d' % count, |
|
337 |
now - timedelta(days=2, seconds=count), |
|
338 |
'old dupe') |
|
339 |
for count in range(1, 7): |
|
340 |
expected_sessions.add(u'old dupe %d' % count) |
|
341 |
||
342 |
# Make some other duplicate logins less than an hour old.
|
|
343 |
# All of these will be kept.
|
|
344 |
for count in range(1, 10): |
|
345 |
self.make_session(u'new dupe %d' % count, now, 'new dupe') |
|
346 |
expected_sessions.add(u'new dupe %d' % count) |
|
347 |
||
348 |
chunk_size = 2 |
|
8758.2.63
by Stuart Bishop
Fix tests to cope with the more complex logging environment |
349 |
pruner = DuplicateSessionPruner(self.log) |
4953.7.17
by Stuart Bishop
Keep only last 6 authenticated sessions for a user |
350 |
try: |
351 |
while not pruner.isDone(): |
|
352 |
pruner(chunk_size) |
|
353 |
finally: |
|
354 |
pruner.cleanUp() |
|
355 |
||
356 |
found_sessions = set( |
|
357 |
IMasterStore(SessionData).find(SessionData.client_id)) |
|
358 |
||
359 |
self.assertEqual(expected_sessions, found_sessions) |
|
360 |
||
4953.7.7
by Stuart Bishop
Session model classes and session pruner tests |
361 |
|
8303.10.1
by James Henstridge
Garbo jobs to link people to RevisionAuthors and HWSubmissions as new |
362 |
class TestGarbo(TestCaseWithFactory): |
8758.2.38
by Stuart Bishop
Fix test layer |
363 |
layer = LaunchpadZopelessLayer |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
364 |
|
365 |
def setUp(self): |
|
366 |
super(TestGarbo, self).setUp() |
|
8758.2.63
by Stuart Bishop
Fix tests to cope with the more complex logging environment |
367 |
|
368 |
# Silence the root Logger by instructing the garbo logger to not
|
|
369 |
# propagate messages.
|
|
370 |
self.log = logging.getLogger('garbo') |
|
371 |
self.log.addHandler(NullHandler()) |
|
372 |
self.log.propagate = 0 |
|
373 |
||
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
374 |
# Run the garbage collectors to remove any existing garbage,
|
375 |
# starting us in a known state.
|
|
376 |
self.runDaily() |
|
377 |
self.runHourly() |
|
8758.3.16
by Stuart Bishop
Fix tests for garbo-frequently.py jobs |
378 |
self.runFrequently() |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
379 |
|
8758.2.63
by Stuart Bishop
Fix tests to cope with the more complex logging environment |
380 |
# Capture garbo log output to tests can examine it.
|
381 |
self.log_buffer = StringIO() |
|
382 |
handler = logging.StreamHandler(self.log_buffer) |
|
383 |
self.log.addHandler(handler) |
|
384 |
||
8758.3.16
by Stuart Bishop
Fix tests for garbo-frequently.py jobs |
385 |
def runFrequently(self, maximum_chunk_size=2, test_args=()): |
386 |
transaction.commit() |
|
387 |
LaunchpadZopelessLayer.switchDbUser('garbo_daily') |
|
388 |
collector = FrequentDatabaseGarbageCollector( |
|
389 |
test_args=list(test_args)) |
|
390 |
collector._maximum_chunk_size = maximum_chunk_size |
|
391 |
collector.logger = self.log |
|
392 |
collector.main() |
|
393 |
return collector |
|
394 |
||
8758.2.9
by Stuart Bishop
Tests and fixes for BugNotificationPruner |
395 |
def runDaily(self, maximum_chunk_size=2, test_args=()): |
7176.8.5
by Stuart Bishop
Fix transaction handling in garbo tests |
396 |
transaction.commit() |
7675.177.6
by Stuart Bishop
Garbage collect OpenIDAssociations, allow scripts to correct to the auth store as the correct database user, ensure changing database connection settings in the test suite resets ZStorm so new credentials are used |
397 |
LaunchpadZopelessLayer.switchDbUser('garbo_daily') |
8758.2.9
by Stuart Bishop
Tests and fixes for BugNotificationPruner |
398 |
collector = DailyDatabaseGarbageCollector(test_args=list(test_args)) |
7675.177.7
by Stuart Bishop
Ensure tests run multiple iterations of the LoopTuner and add logging |
399 |
collector._maximum_chunk_size = maximum_chunk_size |
8758.2.63
by Stuart Bishop
Fix tests to cope with the more complex logging environment |
400 |
collector.logger = self.log |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
401 |
collector.main() |
8758.2.4
by Stuart Bishop
Tests to ensure PersonEmailAddressLinkChecker actually detects and reports corruption. |
402 |
return collector |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
403 |
|
8758.2.9
by Stuart Bishop
Tests and fixes for BugNotificationPruner |
404 |
def runHourly(self, maximum_chunk_size=2, test_args=()): |
7675.177.6
by Stuart Bishop
Garbage collect OpenIDAssociations, allow scripts to correct to the auth store as the correct database user, ensure changing database connection settings in the test suite resets ZStorm so new credentials are used |
405 |
LaunchpadZopelessLayer.switchDbUser('garbo_hourly') |
8758.2.9
by Stuart Bishop
Tests and fixes for BugNotificationPruner |
406 |
collector = HourlyDatabaseGarbageCollector(test_args=list(test_args)) |
7675.177.7
by Stuart Bishop
Ensure tests run multiple iterations of the LoopTuner and add logging |
407 |
collector._maximum_chunk_size = maximum_chunk_size |
8758.2.63
by Stuart Bishop
Fix tests to cope with the more complex logging environment |
408 |
collector.logger = self.log |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
409 |
collector.main() |
8758.2.4
by Stuart Bishop
Tests to ensure PersonEmailAddressLinkChecker actually detects and reports corruption. |
410 |
return collector |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
411 |
|
412 |
def test_OAuthNoncePruner(self): |
|
4953.7.11
by Stuart Bishop
datetime.now(UTC) is clearer |
413 |
now = datetime.now(UTC) |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
414 |
timestamps = [ |
13635.1.2
by Ian Booth
Lint |
415 |
now - timedelta(days=2), # Garbage |
416 |
now - timedelta(days=1) - timedelta(seconds=60), # Garbage |
|
417 |
now - timedelta(days=1) + timedelta(seconds=60), # Not garbage |
|
418 |
now, # Not garbage |
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
419 |
]
|
420 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
7675.177.6
by Stuart Bishop
Garbage collect OpenIDAssociations, allow scripts to correct to the auth store as the correct database user, ensure changing database connection settings in the test suite resets ZStorm so new credentials are used |
421 |
store = IMasterStore(OAuthNonce) |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
422 |
|
423 |
# Make sure we start with 0 nonces.
|
|
424 |
self.failUnlessEqual(store.find(OAuthNonce).count(), 0) |
|
425 |
||
426 |
for timestamp in timestamps: |
|
13365.3.3
by William Grant
Fix garbo to cope with new pk. |
427 |
store.add(OAuthNonce( |
428 |
access_token=OAuthAccessToken.get(1), |
|
13635.1.2
by Ian Booth
Lint |
429 |
request_timestamp=timestamp, |
430 |
nonce=str(timestamp))) |
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
431 |
transaction.commit() |
432 |
||
433 |
# Make sure we have 4 nonces now.
|
|
434 |
self.failUnlessEqual(store.find(OAuthNonce).count(), 4) |
|
435 |
||
8758.3.16
by Stuart Bishop
Fix tests for garbo-frequently.py jobs |
436 |
self.runFrequently( |
437 |
maximum_chunk_size=60) # 1 minute maximum chunk size |
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
438 |
|
7675.177.6
by Stuart Bishop
Garbage collect OpenIDAssociations, allow scripts to correct to the auth store as the correct database user, ensure changing database connection settings in the test suite resets ZStorm so new credentials are used |
439 |
store = IMasterStore(OAuthNonce) |
440 |
||
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
441 |
# Now back to two, having removed the two garbage entries.
|
442 |
self.failUnlessEqual(store.find(OAuthNonce).count(), 2) |
|
443 |
||
444 |
# And none of them are older than a day.
|
|
445 |
# Hmm... why is it I'm putting tz aware datetimes in and getting
|
|
446 |
# naive datetimes back? Bug in the SQLObject compatibility layer?
|
|
447 |
# Test is still fine as we know the timezone.
|
|
448 |
self.failUnless( |
|
449 |
store.find( |
|
450 |
Min(OAuthNonce.request_timestamp)).one().replace(tzinfo=UTC) |
|
451 |
>= now - timedelta(days=1)) |
|
452 |
||
7675.88.8
by Stuart Bishop
Stop ShipIt OpenID consumer sharing tables with the SSO server, dev replication setup fixes and test fixes |
453 |
def test_OpenIDConsumerNoncePruner(self): |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
454 |
now = int(time.mktime(time.gmtime())) |
455 |
MINUTES = 60 |
|
456 |
HOURS = 60 * 60 |
|
457 |
DAYS = 24 * HOURS |
|
458 |
timestamps = [ |
|
13635.1.2
by Ian Booth
Lint |
459 |
now - 2 * DAYS, # Garbage |
460 |
now - 1 * DAYS - 1 * MINUTES, # Garbage |
|
461 |
now - 1 * DAYS + 1 * MINUTES, # Not garbage |
|
462 |
now, # Not garbage |
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
463 |
]
|
464 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
465 |
||
7675.88.8
by Stuart Bishop
Stop ShipIt OpenID consumer sharing tables with the SSO server, dev replication setup fixes and test fixes |
466 |
store = IMasterStore(OpenIDConsumerNonce) |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
467 |
|
468 |
# Make sure we start with 0 nonces.
|
|
7675.88.8
by Stuart Bishop
Stop ShipIt OpenID consumer sharing tables with the SSO server, dev replication setup fixes and test fixes |
469 |
self.failUnlessEqual(store.find(OpenIDConsumerNonce).count(), 0) |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
470 |
|
471 |
for timestamp in timestamps: |
|
8447.3.9
by James Henstridge
Fix test_OpenIDConsumerNoncePruner test. |
472 |
store.add(OpenIDConsumerNonce( |
473 |
u'http://server/', timestamp, u'aa')) |
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
474 |
transaction.commit() |
475 |
||
476 |
# Make sure we have 4 nonces now.
|
|
7675.88.8
by Stuart Bishop
Stop ShipIt OpenID consumer sharing tables with the SSO server, dev replication setup fixes and test fixes |
477 |
self.failUnlessEqual(store.find(OpenIDConsumerNonce).count(), 4) |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
478 |
|
479 |
# Run the garbage collector.
|
|
8758.3.16
by Stuart Bishop
Fix tests for garbo-frequently.py jobs |
480 |
self.runFrequently(maximum_chunk_size=60) # 1 minute maximum chunks. |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
481 |
|
7675.177.6
by Stuart Bishop
Garbage collect OpenIDAssociations, allow scripts to correct to the auth store as the correct database user, ensure changing database connection settings in the test suite resets ZStorm so new credentials are used |
482 |
store = IMasterStore(OpenIDConsumerNonce) |
483 |
||
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
484 |
# We should now have 2 nonces.
|
7675.88.8
by Stuart Bishop
Stop ShipIt OpenID consumer sharing tables with the SSO server, dev replication setup fixes and test fixes |
485 |
self.failUnlessEqual(store.find(OpenIDConsumerNonce).count(), 2) |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
486 |
|
487 |
# And none of them are older than 1 day
|
|
7675.88.8
by Stuart Bishop
Stop ShipIt OpenID consumer sharing tables with the SSO server, dev replication setup fixes and test fixes |
488 |
earliest = store.find(Min(OpenIDConsumerNonce.timestamp)).one() |
13635.1.2
by Ian Booth
Lint |
489 |
self.failUnless( |
490 |
earliest >= now - 24 * 60 * 60, 'Still have old nonces') |
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
491 |
|
492 |
def test_CodeImportResultPruner(self): |
|
4953.7.11
by Stuart Bishop
datetime.now(UTC) is clearer |
493 |
now = datetime.now(UTC) |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
494 |
store = IMasterStore(CodeImportResult) |
495 |
||
8377.9.10
by Michael Hudson
untested introduction of a config value for failure limit |
496 |
results_to_keep_count = ( |
497 |
config.codeimport.consecutive_failure_limit - 1) |
|
498 |
||
7675.743.4
by Jonathan Lange
Don't use sample data in garbo test for codeimport |
499 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
500 |
code_import_id = self.factory.makeCodeImport().id |
|
501 |
machine_id = self.factory.makeCodeImportMachine().id |
|
502 |
requester_id = self.factory.makePerson().id |
|
503 |
transaction.commit() |
|
504 |
||
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
505 |
def new_code_import_result(timestamp): |
506 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
507 |
CodeImportResult( |
|
508 |
date_created=timestamp, |
|
7675.743.4
by Jonathan Lange
Don't use sample data in garbo test for codeimport |
509 |
code_importID=code_import_id, machineID=machine_id, |
510 |
requesting_userID=requester_id, |
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
511 |
status=CodeImportResultStatus.FAILURE, |
512 |
date_job_started=timestamp) |
|
513 |
transaction.commit() |
|
514 |
||
515 |
new_code_import_result(now - timedelta(days=60)) |
|
8377.9.10
by Michael Hudson
untested introduction of a config value for failure limit |
516 |
for i in range(results_to_keep_count - 1): |
13635.1.2
by Ian Booth
Lint |
517 |
new_code_import_result(now - timedelta(days=19 + i)) |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
518 |
|
519 |
# Run the garbage collector
|
|
520 |
self.runDaily() |
|
521 |
||
8377.9.10
by Michael Hudson
untested introduction of a config value for failure limit |
522 |
# Nothing is removed, because we always keep the
|
523 |
# ``results_to_keep_count`` latest.
|
|
7675.177.6
by Stuart Bishop
Garbage collect OpenIDAssociations, allow scripts to correct to the auth store as the correct database user, ensure changing database connection settings in the test suite resets ZStorm so new credentials are used |
524 |
store = IMasterStore(CodeImportResult) |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
525 |
self.failUnlessEqual( |
8377.9.10
by Michael Hudson
untested introduction of a config value for failure limit |
526 |
results_to_keep_count, |
527 |
store.find(CodeImportResult).count()) |
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
528 |
|
529 |
new_code_import_result(now - timedelta(days=31)) |
|
530 |
self.runDaily() |
|
7675.177.6
by Stuart Bishop
Garbage collect OpenIDAssociations, allow scripts to correct to the auth store as the correct database user, ensure changing database connection settings in the test suite resets ZStorm so new credentials are used |
531 |
store = IMasterStore(CodeImportResult) |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
532 |
self.failUnlessEqual( |
8377.9.10
by Michael Hudson
untested introduction of a config value for failure limit |
533 |
results_to_keep_count, |
534 |
store.find(CodeImportResult).count()) |
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
535 |
|
536 |
new_code_import_result(now - timedelta(days=29)) |
|
537 |
self.runDaily() |
|
7675.177.6
by Stuart Bishop
Garbage collect OpenIDAssociations, allow scripts to correct to the auth store as the correct database user, ensure changing database connection settings in the test suite resets ZStorm so new credentials are used |
538 |
store = IMasterStore(CodeImportResult) |
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
539 |
self.failUnlessEqual( |
8377.9.10
by Michael Hudson
untested introduction of a config value for failure limit |
540 |
results_to_keep_count, |
541 |
store.find(CodeImportResult).count()) |
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
542 |
|
543 |
# We now have no CodeImportResults older than 30 days
|
|
544 |
self.failUnless( |
|
545 |
store.find( |
|
546 |
Min(CodeImportResult.date_created)).one().replace(tzinfo=UTC) |
|
547 |
>= now - timedelta(days=30)) |
|
548 |
||
11703.1.4
by Tim Penhey
Prune the CodeImportEvents. |
549 |
def test_CodeImportEventPruner(self): |
4953.7.11
by Stuart Bishop
datetime.now(UTC) is clearer |
550 |
now = datetime.now(UTC) |
11703.1.4
by Tim Penhey
Prune the CodeImportEvents. |
551 |
store = IMasterStore(CodeImportResult) |
552 |
||
553 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
554 |
machine = self.factory.makeCodeImportMachine() |
|
555 |
requester = self.factory.makePerson() |
|
556 |
# Create 6 code import events for this machine, 3 on each side of 30
|
|
11768.1.3
by Curtis Hovey
Hushed lint |
557 |
# days. Use the event set to the extra event data rows get created
|
558 |
# too.
|
|
11703.1.4
by Tim Penhey
Prune the CodeImportEvents. |
559 |
event_set = getUtility(ICodeImportEventSet) |
560 |
for age in (35, 33, 31, 29, 27, 15): |
|
561 |
event_set.newOnline( |
|
562 |
machine, user=requester, message='Hello', |
|
563 |
_date_created=(now - timedelta(days=age))) |
|
564 |
transaction.commit() |
|
565 |
||
566 |
# Run the garbage collector
|
|
567 |
self.runDaily() |
|
568 |
||
569 |
# Only the three most recent results are left.
|
|
570 |
events = list(machine.events) |
|
571 |
self.assertEqual(3, len(events)) |
|
572 |
# We now have no CodeImportEvents older than 30 days
|
|
573 |
self.failUnless( |
|
574 |
store.find( |
|
575 |
Min(CodeImportEvent.date_created)).one().replace(tzinfo=UTC) |
|
576 |
>= now - timedelta(days=30)) |
|
577 |
||
10556.4.3
by Guilherme Salgado
Remove the auth_* attributes from DatabaseConfig and fix a bunch of tests which used to rely on auth stores. |
578 |
def test_OpenIDConsumerAssociationPruner(self): |
579 |
pruner = OpenIDConsumerAssociationPruner |
|
7675.177.6
by Stuart Bishop
Garbage collect OpenIDAssociations, allow scripts to correct to the auth store as the correct database user, ensure changing database connection settings in the test suite resets ZStorm so new credentials are used |
580 |
table_name = pruner.table_name |
581 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
582 |
store_selector = getUtility(IStoreSelector) |
|
10556.4.3
by Guilherme Salgado
Remove the auth_* attributes from DatabaseConfig and fix a bunch of tests which used to rely on auth stores. |
583 |
store = store_selector.get(MAIN_STORE, MASTER_FLAVOR) |
7675.177.6
by Stuart Bishop
Garbage collect OpenIDAssociations, allow scripts to correct to the auth store as the correct database user, ensure changing database connection settings in the test suite resets ZStorm so new credentials are used |
584 |
now = time.time() |
585 |
# Create some associations in the past with lifetimes
|
|
586 |
for delta in range(0, 20): |
|
587 |
store.execute(""" |
|
588 |
INSERT INTO %s (server_url, handle, issued, lifetime) |
|
589 |
VALUES (%s, %s, %d, %d) |
|
13635.1.2
by Ian Booth
Lint |
590 |
""" % (table_name, str(delta), str(delta), now - 10, delta)) |
7675.177.6
by Stuart Bishop
Garbage collect OpenIDAssociations, allow scripts to correct to the auth store as the correct database user, ensure changing database connection settings in the test suite resets ZStorm so new credentials are used |
591 |
transaction.commit() |
592 |
||
7675.177.9
by Stuart Bishop
Comment OpenIDAssociationPruner test and confirm it isn't trashing everything |
593 |
# Ensure that we created at least one expirable row (using the
|
594 |
# test start time as 'now').
|
|
7675.177.6
by Stuart Bishop
Garbage collect OpenIDAssociations, allow scripts to correct to the auth store as the correct database user, ensure changing database connection settings in the test suite resets ZStorm so new credentials are used |
595 |
num_expired = store.execute(""" |
596 |
SELECT COUNT(*) FROM %s |
|
597 |
WHERE issued + lifetime < %f |
|
598 |
""" % (table_name, now)).get_one()[0] |
|
599 |
self.failUnless(num_expired > 0) |
|
600 |
||
7675.177.9
by Stuart Bishop
Comment OpenIDAssociationPruner test and confirm it isn't trashing everything |
601 |
# Expire all those expirable rows, and possibly a few more if this
|
602 |
# test is running slow.
|
|
8758.3.16
by Stuart Bishop
Fix tests for garbo-frequently.py jobs |
603 |
self.runFrequently() |
7675.177.6
by Stuart Bishop
Garbage collect OpenIDAssociations, allow scripts to correct to the auth store as the correct database user, ensure changing database connection settings in the test suite resets ZStorm so new credentials are used |
604 |
|
605 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
10556.4.3
by Guilherme Salgado
Remove the auth_* attributes from DatabaseConfig and fix a bunch of tests which used to rely on auth stores. |
606 |
store = store_selector.get(MAIN_STORE, MASTER_FLAVOR) |
7675.177.9
by Stuart Bishop
Comment OpenIDAssociationPruner test and confirm it isn't trashing everything |
607 |
# Confirm all the rows we know should have been expired have
|
608 |
# been expired. These are the ones that would be expired using
|
|
609 |
# the test start time as 'now'.
|
|
7675.177.6
by Stuart Bishop
Garbage collect OpenIDAssociations, allow scripts to correct to the auth store as the correct database user, ensure changing database connection settings in the test suite resets ZStorm so new credentials are used |
610 |
num_expired = store.execute(""" |
611 |
SELECT COUNT(*) FROM %s |
|
612 |
WHERE issued + lifetime < %f |
|
613 |
""" % (table_name, now)).get_one()[0] |
|
614 |
self.failUnlessEqual(num_expired, 0) |
|
615 |
||
7675.177.9
by Stuart Bishop
Comment OpenIDAssociationPruner test and confirm it isn't trashing everything |
616 |
# Confirm that we haven't expired everything. This test will fail
|
617 |
# if it has taken 10 seconds to get this far.
|
|
618 |
num_unexpired = store.execute( |
|
619 |
"SELECT COUNT(*) FROM %s" % table_name).get_one()[0] |
|
620 |
self.failUnless(num_unexpired > 0) |
|
621 |
||
8303.10.5
by James Henstridge
Update tests that expect RevisionAuthors or HWSubmissions to be linked |
622 |
def test_RevisionAuthorEmailLinker(self): |
8303.10.1
by James Henstridge
Garbo jobs to link people to RevisionAuthors and HWSubmissions as new |
623 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
624 |
rev1 = self.factory.makeRevision('Author 1 <author-1@Example.Org>') |
|
625 |
rev2 = self.factory.makeRevision('Author 2 <author-2@Example.Org>') |
|
626 |
||
627 |
person1 = self.factory.makePerson(email='Author-1@example.org') |
|
628 |
person2 = self.factory.makePerson( |
|
629 |
email='Author-2@example.org', |
|
630 |
email_address_status=EmailAddressStatus.NEW) |
|
631 |
||
632 |
self.assertEqual(rev1.revision_author.person, None) |
|
633 |
self.assertEqual(rev2.revision_author.person, None) |
|
634 |
||
635 |
self.runDaily() |
|
636 |
||
637 |
# Only the validated email address associated with a Person
|
|
638 |
# causes a linkage.
|
|
639 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
640 |
self.assertEqual(rev1.revision_author.person, person1) |
|
641 |
self.assertEqual(rev2.revision_author.person, None) |
|
642 |
||
643 |
# Validating an email address creates a linkage.
|
|
644 |
person2.validateAndEnsurePreferredEmail(person2.guessedemails[0]) |
|
645 |
self.assertEqual(rev2.revision_author.person, None) |
|
646 |
||
647 |
self.runDaily() |
|
648 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
649 |
self.assertEqual(rev2.revision_author.person, person2) |
|
650 |
||
8303.10.5
by James Henstridge
Update tests that expect RevisionAuthors or HWSubmissions to be linked |
651 |
def test_HWSubmissionEmailLinker(self): |
8303.10.1
by James Henstridge
Garbo jobs to link people to RevisionAuthors and HWSubmissions as new |
652 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
653 |
sub1 = self.factory.makeHWSubmission( |
|
654 |
emailaddress='author-1@Example.Org') |
|
655 |
sub2 = self.factory.makeHWSubmission( |
|
656 |
emailaddress='author-2@Example.Org') |
|
657 |
||
658 |
person1 = self.factory.makePerson(email='Author-1@example.org') |
|
659 |
person2 = self.factory.makePerson( |
|
660 |
email='Author-2@example.org', |
|
661 |
email_address_status=EmailAddressStatus.NEW) |
|
662 |
||
663 |
self.assertEqual(sub1.owner, None) |
|
664 |
self.assertEqual(sub2.owner, None) |
|
665 |
||
666 |
self.runDaily() |
|
667 |
||
668 |
# Only the validated email address associated with a Person
|
|
669 |
# causes a linkage.
|
|
670 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
671 |
self.assertEqual(sub1.owner, person1) |
|
672 |
self.assertEqual(sub2.owner, None) |
|
673 |
||
674 |
# Validating an email address creates a linkage.
|
|
675 |
person2.validateAndEnsurePreferredEmail(person2.guessedemails[0]) |
|
676 |
self.assertEqual(sub2.owner, None) |
|
677 |
||
678 |
self.runDaily() |
|
679 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
680 |
self.assertEqual(sub2.owner, person2) |
|
681 |
||
8697.25.5
by Stuart Bishop
Add --experimental option to garbo-*.py, and move PersonPruner to the experimental list so it is only run on staging |
682 |
def test_PersonPruner(self): |
8697.25.1
by Guilherme Salgado
New task ran as part of garbo-daily to delete unlinked person entries. |
683 |
personset = getUtility(IPersonSet) |
684 |
# Switch the DB user because the garbo_daily user isn't allowed to
|
|
685 |
# create person entries.
|
|
686 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
687 |
||
688 |
# Create two new person entries, both not linked to anything. One of
|
|
689 |
# them will have the present day as its date created, and so will not
|
|
690 |
# be deleted, whereas the other will have a creation date far in the
|
|
691 |
# past, so it will be deleted.
|
|
12521.5.3
by Steve Kowalik
More lint. |
692 |
self.factory.makePerson(name='test-unlinked-person-new') |
8697.25.1
by Guilherme Salgado
New task ran as part of garbo-daily to delete unlinked person entries. |
693 |
person_old = self.factory.makePerson(name='test-unlinked-person-old') |
694 |
removeSecurityProxy(person_old).datecreated = datetime( |
|
695 |
2008, 01, 01, tzinfo=UTC) |
|
696 |
||
8697.25.5
by Stuart Bishop
Add --experimental option to garbo-*.py, and move PersonPruner to the experimental list so it is only run on staging |
697 |
# Normally, the garbage collector will do nothing because the
|
698 |
# PersonPruner is experimental
|
|
8697.25.1
by Guilherme Salgado
New task ran as part of garbo-daily to delete unlinked person entries. |
699 |
self.runDaily() |
8697.25.5
by Stuart Bishop
Add --experimental option to garbo-*.py, and move PersonPruner to the experimental list so it is only run on staging |
700 |
self.assertIsNot( |
701 |
personset.getByName('test-unlinked-person-new'), None) |
|
702 |
self.assertIsNot( |
|
703 |
personset.getByName('test-unlinked-person-old'), None) |
|
8697.25.1
by Guilherme Salgado
New task ran as part of garbo-daily to delete unlinked person entries. |
704 |
|
8697.25.5
by Stuart Bishop
Add --experimental option to garbo-*.py, and move PersonPruner to the experimental list so it is only run on staging |
705 |
# When we run the garbage collector with experimental jobs turned
|
706 |
# on, the old unlinked Person is removed.
|
|
707 |
self.runDaily(test_args=['--experimental']) |
|
8697.25.1
by Guilherme Salgado
New task ran as part of garbo-daily to delete unlinked person entries. |
708 |
self.assertIsNot( |
709 |
personset.getByName('test-unlinked-person-new'), None) |
|
710 |
self.assertIs(personset.getByName('test-unlinked-person-old'), None) |
|
711 |
||
8758.2.9
by Stuart Bishop
Tests and fixes for BugNotificationPruner |
712 |
def test_BugNotificationPruner(self): |
713 |
# Create some sample data
|
|
714 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
715 |
notification = BugNotification( |
|
716 |
messageID=1, |
|
717 |
bugID=1, |
|
718 |
is_comment=True, |
|
719 |
date_emailed=None) |
|
12521.5.3
by Steve Kowalik
More lint. |
720 |
BugNotificationRecipient( |
8758.2.9
by Stuart Bishop
Tests and fixes for BugNotificationPruner |
721 |
bug_notification=notification, |
722 |
personID=1, |
|
723 |
reason_header='Whatever', |
|
724 |
reason_body='Whatever') |
|
725 |
# We don't create an entry exactly 30 days old to avoid
|
|
726 |
# races in the test.
|
|
727 |
for delta in range(-45, -14, 2): |
|
728 |
message = Message(rfc822msgid=str(delta)) |
|
729 |
notification = BugNotification( |
|
730 |
message=message, |
|
731 |
bugID=1, |
|
732 |
is_comment=True, |
|
733 |
date_emailed=UTC_NOW + SQL("interval '%d days'" % delta)) |
|
12521.5.3
by Steve Kowalik
More lint. |
734 |
BugNotificationRecipient( |
8758.2.9
by Stuart Bishop
Tests and fixes for BugNotificationPruner |
735 |
bug_notification=notification, |
736 |
personID=1, |
|
737 |
reason_header='Whatever', |
|
738 |
reason_body='Whatever') |
|
739 |
||
740 |
store = IMasterStore(BugNotification) |
|
741 |
||
742 |
# Ensure we are at a known starting point.
|
|
743 |
num_unsent = store.find( |
|
744 |
BugNotification, |
|
745 |
BugNotification.date_emailed == None).count() |
|
746 |
num_old = store.find( |
|
747 |
BugNotification, |
|
748 |
BugNotification.date_emailed < THIRTY_DAYS_AGO).count() |
|
749 |
num_new = store.find( |
|
750 |
BugNotification, |
|
751 |
BugNotification.date_emailed > THIRTY_DAYS_AGO).count() |
|
752 |
||
753 |
self.assertEqual(num_unsent, 1) |
|
754 |
self.assertEqual(num_old, 8) |
|
755 |
self.assertEqual(num_new, 8) |
|
756 |
||
757 |
# Run the garbage collector.
|
|
758 |
self.runDaily() |
|
759 |
||
760 |
# We should have 9 BugNotifications left.
|
|
761 |
self.assertEqual( |
|
762 |
store.find( |
|
763 |
BugNotification, |
|
764 |
BugNotification.date_emailed == None).count(), |
|
765 |
num_unsent) |
|
766 |
self.assertEqual( |
|
767 |
store.find( |
|
768 |
BugNotification, |
|
769 |
BugNotification.date_emailed > THIRTY_DAYS_AGO).count(), |
|
770 |
num_new) |
|
771 |
self.assertEqual( |
|
772 |
store.find( |
|
773 |
BugNotification, |
|
774 |
BugNotification.date_emailed < THIRTY_DAYS_AGO).count(), |
|
775 |
0) |
|
776 |
||
13635.1.1
by Ian Booth
Add garbo job to remove old answer contacts |
777 |
def _test_AnswerContactPruner(self, status, interval, expected_count=0): |
778 |
# Garbo should remove answer contacts for accounts with given 'status'
|
|
779 |
# which was set more than 'interval' days ago.
|
|
780 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
781 |
store = IMasterStore(AnswerContact) |
|
782 |
||
783 |
person = self.factory.makePerson() |
|
784 |
person.addLanguage(getUtility(ILanguageSet)['en']) |
|
785 |
question = self.factory.makeQuestion() |
|
786 |
with person_logged_in(question.owner): |
|
787 |
question.target.addAnswerContact(person, person) |
|
788 |
Store.of(question).flush() |
|
789 |
self.assertEqual( |
|
790 |
store.find( |
|
791 |
AnswerContact, |
|
792 |
AnswerContact.person == person.id).count(), |
|
793 |
1) |
|
794 |
||
795 |
account = person.account |
|
796 |
account.status = status |
|
797 |
# We flush because a trigger sets the date_status_set and we need to
|
|
798 |
# modify it ourselves.
|
|
799 |
Store.of(account).flush() |
|
800 |
if interval is not None: |
|
801 |
account.date_status_set = interval |
|
802 |
||
803 |
self.runDaily() |
|
804 |
||
805 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
806 |
self.assertEqual( |
|
807 |
store.find( |
|
808 |
AnswerContact, |
|
809 |
AnswerContact.person == person.id).count(), |
|
810 |
expected_count) |
|
811 |
||
812 |
def test_AnswerContactPruner_deactivated_accounts(self): |
|
813 |
# Answer contacts with an account deactivated at least one day ago
|
|
814 |
# should be pruned.
|
|
815 |
self._test_AnswerContactPruner(AccountStatus.DEACTIVATED, ONE_DAY_AGO) |
|
816 |
||
817 |
def test_AnswerContactPruner_suspended_accounts(self): |
|
818 |
# Answer contacts with an account suspended at least seven days ago
|
|
819 |
# should be pruned.
|
|
820 |
self._test_AnswerContactPruner( |
|
821 |
AccountStatus.SUSPENDED, SEVEN_DAYS_AGO) |
|
822 |
||
823 |
def test_AnswerContactPruner_doesnt_prune_recently_changed_accounts(self): |
|
824 |
# Answer contacts which are suspended or deactivated inside the
|
|
825 |
# minimum time interval are not pruned.
|
|
826 |
self._test_AnswerContactPruner( |
|
827 |
AccountStatus.DEACTIVATED, None, expected_count=1) |
|
828 |
self._test_AnswerContactPruner( |
|
829 |
AccountStatus.SUSPENDED, ONE_DAY_AGO, expected_count=1) |
|
14039.1.8
by Brad Crittenden
Fixed lint |
830 |
|
7675.440.8
by Paul Hummer
Turned the job pruner into a branch job pruner |
831 |
def test_BranchJobPruner(self): |
7675.440.12
by Paul Hummer
Added comments, removed tempfile. |
832 |
# Garbo should remove jobs completed over 30 days ago.
|
7675.440.1
by Paul Hummer
Added JobPruner to garbo daily with accompanying tests |
833 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
7675.440.2
by Paul Hummer
Added failing test for JobPruner |
834 |
store = IMasterStore(Job) |
835 |
||
7675.440.10
by Paul Hummer
Removed creating a tree |
836 |
db_branch = self.factory.makeAnyBranch() |
7675.440.2
by Paul Hummer
Added failing test for JobPruner |
837 |
db_branch.branch_format = BranchFormat.BZR_BRANCH_5 |
838 |
db_branch.repository_format = RepositoryFormat.BZR_KNIT_1 |
|
7176.8.7
by Stuart Bishop
Just a flush needed |
839 |
Store.of(db_branch).flush() |
13717.1.3
by Aaron Bentley
Include requester in BranchUpgradeJobs. |
840 |
branch_job = BranchUpgradeJob.create( |
841 |
db_branch, self.factory.makePerson()) |
|
7675.440.3
by Paul Hummer
Committing at a WTF moment to go take a walk |
842 |
branch_job.job.date_finished = THIRTY_DAYS_AGO |
7675.440.4
by Paul Hummer
Got a working test |
843 |
|
844 |
self.assertEqual( |
|
845 |
store.find( |
|
846 |
BranchJob, |
|
847 |
BranchJob.branch == db_branch.id).count(), |
|
848 |
1) |
|
7675.440.2
by Paul Hummer
Added failing test for JobPruner |
849 |
|
12521.5.3
by Steve Kowalik
More lint. |
850 |
self.runDaily() |
7675.440.2
by Paul Hummer
Added failing test for JobPruner |
851 |
|
7675.440.4
by Paul Hummer
Got a working test |
852 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
7675.440.2
by Paul Hummer
Added failing test for JobPruner |
853 |
self.assertEqual( |
7675.440.4
by Paul Hummer
Got a working test |
854 |
store.find( |
855 |
BranchJob, |
|
856 |
BranchJob.branch == db_branch.id).count(), |
|
857 |
0) |
|
7675.440.1
by Paul Hummer
Added JobPruner to garbo daily with accompanying tests |
858 |
|
7675.440.9
by Paul Hummer
Added another test to make sure that garbo only deletes completed branch jobs that are old. |
859 |
def test_BranchJobPruner_doesnt_prune_recent_jobs(self): |
7675.440.12
by Paul Hummer
Added comments, removed tempfile. |
860 |
# Check to make sure the garbo doesn't remove jobs that aren't more
|
861 |
# than thirty days old.
|
|
7675.440.9
by Paul Hummer
Added another test to make sure that garbo only deletes completed branch jobs that are old. |
862 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
863 |
store = IMasterStore(Job) |
|
864 |
||
7675.477.1
by Paul Hummer
Reverted the reversion of the patch that went into devel by mistake |
865 |
db_branch = self.factory.makeAnyBranch( |
866 |
branch_format=BranchFormat.BZR_BRANCH_5, |
|
867 |
repository_format=RepositoryFormat.BZR_KNIT_1) |
|
7675.440.9
by Paul Hummer
Added another test to make sure that garbo only deletes completed branch jobs that are old. |
868 |
|
13717.1.3
by Aaron Bentley
Include requester in BranchUpgradeJobs. |
869 |
branch_job = BranchUpgradeJob.create( |
870 |
db_branch, self.factory.makePerson()) |
|
7675.440.9
by Paul Hummer
Added another test to make sure that garbo only deletes completed branch jobs that are old. |
871 |
branch_job.job.date_finished = THIRTY_DAYS_AGO |
872 |
||
7675.477.1
by Paul Hummer
Reverted the reversion of the patch that went into devel by mistake |
873 |
db_branch2 = self.factory.makeAnyBranch( |
874 |
branch_format=BranchFormat.BZR_BRANCH_5, |
|
875 |
repository_format=RepositoryFormat.BZR_KNIT_1) |
|
13717.1.3
by Aaron Bentley
Include requester in BranchUpgradeJobs. |
876 |
BranchUpgradeJob.create(db_branch2, self.factory.makePerson()) |
7675.440.9
by Paul Hummer
Added another test to make sure that garbo only deletes completed branch jobs that are old. |
877 |
|
12521.5.3
by Steve Kowalik
More lint. |
878 |
self.runDaily() |
7675.440.9
by Paul Hummer
Added another test to make sure that garbo only deletes completed branch jobs that are old. |
879 |
|
880 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
12521.5.3
by Steve Kowalik
More lint. |
881 |
self.assertEqual(store.find(BranchJob).count(), 1) |
7675.440.9
by Paul Hummer
Added another test to make sure that garbo only deletes completed branch jobs that are old. |
882 |
|
8758.2.47
by Stuart Bishop
Switch ObsoleteBugAttachmentPruner to use BulkPruner |
883 |
def test_ObsoleteBugAttachmentPruner(self): |
10606.5.2
by Abel Deuring
new garbo job: delete bug attachments that don't have a LibraryFileContent record |
884 |
# Bug attachments without a LibraryFileContent record are removed.
|
885 |
||
886 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
887 |
bug = self.factory.makeBug() |
|
888 |
attachment = self.factory.makeBugAttachment(bug=bug) |
|
889 |
transaction.commit() |
|
890 |
||
891 |
# Bug attachments that have a LibraryFileContent record are
|
|
892 |
# not deleted.
|
|
893 |
self.assertIsNot(attachment.libraryfile.content, None) |
|
894 |
self.runDaily() |
|
895 |
self.assertEqual(bug.attachments.count(), 1) |
|
896 |
||
897 |
# But once we delete the LfC record, the attachment is deleted
|
|
898 |
# in the next daily garbo run.
|
|
899 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
900 |
removeSecurityProxy(attachment.libraryfile).content = None |
|
901 |
transaction.commit() |
|
902 |
self.runDaily() |
|
903 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
904 |
self.assertEqual(bug.attachments.count(), 0) |
|
905 |
||
7675.809.6
by Robert Collins
Create a garbo daily task to clean up file access tokens. |
906 |
def test_TimeLimitedTokenPruner(self): |
907 |
# Ensure there are no tokens
|
|
908 |
store = sqlbase.session_store() |
|
909 |
map(store.remove, store.find(TimeLimitedToken)) |
|
910 |
store.flush() |
|
911 |
self.assertEqual(0, len(list(store.find(TimeLimitedToken, |
|
7675.809.30
by Robert Collins
Rename url to path in TimeLimitedToken. |
912 |
path="sample path")))) |
7675.809.8
by Robert Collins
Test that only old file access tokens are garbage collected. |
913 |
# One to clean and one to keep
|
7675.809.30
by Robert Collins
Rename url to path in TimeLimitedToken. |
914 |
store.add(TimeLimitedToken(path="sample path", token="foo", |
7675.809.6
by Robert Collins
Create a garbo daily task to clean up file access tokens. |
915 |
created=datetime(2008, 01, 01, tzinfo=UTC))) |
7675.809.30
by Robert Collins
Rename url to path in TimeLimitedToken. |
916 |
store.add(TimeLimitedToken(path="sample path", token="bar")), |
7675.809.6
by Robert Collins
Create a garbo daily task to clean up file access tokens. |
917 |
store.commit() |
7675.809.8
by Robert Collins
Test that only old file access tokens are garbage collected. |
918 |
self.assertEqual(2, len(list(store.find(TimeLimitedToken, |
7675.809.30
by Robert Collins
Rename url to path in TimeLimitedToken. |
919 |
path="sample path")))) |
7675.809.8
by Robert Collins
Test that only old file access tokens are garbage collected. |
920 |
self.runDaily() |
921 |
self.assertEqual(0, len(list(store.find(TimeLimitedToken, |
|
7675.809.30
by Robert Collins
Rename url to path in TimeLimitedToken. |
922 |
path="sample path", token="foo")))) |
7675.809.6
by Robert Collins
Create a garbo daily task to clean up file access tokens. |
923 |
self.assertEqual(1, len(list(store.find(TimeLimitedToken, |
7675.809.30
by Robert Collins
Rename url to path in TimeLimitedToken. |
924 |
path="sample path", token="bar")))) |
7675.809.14
by Robert Collins
Merge trunk resolving conflicts, fingers crossed. |
925 |
|
7675.758.8
by Jeroen Vermeulen
Okay, okay, running it through garbo instead of cron. |
926 |
def test_CacheSuggestivePOTemplates(self): |
927 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
928 |
template = self.factory.makePOTemplate() |
|
929 |
self.runDaily() |
|
930 |
||
931 |
store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR) |
|
932 |
count, = store.execute(""" |
|
933 |
SELECT count(*)
|
|
934 |
FROM SuggestivePOTemplate
|
|
935 |
WHERE potemplate = %s |
|
7675.809.14
by Robert Collins
Merge trunk resolving conflicts, fingers crossed. |
936 |
""" % sqlbase.quote(template.id)).get_one() |
7675.758.8
by Jeroen Vermeulen
Okay, okay, running it through garbo instead of cron. |
937 |
|
938 |
self.assertEqual(1, count) |
|
8758.3.20
by Stuart Bishop
Add garbo job to rollup BugSummaryJournal |
939 |
|
940 |
def test_BugSummaryJournalRollup(self): |
|
941 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
942 |
store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR) |
|
943 |
||
944 |
# Generate a load of entries in BugSummaryJournal.
|
|
945 |
store.execute("UPDATE BugTask SET status=42") |
|
946 |
||
947 |
# We only need a few to test.
|
|
948 |
num_rows = store.execute( |
|
949 |
"SELECT COUNT(*) FROM BugSummaryJournal").get_one()[0] |
|
950 |
self.assertThat(num_rows, GreaterThan(10)) |
|
951 |
||
952 |
self.runFrequently() |
|
953 |
||
954 |
# We just care that the rows have been removed. The bugsummary
|
|
955 |
# tests confirm that the rollup stored method is working correctly.
|
|
956 |
num_rows = store.execute( |
|
957 |
"SELECT COUNT(*) FROM BugSummaryJournal").get_one()[0] |
|
958 |
self.assertThat(num_rows, Equals(0)) |
|
13581.1.1
by Danilo Segan
Merge gmb's fix for 814576. |
959 |
|
960 |
def test_UnusedPOTMsgSetPruner_removes_obsolete_message_sets(self): |
|
961 |
# UnusedPOTMsgSetPruner removes any POTMsgSet that are
|
|
962 |
# participating in a POTemplate only as obsolete messages.
|
|
963 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
964 |
pofile = self.factory.makePOFile() |
|
965 |
translation_message = self.factory.makeCurrentTranslationMessage( |
|
966 |
pofile=pofile) |
|
967 |
translation_message.potmsgset.setSequence( |
|
968 |
pofile.potemplate, 0) |
|
969 |
transaction.commit() |
|
970 |
store = IMasterStore(POTMsgSet) |
|
971 |
obsolete_msgsets = store.find( |
|
972 |
POTMsgSet, |
|
973 |
TranslationTemplateItem.potmsgset == POTMsgSet.id, |
|
974 |
TranslationTemplateItem.sequence == 0) |
|
975 |
self.assertNotEqual(0, obsolete_msgsets.count()) |
|
976 |
self.runDaily() |
|
977 |
self.assertEqual(0, obsolete_msgsets.count()) |
|
978 |
||
979 |
def test_UnusedPOTMsgSetPruner_removes_unreferenced_message_sets(self): |
|
980 |
# If a POTMsgSet is not referenced by any templates the
|
|
981 |
# UnusedPOTMsgSetPruner will remove it.
|
|
982 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
983 |
potmsgset = self.factory.makePOTMsgSet() |
|
984 |
# Cheekily drop any references to the POTMsgSet we just created.
|
|
985 |
store = IMasterStore(POTMsgSet) |
|
986 |
store.execute( |
|
987 |
"DELETE FROM TranslationTemplateItem WHERE potmsgset = %s" |
|
988 |
% potmsgset.id) |
|
989 |
transaction.commit() |
|
990 |
unreferenced_msgsets = store.find( |
|
991 |
POTMsgSet, |
|
992 |
Not(In( |
|
993 |
POTMsgSet.id, |
|
994 |
SQL("SELECT potmsgset FROM TranslationTemplateItem")))) |
|
995 |
self.assertNotEqual(0, unreferenced_msgsets.count()) |
|
996 |
self.runDaily() |
|
997 |
self.assertEqual(0, unreferenced_msgsets.count()) |
|
13646.11.17
by Steve Kowalik
Write tests for the two new populators |
998 |
|
14625.2.2
by Colin Watson
Add garbo job to clean up broken SPR.dsc_binaries values. |
999 |
def test_SourcePackageReleaseDscBinariesUpdater_updates_incorrect(self): |
1000 |
# SourcePackageReleaseDscBinariesUpdater fixes incorrectly-separated
|
|
1001 |
# dsc_binaries values.
|
|
1002 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
14625.2.5
by Colin Watson
Simplify test as suggested by Gavin Panella. |
1003 |
spr = self.factory.makeSourcePackageRelease( |
1004 |
dsc_binaries="one two three") |
|
14625.2.2
by Colin Watson
Add garbo job to clean up broken SPR.dsc_binaries values. |
1005 |
transaction.commit() |
1006 |
self.runDaily() |
|
14625.2.5
by Colin Watson
Simplify test as suggested by Gavin Panella. |
1007 |
self.assertEqual("one, two, three", spr.dsc_binaries) |
14625.2.2
by Colin Watson
Add garbo job to clean up broken SPR.dsc_binaries values. |
1008 |
|
1009 |
def test_SourcePackageReleaseDscBinariesUpdater_skips_correct(self): |
|
1010 |
# SourcePackageReleaseDscBinariesUpdater leaves correct dsc_binaries
|
|
1011 |
# values alone.
|
|
1012 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
14625.2.5
by Colin Watson
Simplify test as suggested by Gavin Panella. |
1013 |
spr_one = self.factory.makeSourcePackageRelease(dsc_binaries="one") |
1014 |
spr_three = self.factory.makeSourcePackageRelease( |
|
1015 |
dsc_binaries="one, two, three") |
|
14625.2.2
by Colin Watson
Add garbo job to clean up broken SPR.dsc_binaries values. |
1016 |
transaction.commit() |
1017 |
self.runDaily() |
|
14625.2.5
by Colin Watson
Simplify test as suggested by Gavin Panella. |
1018 |
self.assertEqual("one", spr_one.dsc_binaries) |
1019 |
self.assertEqual("one, two, three", spr_three.dsc_binaries) |
|
14625.2.2
by Colin Watson
Add garbo job to clean up broken SPR.dsc_binaries values. |
1020 |
|
1021 |
def test_SourcePackageReleaseDscBinariesUpdater_skips_broken(self): |
|
1022 |
# There have been a few instances of Binary fields in PPA packages
|
|
1023 |
# that are formatted like a dependency relationship field, complete
|
|
1024 |
# with (>= ...). This is completely invalid (and failed to build),
|
|
1025 |
# but does exist historically, so we have to deal with it.
|
|
1026 |
# SourcePackageReleaseDscBinariesUpdater leaves such fields well
|
|
1027 |
# alone.
|
|
1028 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
14625.2.5
by Colin Watson
Simplify test as suggested by Gavin Panella. |
1029 |
spr = self.factory.makeSourcePackageRelease( |
1030 |
dsc_binaries="one (>= 1), two") |
|
14625.2.2
by Colin Watson
Add garbo job to clean up broken SPR.dsc_binaries values. |
1031 |
transaction.commit() |
1032 |
self.runDaily() |
|
14625.2.5
by Colin Watson
Simplify test as suggested by Gavin Panella. |
1033 |
self.assertEqual("one (>= 1), two", spr.dsc_binaries) |
14625.2.2
by Colin Watson
Add garbo job to clean up broken SPR.dsc_binaries values. |
1034 |
|
8758.4.18
by Stuart Bishop
Remove LoginToken rows older than 1 year |
1035 |
|
1036 |
class TestGarboTasks(TestCaseWithFactory): |
|
1037 |
layer = LaunchpadZopelessLayer |
|
1038 |
||
1039 |
def test_LoginTokenPruner(self): |
|
1040 |
store = IMasterStore(LoginToken) |
|
1041 |
now = datetime.now(UTC) |
|
1042 |
LaunchpadZopelessLayer.switchDbUser('testadmin') |
|
1043 |
||
1044 |
# It is configured as a daily task.
|
|
1045 |
self.assertTrue( |
|
1046 |
LoginTokenPruner in DailyDatabaseGarbageCollector.tunable_loops) |
|
1047 |
||
1048 |
# Create a token that will be pruned.
|
|
1049 |
old_token = LoginToken( |
|
1050 |
email='whatever', tokentype=LoginTokenType.NEWACCOUNT) |
|
1051 |
old_token.date_created = now - timedelta(days=666) |
|
1052 |
old_token_id = old_token.id |
|
1053 |
store.add(old_token) |
|
1054 |
||
1055 |
# Create a token that will not be pruned.
|
|
1056 |
current_token = LoginToken( |
|
1057 |
email='whatever', tokentype=LoginTokenType.NEWACCOUNT) |
|
1058 |
current_token_id = current_token.id |
|
1059 |
store.add(current_token) |
|
1060 |
||
1061 |
# Run the pruner. Batching is tested by the BulkPruner tests so
|
|
1062 |
# no need to repeat here.
|
|
1063 |
LaunchpadZopelessLayer.switchDbUser('garbo_daily') |
|
1064 |
pruner = LoginTokenPruner(logging.getLogger('garbo')) |
|
1065 |
while not pruner.isDone(): |
|
1066 |
pruner(10) |
|
1067 |
pruner.cleanUp() |
|
1068 |
||
1069 |
# Only the old LoginToken is gone.
|
|
1070 |
self.assertEqual( |
|
1071 |
store.find(LoginToken, id=old_token_id).count(), 0) |
|
1072 |
self.assertEqual( |
|
1073 |
store.find(LoginToken, id=current_token_id).count(), 1) |