Merge lp:~stub/launchpad/cronscripts into lp:launchpad
- cronscripts
- Merge into devel
Status: | Merged | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Approved by: | Stuart Bishop | ||||||||||||
Approved revision: | no longer in the source branch. | ||||||||||||
Merged at revision: | 11395 | ||||||||||||
Proposed branch: | lp:~stub/launchpad/cronscripts | ||||||||||||
Merge into: | lp:launchpad | ||||||||||||
Diff against target: |
459 lines (+264/-14) 14 files modified
configs/testrunner/launchpad-lazr.conf (+1/-0) lib/canonical/config/schema-lazr.conf (+5/-1) lib/lp/bugs/doc/bugnotification-sending.txt (+1/-1) lib/lp/bugs/doc/checkwatches.txt (+1/-1) lib/lp/bugs/doc/sourceforge-remote-products.txt (+1/-1) lib/lp/registry/doc/teammembership.txt (+1/-0) lib/lp/services/scripts/base.py (+63/-3) lib/lp/services/scripts/tests/cronscripts.ini (+2/-0) lib/lp/services/scripts/tests/example-cronscript.py (+30/-0) lib/lp/services/scripts/tests/test_cronscript_enabled.py (+144/-0) lib/lp/soyuz/doc/buildd-slavescanner.txt (+2/-2) lib/lp/soyuz/scripts/tests/test_processupload.py (+6/-5) lib/lp/testing/tests/test_standard_test_template.py (+6/-0) lib/lp/translations/doc/poexport-request.txt (+1/-0) |
||||||||||||
To merge this branch: | bzr merge lp:~stub/launchpad/cronscripts | ||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Abel Deuring (community) | code | Approve | |
Review via email: mp+31934@code.launchpad.net |
Commit message
Enable and disable cronscripts using a configuration file.
Description of the change
Steps towards Bug #607391.
Adds a config file controlling cronscripts. This config file allows them to be selectively or in bulk disabled from running.
Robert Collins (lifeless) wrote : | # |
Thanks for working on this Stuart, its key to making rollouts safer
and more reliable.
I did have a small question though; our conf system is kindof like an
ini file already; how does using a regular ini file from within it
help?
-Rob
Stuart Bishop (stub) wrote : | # |
On Fri, Aug 20, 2010 at 12:28 AM, Robert Collins
<email address hidden> wrote:
> Thanks for working on this Stuart, its key to making rollouts safer
> and more reliable.
>
> I did have a small question though; our conf system is kindof like an
> ini file already; how does using a regular ini file from within it
> help?
Currently, altering our existing config files is a heavyweight
operation. If we can fix this operational issue, we could collapse the
cron .ini file into the main config. I just took a lightweight
approach that we can expand on (scheduling shutdowns requested in the
bug for instance). I suspect we will stick with the .ini approach
until move to a zookeeper type system to control runtime
configuration.
The alternative I considered was using a separate PostgreSQL
configuration database, but after discussion with Gary we decided even
a separate PostgreSQL database doesn't provide the robustness we want
(and is probably NIH other zookeeper type systems).
--
Stuart Bishop <email address hidden>
http://
Robert Collins (lifeless) wrote : | # |
I'm ok with an ini file; but would like to note that changing our
config is -only- heavyweight because we've chosen to have it so.
We can, in principle, have another config file referenced just like
you are here; I don't particularly care for that though.
I don't like the idea of another pg db either; zookeepr or something
may be fairly far away.
So I'm +0.5 or something on the ini; I think its a shame to have
*another* mechanism in play, but I'm keen on getting this work out
here; I think we should consider the presence of the two config
systems a techdebt bug and file it as such though.
-Rob
Preview Diff
1 | === modified file 'configs/testrunner/launchpad-lazr.conf' | |||
2 | --- configs/testrunner/launchpad-lazr.conf 2010-07-16 20:55:29 +0000 | |||
3 | +++ configs/testrunner/launchpad-lazr.conf 2010-08-19 09:52:48 +0000 | |||
4 | @@ -7,6 +7,7 @@ | |||
5 | 7 | 7 | ||
6 | 8 | [canonical] | 8 | [canonical] |
7 | 9 | chunkydiff: False | 9 | chunkydiff: False |
8 | 10 | cron_control_file: lib/lp/services/scripts/tests/cronscripts.ini | ||
9 | 10 | 11 | ||
10 | 11 | [archivepublisher] | 12 | [archivepublisher] |
11 | 12 | base_url: http://ftpmaster.internal/ | 13 | base_url: http://ftpmaster.internal/ |
12 | 13 | 14 | ||
13 | === modified file 'lib/canonical/config/schema-lazr.conf' | |||
14 | --- lib/canonical/config/schema-lazr.conf 2010-08-18 17:51:27 +0000 | |||
15 | +++ lib/canonical/config/schema-lazr.conf 2010-08-19 09:52:48 +0000 | |||
16 | @@ -209,6 +209,10 @@ | |||
17 | 209 | # datatype: string | 209 | # datatype: string |
18 | 210 | admin_address: system-error@launchpad.net | 210 | admin_address: system-error@launchpad.net |
19 | 211 | 211 | ||
20 | 212 | # By default, relative to the root. | ||
21 | 213 | # datatype: filename | ||
22 | 214 | cron_control_file: cronscripts.ini | ||
23 | 215 | |||
24 | 212 | 216 | ||
25 | 213 | [checkwatches] | 217 | [checkwatches] |
26 | 214 | # The database user to run this process as. | 218 | # The database user to run this process as. |
27 | @@ -796,7 +800,7 @@ | |||
28 | 796 | 800 | ||
29 | 797 | # If true, only the source package names are imported into | 801 | # If true, only the source package names are imported into |
30 | 798 | # Launchpad | 802 | # Launchpad |
32 | 799 | # datatype: boolean" | 803 | # datatype: boolean |
33 | 800 | sourcepackagenames_only: false | 804 | sourcepackagenames_only: false |
34 | 801 | 805 | ||
35 | 802 | 806 | ||
36 | 803 | 807 | ||
37 | === modified file 'lib/lp/bugs/doc/bugnotification-sending.txt' | |||
38 | --- lib/lp/bugs/doc/bugnotification-sending.txt 2010-08-16 13:50:28 +0000 | |||
39 | +++ lib/lp/bugs/doc/bugnotification-sending.txt 2010-08-19 09:52:48 +0000 | |||
40 | @@ -931,7 +931,7 @@ | |||
41 | 931 | >>> process.returncode | 931 | >>> process.returncode |
42 | 932 | 0 | 932 | 0 |
43 | 933 | >>> print err | 933 | >>> print err |
45 | 934 | INFO Creating lockfile: /var/lock/launchpad-send-bug-notifications.lock | 934 | DEBUG ... |
46 | 935 | INFO Notifying mark@example.com about bug 2. | 935 | INFO Notifying mark@example.com about bug 2. |
47 | 936 | ... | 936 | ... |
48 | 937 | INFO Notifying support@ubuntu.com about bug 2. | 937 | INFO Notifying support@ubuntu.com about bug 2. |
49 | 938 | 938 | ||
50 | === modified file 'lib/lp/bugs/doc/checkwatches.txt' | |||
51 | --- lib/lp/bugs/doc/checkwatches.txt 2010-08-02 17:48:13 +0000 | |||
52 | +++ lib/lp/bugs/doc/checkwatches.txt 2010-08-19 09:52:48 +0000 | |||
53 | @@ -44,7 +44,7 @@ | |||
54 | 44 | 0 | 44 | 0 |
55 | 45 | 45 | ||
56 | 46 | >>> print err | 46 | >>> print err |
58 | 47 | INFO Creating lockfile: /var/lock/launchpad-checkwatches.lock | 47 | DEBUG ... |
59 | 48 | DEBUG No global batch size specified. | 48 | DEBUG No global batch size specified. |
60 | 49 | DEBUG Skipping updating Ubuntu Bugzilla watches. | 49 | DEBUG Skipping updating Ubuntu Bugzilla watches. |
61 | 50 | DEBUG No watches to update on http://bugs.debian.org | 50 | DEBUG No watches to update on http://bugs.debian.org |
62 | 51 | 51 | ||
63 | === modified file 'lib/lp/bugs/doc/sourceforge-remote-products.txt' | |||
64 | --- lib/lp/bugs/doc/sourceforge-remote-products.txt 2010-05-18 22:36:20 +0000 | |||
65 | +++ lib/lp/bugs/doc/sourceforge-remote-products.txt 2010-08-19 09:52:48 +0000 | |||
66 | @@ -117,7 +117,7 @@ | |||
67 | 117 | 0 | 117 | 0 |
68 | 118 | 118 | ||
69 | 119 | >>> print err | 119 | >>> print err |
71 | 120 | INFO Creating lockfile: /var/lock/launchpad-updateremoteproduct.lock | 120 | DEBUG ... |
72 | 121 | INFO No Products to update. | 121 | INFO No Products to update. |
73 | 122 | INFO Time for this run: ... seconds. | 122 | INFO Time for this run: ... seconds. |
74 | 123 | DEBUG Removing lock file:... | 123 | DEBUG Removing lock file:... |
75 | 124 | 124 | ||
76 | === modified file 'lib/lp/registry/doc/teammembership.txt' | |||
77 | --- lib/lp/registry/doc/teammembership.txt 2010-08-16 06:45:39 +0000 | |||
78 | +++ lib/lp/registry/doc/teammembership.txt 2010-08-19 09:52:48 +0000 | |||
79 | @@ -681,6 +681,7 @@ | |||
80 | 681 | 681 | ||
81 | 682 | >>> print '\n'.join( | 682 | >>> print '\n'.join( |
82 | 683 | ... line for line in err.split('\n') if 'INFO' not in line) | 683 | ... line for line in err.split('\n') if 'INFO' not in line) |
83 | 684 | DEBUG ... | ||
84 | 684 | DEBUG Sent warning email to name16 in launchpad-buildd-admins team. | 685 | DEBUG Sent warning email to name16 in launchpad-buildd-admins team. |
85 | 685 | DEBUG Sent warning email to name12 in landscape-developers team. | 686 | DEBUG Sent warning email to name12 in landscape-developers team. |
86 | 686 | DEBUG Removing lock file: /var/lock/launchpad-flag-expired-memberships.lock | 687 | DEBUG Removing lock file: /var/lock/launchpad-flag-expired-memberships.lock |
87 | 687 | 688 | ||
88 | === modified file 'lib/lp/services/scripts/base.py' | |||
89 | --- lib/lp/services/scripts/base.py 2010-04-27 06:15:37 +0000 | |||
90 | +++ lib/lp/services/scripts/base.py 2010-08-19 09:52:48 +0000 | |||
91 | @@ -9,17 +9,19 @@ | |||
92 | 9 | 'SilentLaunchpadScriptFailure' | 9 | 'SilentLaunchpadScriptFailure' |
93 | 10 | ] | 10 | ] |
94 | 11 | 11 | ||
95 | 12 | from ConfigParser import SafeConfigParser | ||
96 | 12 | from cProfile import Profile | 13 | from cProfile import Profile |
97 | 13 | import datetime | 14 | import datetime |
98 | 14 | import logging | 15 | import logging |
99 | 15 | from optparse import OptionParser | 16 | from optparse import OptionParser |
101 | 16 | import os | 17 | import os.path |
102 | 17 | import sys | 18 | import sys |
103 | 18 | 19 | ||
104 | 19 | from contrib.glock import GlobalLock, LockAlreadyAcquired | 20 | from contrib.glock import GlobalLock, LockAlreadyAcquired |
105 | 20 | import pytz | 21 | import pytz |
106 | 21 | from zope.component import getUtility | 22 | from zope.component import getUtility |
107 | 22 | 23 | ||
108 | 24 | from canonical.config import config | ||
109 | 23 | from canonical.database.sqlbase import ISOLATION_LEVEL_DEFAULT | 25 | from canonical.database.sqlbase import ISOLATION_LEVEL_DEFAULT |
110 | 24 | from canonical.launchpad import scripts | 26 | from canonical.launchpad import scripts |
111 | 25 | from canonical.launchpad.interfaces import IScriptActivitySet | 27 | from canonical.launchpad.interfaces import IScriptActivitySet |
112 | @@ -185,8 +187,8 @@ | |||
113 | 185 | def setup_lock(self): | 187 | def setup_lock(self): |
114 | 186 | """Create lockfile. | 188 | """Create lockfile. |
115 | 187 | 189 | ||
118 | 188 | Note that this will create a lockfile even if you don't actually use it. | 190 | Note that this will create a lockfile even if you don't actually |
119 | 189 | GlobalLock.__del__ is meant to clean it up though. | 191 | use it. GlobalLock.__del__ is meant to clean it up though. |
120 | 190 | """ | 192 | """ |
121 | 191 | self.lock = GlobalLock(self.lockfilepath, logger=self.logger) | 193 | self.lock = GlobalLock(self.lockfilepath, logger=self.logger) |
122 | 192 | 194 | ||
123 | @@ -290,6 +292,22 @@ | |||
124 | 290 | class LaunchpadCronScript(LaunchpadScript): | 292 | class LaunchpadCronScript(LaunchpadScript): |
125 | 291 | """Logs successful script runs in the database.""" | 293 | """Logs successful script runs in the database.""" |
126 | 292 | 294 | ||
127 | 295 | def __init__(self, name=None, dbuser=None, test_args=None): | ||
128 | 296 | """Initialize, and sys.exit() if the cronscript is disabled. | ||
129 | 297 | |||
130 | 298 | Rather than hand editing crontab files, cronscripts can be | ||
131 | 299 | enabled and disabled using a config file. | ||
132 | 300 | |||
133 | 301 | The control file location is specified by | ||
134 | 302 | config.canonical.cron_control_file. | ||
135 | 303 | """ | ||
136 | 304 | super(LaunchpadCronScript, self).__init__(name, dbuser, test_args) | ||
137 | 305 | |||
138 | 306 | enabled = cronscript_enabled( | ||
139 | 307 | config.canonical.cron_control_file, self.name, self.logger) | ||
140 | 308 | if not enabled: | ||
141 | 309 | sys.exit(0) | ||
142 | 310 | |||
143 | 293 | def record_activity(self, date_started, date_completed): | 311 | def record_activity(self, date_started, date_completed): |
144 | 294 | """Record the successful completion of the script.""" | 312 | """Record the successful completion of the script.""" |
145 | 295 | self.txn.begin() | 313 | self.txn.begin() |
146 | @@ -299,3 +317,45 @@ | |||
147 | 299 | date_started=date_started, | 317 | date_started=date_started, |
148 | 300 | date_completed=date_completed) | 318 | date_completed=date_completed) |
149 | 301 | self.txn.commit() | 319 | self.txn.commit() |
150 | 320 | |||
151 | 321 | |||
152 | 322 | def cronscript_enabled(control_path, name, log): | ||
153 | 323 | """Return True if the cronscript is enabled.""" | ||
154 | 324 | if not os.path.isabs(control_path): | ||
155 | 325 | control_path = os.path.abspath( | ||
156 | 326 | os.path.join(config.root, control_path)) | ||
157 | 327 | |||
158 | 328 | cron_config = SafeConfigParser({'enabled': str(True)}) | ||
159 | 329 | |||
160 | 330 | if not os.path.exists(control_path): | ||
161 | 331 | # No control file exists. Everything enabled by default. | ||
162 | 332 | log.debug("Cronscript control file not found at %s", control_path) | ||
163 | 333 | else: | ||
164 | 334 | log.debug("Cronscript control file found at %s", control_path) | ||
165 | 335 | |||
166 | 336 | # Try reading the config file. If it fails, we log the | ||
167 | 337 | # traceback and continue on using the defaults. | ||
168 | 338 | try: | ||
169 | 339 | cron_config.read(control_path) | ||
170 | 340 | except: | ||
171 | 341 | log.exception("Error parsing %s", control_path) | ||
172 | 342 | |||
173 | 343 | if cron_config.has_option(name, 'enabled'): | ||
174 | 344 | section = name | ||
175 | 345 | else: | ||
176 | 346 | section = 'DEFAULT' | ||
177 | 347 | |||
178 | 348 | try: | ||
179 | 349 | enabled = cron_config.getboolean(section, 'enabled') | ||
180 | 350 | except: | ||
181 | 351 | log.exception( | ||
182 | 352 | "Failed to load value from %s section of %s", | ||
183 | 353 | section, control_path) | ||
184 | 354 | enabled = True | ||
185 | 355 | |||
186 | 356 | if enabled: | ||
187 | 357 | log.debug("Enabled by %s section", section) | ||
188 | 358 | else: | ||
189 | 359 | log.info("Disabled by %s section", section) | ||
190 | 360 | |||
191 | 361 | return enabled | ||
192 | 302 | 362 | ||
193 | === added file 'lib/lp/services/scripts/tests/cronscripts.ini' | |||
194 | --- lib/lp/services/scripts/tests/cronscripts.ini 1970-01-01 00:00:00 +0000 | |||
195 | +++ lib/lp/services/scripts/tests/cronscripts.ini 2010-08-19 09:52:48 +0000 | |||
196 | @@ -0,0 +1,2 @@ | |||
197 | 1 | [example-cronscript-disabled] | ||
198 | 2 | enabled: False | ||
199 | 0 | 3 | ||
200 | === added file 'lib/lp/services/scripts/tests/example-cronscript.py' | |||
201 | --- lib/lp/services/scripts/tests/example-cronscript.py 1970-01-01 00:00:00 +0000 | |||
202 | +++ lib/lp/services/scripts/tests/example-cronscript.py 2010-08-19 09:52:48 +0000 | |||
203 | @@ -0,0 +1,30 @@ | |||
204 | 1 | # Copyright 2010 Canonical Ltd. This software is licensed under the | ||
205 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
206 | 3 | |||
207 | 4 | """An example cronscript. If it runs, it returns 42 as its return code.""" | ||
208 | 5 | |||
209 | 6 | __metaclass__ = type | ||
210 | 7 | __all__ = [] | ||
211 | 8 | |||
212 | 9 | import sys | ||
213 | 10 | |||
214 | 11 | from lp.services.scripts.base import ( | ||
215 | 12 | LaunchpadCronScript, SilentLaunchpadScriptFailure) | ||
216 | 13 | |||
217 | 14 | class Script(LaunchpadCronScript): | ||
218 | 15 | def main(self): | ||
219 | 16 | if self.name == 'example-cronscript-enabled': | ||
220 | 17 | raise SilentLaunchpadScriptFailure(42) | ||
221 | 18 | else: | ||
222 | 19 | # Raise a non-standard error code, as if the | ||
223 | 20 | # script was invoked as disabled the main() | ||
224 | 21 | # method should never be invoked. | ||
225 | 22 | raise SilentLaunchpadScriptFailure(999) | ||
226 | 23 | |||
227 | 24 | if __name__ == '__main__': | ||
228 | 25 | if sys.argv[-1] == 'enabled': | ||
229 | 26 | name = 'example-cronscript-enabled' | ||
230 | 27 | else: | ||
231 | 28 | name = 'example-cronscript-disabled' | ||
232 | 29 | script = Script(name) | ||
233 | 30 | script.lock_and_run() | ||
234 | 0 | 31 | ||
235 | === added file 'lib/lp/services/scripts/tests/test_cronscript_enabled.py' | |||
236 | --- lib/lp/services/scripts/tests/test_cronscript_enabled.py 1970-01-01 00:00:00 +0000 | |||
237 | +++ lib/lp/services/scripts/tests/test_cronscript_enabled.py 2010-08-19 09:52:48 +0000 | |||
238 | @@ -0,0 +1,144 @@ | |||
239 | 1 | # Copyright 2010 Canonical Ltd. This software is licensed under the | ||
240 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
241 | 3 | |||
242 | 4 | """Test the cronscript_enabled function in scripts/base.py.""" | ||
243 | 5 | |||
244 | 6 | __metaclass__ = type | ||
245 | 7 | |||
246 | 8 | from cStringIO import StringIO | ||
247 | 9 | from logging import DEBUG | ||
248 | 10 | import os.path | ||
249 | 11 | import subprocess | ||
250 | 12 | import sys | ||
251 | 13 | from tempfile import NamedTemporaryFile | ||
252 | 14 | from textwrap import dedent | ||
253 | 15 | import unittest | ||
254 | 16 | |||
255 | 17 | from lp.services.scripts.base import cronscript_enabled | ||
256 | 18 | from lp.testing import TestCase | ||
257 | 19 | from lp.testing.logger import MockLogger | ||
258 | 20 | |||
259 | 21 | |||
260 | 22 | class TestCronscriptEnabled(TestCase): | ||
261 | 23 | def setUp(self): | ||
262 | 24 | super(TestCronscriptEnabled, self).setUp() | ||
263 | 25 | self.log_output = StringIO() | ||
264 | 26 | self.log = MockLogger(self.log_output) | ||
265 | 27 | self.log.setLevel(DEBUG) | ||
266 | 28 | |||
267 | 29 | def makeConfig(self, body): | ||
268 | 30 | tempfile = NamedTemporaryFile(suffix='.ini') | ||
269 | 31 | tempfile.write(body) | ||
270 | 32 | tempfile.flush() | ||
271 | 33 | # Ensure a reference is kept until the test is over. | ||
272 | 34 | # tempfile will then clean itself up. | ||
273 | 35 | self.addCleanup(lambda x: None, tempfile) | ||
274 | 36 | return tempfile.name | ||
275 | 37 | |||
276 | 38 | def test_noconfig(self): | ||
277 | 39 | enabled = cronscript_enabled('/idontexist.ini', 'foo', self.log) | ||
278 | 40 | self.assertIs(True, enabled) | ||
279 | 41 | |||
280 | 42 | def test_emptyconfig(self): | ||
281 | 43 | config = self.makeConfig('') | ||
282 | 44 | enabled = cronscript_enabled(config, 'foo', self.log) | ||
283 | 45 | self.assertIs(True, enabled) | ||
284 | 46 | |||
285 | 47 | def test_default_true(self): | ||
286 | 48 | config = self.makeConfig(dedent("""\ | ||
287 | 49 | [DEFAULT] | ||
288 | 50 | enabled: True | ||
289 | 51 | """)) | ||
290 | 52 | enabled = cronscript_enabled(config, 'foo', self.log) | ||
291 | 53 | self.assertIs(True, enabled) | ||
292 | 54 | |||
293 | 55 | def test_default_false(self): | ||
294 | 56 | config = self.makeConfig(dedent("""\ | ||
295 | 57 | [DEFAULT] | ||
296 | 58 | enabled: False | ||
297 | 59 | """)) | ||
298 | 60 | enabled = cronscript_enabled(config, 'foo', self.log) | ||
299 | 61 | self.assertIs(False, enabled) | ||
300 | 62 | |||
301 | 63 | def test_specific_true(self): | ||
302 | 64 | config = self.makeConfig(dedent("""\ | ||
303 | 65 | [DEFAULT] | ||
304 | 66 | enabled: False | ||
305 | 67 | [foo] | ||
306 | 68 | enabled: True | ||
307 | 69 | """)) | ||
308 | 70 | enabled = cronscript_enabled(config, 'foo', self.log) | ||
309 | 71 | self.assertIs(True, enabled) | ||
310 | 72 | |||
311 | 73 | def test_specific_false(self): | ||
312 | 74 | config = self.makeConfig(dedent("""\ | ||
313 | 75 | [DEFAULT] | ||
314 | 76 | enabled: True | ||
315 | 77 | [foo] | ||
316 | 78 | enabled: False | ||
317 | 79 | """)) | ||
318 | 80 | enabled = cronscript_enabled(config, 'foo', self.log) | ||
319 | 81 | self.assertIs(False, enabled) | ||
320 | 82 | |||
321 | 83 | def test_broken_true(self): | ||
322 | 84 | config = self.makeConfig(dedent("""\ | ||
323 | 85 | # This file is unparsable | ||
324 | 86 | [DEFAULT | ||
325 | 87 | enabled: False | ||
326 | 88 | [foo | ||
327 | 89 | enabled: False | ||
328 | 90 | """)) | ||
329 | 91 | enabled = cronscript_enabled(config, 'foo', self.log) | ||
330 | 92 | self.assertIs(True, enabled) | ||
331 | 93 | |||
332 | 94 | def test_invalid_boolean_true(self): | ||
333 | 95 | config = self.makeConfig(dedent("""\ | ||
334 | 96 | [DEFAULT] | ||
335 | 97 | enabled: whoops | ||
336 | 98 | """)) | ||
337 | 99 | enabled = cronscript_enabled(config, 'foo', self.log) | ||
338 | 100 | self.assertIs(True, enabled) | ||
339 | 101 | |||
340 | 102 | def test_specific_missing_fallsback(self): | ||
341 | 103 | config = self.makeConfig(dedent("""\ | ||
342 | 104 | [DEFAULT] | ||
343 | 105 | enabled: False | ||
344 | 106 | [foo] | ||
345 | 107 | # There is a typo in the next line. | ||
346 | 108 | enobled: True | ||
347 | 109 | """)) | ||
348 | 110 | enabled = cronscript_enabled(config, 'foo', self.log) | ||
349 | 111 | self.assertIs(False, enabled) | ||
350 | 112 | |||
351 | 113 | def test_default_missing_fallsback(self): | ||
352 | 114 | config = self.makeConfig(dedent("""\ | ||
353 | 115 | [DEFAULT] | ||
354 | 116 | # There is a typo in the next line. Fallsback to hardcoded | ||
355 | 117 | # default. | ||
356 | 118 | enobled: False | ||
357 | 119 | [foo] | ||
358 | 120 | # There is a typo in the next line. | ||
359 | 121 | enobled: False | ||
360 | 122 | """)) | ||
361 | 123 | enabled = cronscript_enabled(config, 'foo', self.log) | ||
362 | 124 | self.assertIs(True, enabled) | ||
363 | 125 | |||
364 | 126 | def test_enabled_cronscript(self): | ||
365 | 127 | cmd = [ | ||
366 | 128 | sys.executable, | ||
367 | 129 | os.path.join(os.path.dirname(__file__), 'example-cronscript.py'), | ||
368 | 130 | '-qqqqq', 'enabled', | ||
369 | 131 | ] | ||
370 | 132 | self.assertEqual(42, subprocess.call(cmd)) | ||
371 | 133 | |||
372 | 134 | def test_disabled_cronscript(self): | ||
373 | 135 | cmd = [ | ||
374 | 136 | sys.executable, | ||
375 | 137 | os.path.join(os.path.dirname(__file__), 'example-cronscript.py'), | ||
376 | 138 | '-qqqqq', 'disabled', | ||
377 | 139 | ] | ||
378 | 140 | self.assertEqual(0, subprocess.call(cmd)) | ||
379 | 141 | |||
380 | 142 | |||
381 | 143 | def test_suite(): | ||
382 | 144 | return unittest.TestLoader().loadTestsFromName(__name__) | ||
383 | 0 | 145 | ||
384 | === modified file 'lib/lp/soyuz/doc/buildd-slavescanner.txt' | |||
385 | --- lib/lp/soyuz/doc/buildd-slavescanner.txt 2010-06-02 16:32:10 +0000 | |||
386 | +++ lib/lp/soyuz/doc/buildd-slavescanner.txt 2010-08-19 09:52:48 +0000 | |||
387 | @@ -382,7 +382,7 @@ | |||
388 | 382 | * Build Log: http://.../...i386.mozilla-firefox_0.9_BUILDING.txt.gz | 382 | * Build Log: http://.../...i386.mozilla-firefox_0.9_BUILDING.txt.gz |
389 | 383 | ... | 383 | ... |
390 | 384 | Upload log: | 384 | Upload log: |
392 | 385 | INFO Creating lockfile:... | 385 | DEBUG ... |
393 | 386 | DEBUG Initialising connection. | 386 | DEBUG Initialising connection. |
394 | 387 | ... | 387 | ... |
395 | 388 | DEBUG Removing lock file: /var/lock/process-upload-buildd.lock | 388 | DEBUG Removing lock file: /var/lock/process-upload-buildd.lock |
396 | @@ -625,7 +625,7 @@ | |||
397 | 625 | ... 'uploader.log')) | 625 | ... 'uploader.log')) |
398 | 626 | 626 | ||
399 | 627 | >>> print uploader_log.read() | 627 | >>> print uploader_log.read() |
401 | 628 | INFO Creating lockfile:... | 628 | DEBUG ... |
402 | 629 | DEBUG Initialising connection. | 629 | DEBUG Initialising connection. |
403 | 630 | DEBUG Beginning processing | 630 | DEBUG Beginning processing |
404 | 631 | DEBUG Creating directory /var/tmp/builddmaster/accepted | 631 | DEBUG Creating directory /var/tmp/builddmaster/accepted |
405 | 632 | 632 | ||
406 | === modified file 'lib/lp/soyuz/scripts/tests/test_processupload.py' | |||
407 | --- lib/lp/soyuz/scripts/tests/test_processupload.py 2010-07-20 12:06:36 +0000 | |||
408 | +++ lib/lp/soyuz/scripts/tests/test_processupload.py 2010-08-19 09:52:48 +0000 | |||
409 | @@ -91,11 +91,12 @@ | |||
410 | 91 | # the process-upload call terminated with ERROR and | 91 | # the process-upload call terminated with ERROR and |
411 | 92 | # proper log message | 92 | # proper log message |
412 | 93 | self.assertEqual(1, returncode) | 93 | self.assertEqual(1, returncode) |
418 | 94 | self.assertEqual([ | 94 | self.assert_( |
419 | 95 | ('INFO Creating lockfile: ' | 95 | 'INFO Creating lockfile: ' |
420 | 96 | '/var/lock/process-upload-insecure.lock'), | 96 | '/var/lock/process-upload-insecure.lock' in err.splitlines()) |
421 | 97 | 'DEBUG Lockfile /var/lock/process-upload-insecure.lock in use', | 97 | self.assert_( |
422 | 98 | ], err.splitlines()) | 98 | 'DEBUG Lockfile /var/lock/process-upload-insecure.lock in use' |
423 | 99 | in err.splitlines()) | ||
424 | 99 | 100 | ||
425 | 100 | # release the locally acquired lockfile | 101 | # release the locally acquired lockfile |
426 | 101 | locker.release() | 102 | locker.release() |
427 | 102 | 103 | ||
428 | === modified file 'lib/lp/testing/tests/test_standard_test_template.py' | |||
429 | --- lib/lp/testing/tests/test_standard_test_template.py 2010-07-17 21:13:21 +0000 | |||
430 | +++ lib/lp/testing/tests/test_standard_test_template.py 2010-08-19 09:52:48 +0000 | |||
431 | @@ -5,6 +5,8 @@ | |||
432 | 5 | 5 | ||
433 | 6 | __metaclass__ = type | 6 | __metaclass__ = type |
434 | 7 | 7 | ||
435 | 8 | import unittest | ||
436 | 9 | |||
437 | 8 | from canonical.testing import DatabaseFunctionalLayer | 10 | from canonical.testing import DatabaseFunctionalLayer |
438 | 9 | from lp.testing import TestCase | 11 | from lp.testing import TestCase |
439 | 10 | 12 | ||
440 | @@ -22,3 +24,7 @@ | |||
441 | 22 | 24 | ||
442 | 23 | # XXX: Assertions take expected value first, actual value second. | 25 | # XXX: Assertions take expected value first, actual value second. |
443 | 24 | self.assertEqual(4, 2 + 2) | 26 | self.assertEqual(4, 2 + 2) |
444 | 27 | |||
445 | 28 | |||
446 | 29 | def test_suite(): | ||
447 | 30 | return unittest.TestLoader().loadTestsFromName(__name__) | ||
448 | 25 | 31 | ||
449 | === modified file 'lib/lp/translations/doc/poexport-request.txt' | |||
450 | --- lib/lp/translations/doc/poexport-request.txt 2010-07-22 10:14:53 +0000 | |||
451 | +++ lib/lp/translations/doc/poexport-request.txt 2010-08-19 09:52:48 +0000 | |||
452 | @@ -269,6 +269,7 @@ | |||
453 | 269 | ... ) | 269 | ... ) |
454 | 270 | >>> (output, empty) = process.communicate() | 270 | >>> (output, empty) = process.communicate() |
455 | 271 | >>> print output | 271 | >>> print output |
456 | 272 | DEBUG ... | ||
457 | 272 | INFO Creating lockfile: /var/lock/launchpad-rosetta-export-queue.lock | 273 | INFO Creating lockfile: /var/lock/launchpad-rosetta-export-queue.lock |
458 | 273 | DEBUG Exporting objects for Happy Downloader, related to template | 274 | DEBUG Exporting objects for Happy Downloader, related to template |
459 | 274 | evolution-2.2 in Evolution trunk | 275 | evolution-2.2 in Evolution trunk |
looks good