Merge lp:~leonardr/launchpad/no-mutator-named-operations into lp:launchpad/db-devel

Proposed by Leonard Richardson
Status: Merged
Merge reported by: Leonard Richardson
Merged at revision: not available
Proposed branch: lp:~leonardr/launchpad/no-mutator-named-operations
Merge into: lp:launchpad/db-devel
Diff against target: 908 lines (+239/-199)
19 files modified
.bzrignore (+1/-1)
cronscripts/expire-archive-files.py (+3/-3)
lib/canonical/launchpad/doc/timeout.txt (+1/-1)
lib/canonical/launchpad/pagetests/basics/demo-and-lpnet.txt (+7/-6)
lib/canonical/launchpad/pagetests/webservice/multiversion.txt (+32/-0)
lib/canonical/launchpad/rest/configuration.py (+1/-0)
lib/canonical/launchpad/templates/launchpad-requestexpired.pt (+9/-20)
lib/canonical/launchpad/templates/oops.pt (+24/-0)
lib/canonical/launchpad/webapp/error.py (+3/-3)
lib/canonical/launchpad/webapp/tests/test_servers.py (+1/-1)
lib/lp/app/stories/basics/xx-beta-testers-redirection.txt (+7/-7)
lib/lp/app/templates/base-layout-macros.pt (+8/-10)
lib/lp/bugs/stories/webservice/xx-bug.txt (+9/-40)
lib/lp/registry/browser/productseries.py (+1/-1)
lib/lp/registry/browser/tests/productseries-views.txt (+5/-0)
lib/lp/registry/templates/productseries-codesummary.pt (+1/-1)
lib/lp/soyuz/scripts/expire_archive_files.py (+21/-15)
lib/lp/soyuz/scripts/tests/test_expire_archive_files.py (+103/-88)
versions.cfg (+2/-2)
To merge this branch: bzr merge lp:~leonardr/launchpad/no-mutator-named-operations
Reviewer Review Type Date Requested Status
Guilherme Salgado (community) code Approve
Review via email: mp+20777@code.launchpad.net

Description of the change

This branch integrates the latest versions of lazr.restful and launchpadlib into Launchpad. launchpadlib didn't need any changes; it's just a more useful version of the software. To integrate lazr.restful I had to make some changes.

Specifically, this branch introduces the first real difference between the 'beta' and '1.0' versions of the web service. As of '1.0', named operations that duplicate the functionality of fields (such as IBugTask.transitionToStatus) are not published on the web service. In 'beta', those operations are still available. This is controlled by the configuration variable last_version_with_mutator_named_operations.

I changed the xx-bug.txt test to stop testing for the presence of the named operation, even though that test is still using 'beta' and so the named operation is still available. I plan to do a test soon that changes the default version used by the tests to 'devel', and I'm going to have to search-and-replace a whole lot of URLs in tests to make the tests work again. I don't want to also have to make a more complex change to the web service tests.

I made a minor fix to the .bzrignore file so that it would ignore all versions of the generated WADL. (There used to be only one; I recently changed the Makefile to generate many such files, but I didn't think to change the .bzrignore then.)

Finally, I changed test_servers.py to import WebServiceTestCase and other helpful classes from lazr.restful.testing.webservice. In the old version of lazr.restful those classes were buried in lazr.restful's web service unit test module; in the new version, I moved them to a place more appropriate to import from.

To post a comment you must log in.
Revision history for this message
Guilherme Salgado (salgado) wrote :

This looks good, although the diff currently shows the changes from one of my branches that recently landed on devel. As discussed on IRC, this is because you had branched off of db-devel and then merged devel after I landed my changes.

Also, one thing that concerns me is that we're losing test coverage for things that don't exist in the latest version of the api (e.g. transitionToStatus). Is the plan really to test just whatever is supported by the latest version or am I missing something?

review: Approve (code)
Revision history for this message
Leonard Richardson (leonardr) wrote :

This is a little different from other version-specific changes because it's one change that affects _every_ mutator named operation, not a bunch of decisions made on a case-by-case basis. So I think it's sufficient to show that, in general, named operations are available in beta but not in 1.0, which is what the transitionToImportance test does.

In general, the plan is to pick a few applications written against beta, and make sure they continue to work against beta as we change 1.0, rather than write a test for every change. But even by the standards of "write a test for every change", I think in this case a single representative test is good enough.

9076. By Leonard Richardson

Merge with trunk.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.bzrignore'
--- .bzrignore 2010-03-09 02:42:40 +0000
+++ .bzrignore 2010-03-11 21:49:26 +0000
@@ -32,7 +32,7 @@
32database/sampledata/lintdata-dev.sql32database/sampledata/lintdata-dev.sql
33lib/canonical/launchpad/apidoc/index.html33lib/canonical/launchpad/apidoc/index.html
34xxx-report.*34xxx-report.*
35lib/canonical/launchpad/apidoc/wadl-development.xml35lib/canonical/launchpad/apidoc/wadl-development-*.xml
36lib/canonical/launchpad/apidoc/wadl-test-playground.xml36lib/canonical/launchpad/apidoc/wadl-test-playground.xml
37lib/canonical/launchpad/icing/build/*37lib/canonical/launchpad/icing/build/*
38lib/canonical/launchpad/icing/combo.css38lib/canonical/launchpad/icing/combo.css
3939
=== renamed file 'cronscripts/expire-ppa-files.py' => 'cronscripts/expire-archive-files.py'
--- cronscripts/expire-ppa-files.py 2010-01-20 10:32:32 +0000
+++ cronscripts/expire-archive-files.py 2010-03-11 21:49:26 +0000
@@ -12,11 +12,11 @@
12import _pythonpath12import _pythonpath
1313
14from canonical.config import config14from canonical.config import config
15from lp.soyuz.scripts.expire_ppa_binaries import PPABinaryExpirer15from lp.soyuz.scripts.expire_archive_files import ArchiveExpirer
1616
1717
18if __name__ == '__main__':18if __name__ == '__main__':
19 script = PPABinaryExpirer(19 script = ArchiveExpirer(
20 'expire-ppa-files', dbuser=config.binaryfile_expire.dbuser)20 'expire-archive-files', dbuser=config.binaryfile_expire.dbuser)
21 script.lock_and_run()21 script.lock_and_run()
2222
2323
=== modified file 'lib/canonical/launchpad/doc/timeout.txt'
--- lib/canonical/launchpad/doc/timeout.txt 2008-05-17 02:36:00 +0000
+++ lib/canonical/launchpad/doc/timeout.txt 2010-03-11 21:49:26 +0000
@@ -12,7 +12,7 @@
12 >>> from canonical.lazr.timeout import get_default_timeout_function12 >>> from canonical.lazr.timeout import get_default_timeout_function
13 >>> from canonical.launchpad.webapp.servers import (13 >>> from canonical.launchpad.webapp.servers import (
14 ... set_launchpad_default_timeout)14 ... set_launchpad_default_timeout)
15 >>> old_func = get_default_timeout_function()15 >>> old_func = get_default_timeout_function()
1616
17 >>> from zope.app.appsetup import ProcessStarting17 >>> from zope.app.appsetup import ProcessStarting
1818
1919
=== modified file 'lib/canonical/launchpad/pagetests/basics/demo-and-lpnet.txt'
--- lib/canonical/launchpad/pagetests/basics/demo-and-lpnet.txt 2010-02-09 17:25:13 +0000
+++ lib/canonical/launchpad/pagetests/basics/demo-and-lpnet.txt 2010-03-11 21:49:26 +0000
@@ -103,16 +103,18 @@
103 ... 'a', onclick="setBetaRedirect(false)"))103 ... 'a', onclick="setBetaRedirect(false)"))
104 Disable edge redirect.104 Disable edge redirect.
105105
106The disable-redirect link will not appear in the site_message when106The disable-redirect link will also appear in the site_message when browsed by
107browsed by non-beta users.107non-beta/anonymous users. This is to reduce the annoyance when users are
108logged into launchpad.net but haven't noticed yet that they need to log into
109edge as well (https://launchpad.net/bugs/160191).
108110
109 >>> browser.open('http://launchpad.dev/ubuntu')111 >>> browser.open('http://launchpad.dev/ubuntu')
110 >>> print extract_text(find_tags_by_class(112 >>> print extract_text(find_tags_by_class(
111 ... browser.contents, 'sitemessage')[0])113 ... browser.contents, 'sitemessage')[0])
112 This is a beta site.114 This is a beta site. Disable edge redirect.
113115
114Similarly, once the redirection has been inhibited, the link changes to116Once the redirection has been inhibited, the link changes to enable
115enable redirects..117redirects.
116118
117 # Workaround bug in mechanize where you cannot use the Cookie119 # Workaround bug in mechanize where you cannot use the Cookie
118 # header with the CookieJar120 # header with the CookieJar
@@ -135,7 +137,6 @@
135 ... 'a', onclick="setBetaRedirect(true)"))137 ... 'a', onclick="setBetaRedirect(true)"))
136 Enable edge redirect.138 Enable edge redirect.
137139
138
139 # Remove the specific site-message config data before continuing.140 # Remove the specific site-message config data before continuing.
140 >>> dummy = config.pop('edge_config_data')141 >>> dummy = config.pop('edge_config_data')
141142
142143
=== added file 'lib/canonical/launchpad/pagetests/webservice/multiversion.txt'
--- lib/canonical/launchpad/pagetests/webservice/multiversion.txt 1970-01-01 00:00:00 +0000
+++ lib/canonical/launchpad/pagetests/webservice/multiversion.txt 2010-03-11 21:49:26 +0000
@@ -0,0 +1,32 @@
1Differences between versions
2----------------------------
3
4In the 'beta' version of the web service, mutator methods like
5IBugTask.transitionToStatus are published as named operations. In
6subsequent versions, those named operations are not published.
7
8 >>> def get_bugtask_path(version):
9 ... bug_one = webservice.get("/bugs/1", api_version=version).jsonBody()
10 ... bug_one_bugtasks_url = bug_one['bug_tasks_collection_link']
11 ... bug_one_bugtasks = sorted(webservice.get(
12 ... bug_one_bugtasks_url).jsonBody()['entries'])
13 ... bugtask_path = bug_one_bugtasks[0]['self_link']
14 ... return bugtask_path
15
16Here's the 'beta' version, where the named operation works.
17
18 >>> url = get_bugtask_path('beta')
19 >>> print webservice.named_post(
20 ... url, 'transitionToImportance', importance='Low',
21 ... api_version='beta')
22 HTTP/1.1 200 Ok
23 ...
24
25Now let's try the same thing in the '1.0' version, where it fails.
26
27 >>> url = get_bugtask_path('1.0')
28 >>> print webservice.named_post(
29 ... url, 'transitionToImportance', importance='Low',
30 ... api_version='devel')
31 HTTP/1.1 405 Method Not Allowed
32 ...
033
=== modified file 'lib/canonical/launchpad/rest/configuration.py'
--- lib/canonical/launchpad/rest/configuration.py 2010-02-15 02:09:32 +0000
+++ lib/canonical/launchpad/rest/configuration.py 2010-03-11 21:49:26 +0000
@@ -24,6 +24,7 @@
2424
25 path_override = "api"25 path_override = "api"
26 active_versions = ["beta", "1.0", "devel"]26 active_versions = ["beta", "1.0", "devel"]
27 last_version_with_mutator_named_operations = "beta"
27 view_permission = "launchpad.View"28 view_permission = "launchpad.View"
28 set_hop_by_hop_headers = True29 set_hop_by_hop_headers = True
2930
3031
=== modified file 'lib/canonical/launchpad/templates/launchpad-requestexpired.pt'
--- lib/canonical/launchpad/templates/launchpad-requestexpired.pt 2009-07-28 17:19:42 +0000
+++ lib/canonical/launchpad/templates/launchpad-requestexpired.pt 2010-03-11 21:49:26 +0000
@@ -9,27 +9,16 @@
9 <body>9 <body>
10 <div class="top-portlet" metal:fill-slot="main">10 <div class="top-portlet" metal:fill-slot="main">
11 <h1 class="exception">Timeout error</h1>11 <h1 class="exception">Timeout error</h1>
12 <div12 <div tal:condition="is_edge"
13 id="redirect_notice" style="display:none" class="informational message">13 id="redirect_notice" class="informational message">
14 <p>Our edge server has a lower timeout threshold than launchpad.net,14 <p>Our edge server has a lower timeout threshold than launchpad.net,
15 so we can catch those before they hit a wider audience.15 so we can catch those before they hit a wider audience.
16 As a member of the Launchpad Beta Testers team, you're more16 If this is blocking your work and you are a member of the Launchpad
17 likely to experience them. If this is blocking your work, you17 Beta Testers team, you can disable automatic redirection
18 can disable redirection.</p>18 to edge in order to use launchpad.net.</p>
19 <p><button onclick="setBetaRedirect(false)">Disable redirection19 <p><button onclick="setBetaRedirect(false)">Disable redirection
20 for 2 hours</button></p>20 for 2 hours</button></p>
21 </div>21 </div>
22 <script type="text/javascript">
23 var edge_cookie = document.cookie.match('edge');
24 var edge_host = document.location.hostname.match('edge');
25
26 // Logic has been inverted in the next line to avoid breaking
27 // XHTML compliance of the template due to ampersand usage.
28 if (!(edge_cookie || edge_host)) {
29 redirect_notice_div = document.getElementById('redirect_notice');
30 redirect_notice_div.style.display = "block";
31 };
32 </script>
33 <p>22 <p>
34 Sorry, something just went wrong in Launchpad.23 Sorry, something just went wrong in Launchpad.
35 </p>24 </p>
3625
=== modified file 'lib/canonical/launchpad/templates/oops.pt'
--- lib/canonical/launchpad/templates/oops.pt 2010-01-13 17:58:30 +0000
+++ lib/canonical/launchpad/templates/oops.pt 2010-03-11 21:49:26 +0000
@@ -9,6 +9,9 @@
9 <style type="text/css" media="screen, print">9 <style type="text/css" media="screen, print">
10 @import url(/+icing/rev5/combo.css);10 @import url(/+icing/rev5/combo.css);
11 </style>11 </style>
12 <script type="text/javascript"
13 tal:content="string:var cookie_scope = '${request/lp:cookie_scope}';"></script>
14 <script type="text/javascript" src="/+icing/rev5/build/lp/lp.js" />
12 </head>15 </head>
13 <body>16 <body>
14 <div class="yui-d0">17 <div class="yui-d0">
@@ -27,6 +30,27 @@
27 (Error <abbr>ID</abbr>:30 (Error <abbr>ID</abbr>:
28 <tal:oops replace="structure view/oops_id_text" />)31 <tal:oops replace="structure view/oops_id_text" />)
29 </p>32 </p>
33
34 <div id="redirect_notice" style="display:none"
35 class="informational message">
36 <p>This server runs pre-release code, so it's possible this problem
37 doesn't affect launchpad.net. If you're a member of the Launchpad
38 Beta Testers team, you can disable redirection in order to use
39 launchpad.net.</p>
40 <p><button onclick="setBetaRedirect(false)">Disable redirection
41 for 2 hours</button></p>
42 </div>
43 <tal:comment condition="nothing">
44 Can't use the 'is_edge' global because we don't use our page
45 macros here.
46 </tal:comment>
47 <script type="text/javascript">
48 if (document.location.hostname.match('edge.')) {
49 redirect_notice_div = document.getElementById('redirect_notice');
50 redirect_notice_div.style.display = "block";
51 };
52 </script>
53
30 <tal:traceback replace="structure view/maybeShowTraceback" />54 <tal:traceback replace="structure view/maybeShowTraceback" />
3155
32 <div class="related">56 <div class="related">
3357
=== modified file 'lib/canonical/launchpad/webapp/error.py'
--- lib/canonical/launchpad/webapp/error.py 2009-12-23 16:17:12 +0000
+++ lib/canonical/launchpad/webapp/error.py 2010-03-11 21:49:26 +0000
@@ -26,12 +26,13 @@
26from canonical.cachedproperty import cachedproperty26from canonical.cachedproperty import cachedproperty
27from canonical.config import config27from canonical.config import config
28import canonical.launchpad.layers28import canonical.launchpad.layers
29from canonical.launchpad.webapp.publisher import LaunchpadView
29from canonical.launchpad.webapp.adapter import (30from canonical.launchpad.webapp.adapter import (
30 clear_request_started, set_request_started)31 clear_request_started, set_request_started)
31from canonical.launchpad.webapp.interfaces import ILaunchBag32from canonical.launchpad.webapp.interfaces import ILaunchBag
3233
3334
34class SystemErrorView:35class SystemErrorView(LaunchpadView):
35 """Helper class for views on exceptions.36 """Helper class for views on exceptions.
3637
37 Also, sets a 500 response code.38 Also, sets a 500 response code.
@@ -64,8 +65,7 @@
64 safe_to_show_in_restricted_mode = False65 safe_to_show_in_restricted_mode = False
6566
66 def __init__(self, context, request):67 def __init__(self, context, request):
67 self.context = context68 super(SystemErrorView, self).__init__(context, request)
68 self.request = request
69 self.request.response.removeAllNotifications()69 self.request.response.removeAllNotifications()
70 if self.response_code is not None:70 if self.response_code is not None:
71 self.request.response.setStatus(self.response_code)71 self.request.response.setStatus(self.response_code)
7272
=== modified file 'lib/canonical/launchpad/webapp/tests/test_servers.py'
--- lib/canonical/launchpad/webapp/tests/test_servers.py 2010-02-24 14:45:33 +0000
+++ lib/canonical/launchpad/webapp/tests/test_servers.py 2010-03-11 21:49:26 +0000
@@ -14,7 +14,7 @@
14from lazr.restful.interfaces import (14from lazr.restful.interfaces import (
15 IServiceRootResource, IWebServiceConfiguration)15 IServiceRootResource, IWebServiceConfiguration)
16from lazr.restful.simple import RootResource16from lazr.restful.simple import RootResource
17from lazr.restful.tests.test_webservice import (17from lazr.restful.testing.webservice import (
18 IGenericCollection, IGenericEntry, WebServiceTestCase)18 IGenericCollection, IGenericEntry, WebServiceTestCase)
1919
20from lp.testing import TestCase20from lp.testing import TestCase
2121
=== modified file 'lib/lp/app/stories/basics/xx-beta-testers-redirection.txt'
--- lib/lp/app/stories/basics/xx-beta-testers-redirection.txt 2010-02-09 17:25:13 +0000
+++ lib/lp/app/stories/basics/xx-beta-testers-redirection.txt 2010-03-11 21:49:26 +0000
@@ -216,11 +216,12 @@
216216
217 >>> logout()217 >>> logout()
218218
219Decrease the timeout values for launchpad.dev219Decrease the timeout values for launchpad.dev and pretend we're on the edge
220server.
220221
221 >>> beta_data = """222 >>> beta_data = """
222 ... [launchpad]223 ... [launchpad]
223 ... beta_testers_redirection_host = edge.launchpad.dev224 ... is_edge: True
224 ... [database]225 ... [database]
225 ... db_statement_timeout: 1226 ... db_statement_timeout: 1
226 ... soft_request_timeout: 2227 ... soft_request_timeout: 2
@@ -240,15 +241,14 @@
240 <title>Error: Timeout</title>241 <title>Error: Timeout</title>
241 ...242 ...
242 <h1 class="exception">Timeout error</h1>243 <h1 class="exception">Timeout error</h1>
243 <div id="redirect_notice" style="display:none" class="informational message">244 ...
244 <p>Our edge server has a lower timeout threshold than launchpad.net,245 <p>Our edge server has a lower timeout threshold than launchpad.net,
245 so we can catch those before they hit a wider audience.246 so we can catch those before they hit a wider audience.
246 As a member of the Launchpad Beta Testers team, you're more247 If this is blocking your work and you are a member of the Launchpad
247 likely to experience them. If this is blocking your work, you248 Beta Testers team, you can disable automatic redirection
248 can disable redirection.</p>249 to edge in order to use launchpad.net.</p>
249 <p><button onclick="setBetaRedirect(false)">Disable redirection250 <p><button onclick="setBetaRedirect(false)">Disable redirection
250 for 2 hours</button></p>251 for 2 hours</button></p>
251 </div>
252 ...252 ...
253253
254Restore the config to state it was in at the start of the test.254Restore the config to state it was in at the start of the test.
255255
=== modified file 'lib/lp/app/templates/base-layout-macros.pt'
--- lib/lp/app/templates/base-layout-macros.pt 2010-03-05 02:57:25 +0000
+++ lib/lp/app/templates/base-layout-macros.pt 2010-03-11 21:49:26 +0000
@@ -379,16 +379,14 @@
379 This site is running pre-release code.379 This site is running pre-release code.
380 </tal:site_message>380 </tal:site_message>
381 <tal:edge_only condition="is_edge">381 <tal:edge_only condition="is_edge">
382 <tal:beta_user condition="view/macro:isbetauser">382 <a href="#" class="js-action" onclick="setBetaRedirect(false)"
383 <a href="#" class="js-action" onclick="setBetaRedirect(false)"383 tal:condition="not:view/isRedirectInhibited">
384 tal:condition="not:view/isRedirectInhibited">384 Disable edge redirect.
385 Disable edge redirect.385 </a>
386 </a>386 <a href="#" class="js-action" onclick="setBetaRedirect(true)"
387 <a href="#" class="js-action" onclick="setBetaRedirect(true)"387 tal:condition="view/isRedirectInhibited">
388 tal:condition="view/isRedirectInhibited">388 Enable edge redirect.
389 Enable edge redirect.389 </a>
390 </a>
391 </tal:beta_user>
392 </tal:edge_only>390 </tal:edge_only>
393 </div>391 </div>
394</metal:site-message>392</metal:site-message>
395393
=== modified file 'lib/lp/bugs/stories/webservice/xx-bug.txt'
--- lib/lp/bugs/stories/webservice/xx-bug.txt 2010-03-10 14:14:38 +0000
+++ lib/lp/bugs/stories/webservice/xx-bug.txt 2010-03-11 21:49:26 +0000
@@ -357,7 +357,7 @@
357 http://.../~cprov357 http://.../~cprov
358358
359359
360The task's importance can be modified directly...360The task's importance can be modified directly.
361361
362 >>> body = webservice.get(bugtask_path).jsonBody()362 >>> body = webservice.get(bugtask_path).jsonBody()
363 >>> body['importance']363 >>> body['importance']
@@ -371,20 +371,6 @@
371 >>> body['importance']371 >>> body['importance']
372 u'High'372 u'High'
373373
374...or through a named operation.
375
376 >>> print webservice.named_post(
377 ... bugtask_path, 'transitionToImportance', importance='Low')
378 HTTP/1.1 200 Ok
379 ...
380 Content-Type: application/json
381 ...
382 <BLANKLINE>
383 null
384 >>> body = webservice.get(bugtask_path).jsonBody()
385 >>> body['importance']
386 u'Low'
387
388Only bug supervisors or people who can otherwise edit the bugtask's374Only bug supervisors or people who can otherwise edit the bugtask's
389pillar are authorised to edit the importance.375pillar are authorised to edit the importance.
390376
@@ -394,10 +380,9 @@
394380
395 >>> body = webservice.get(bugtask_path).jsonBody()381 >>> body = webservice.get(bugtask_path).jsonBody()
396 >>> body['importance']382 >>> body['importance']
397 u'Low'383 u'High'
398384
399The task's status is another aspect of the task that can be modified385The task's status can also be modified directly.
400either directly or through a named operation.
401386
402 >>> print webservice.get(bugtask_path).jsonBody()['status']387 >>> print webservice.get(bugtask_path).jsonBody()['status']
403 Confirmed388 Confirmed
@@ -409,21 +394,14 @@
409 >>> print webservice.get(bugtask_path).jsonBody()['status']394 >>> print webservice.get(bugtask_path).jsonBody()['status']
410 Fix Committed395 Fix Committed
411396
412 >>> print webservice.named_post(
413 ... bugtask_path, 'transitionToStatus', status='New')
414 HTTP/1.1 200 Ok...
415
416 >>> print webservice.get(bugtask_path).jsonBody()['status']
417 New
418
419If an error occurs during a request that sets both 'status' and397If an error occurs during a request that sets both 'status' and
420'importance', neither one will be set.398'importance', neither one will be set.
421399
422 >>> task = webservice.get(bugtask_path).jsonBody()400 >>> task = webservice.get(bugtask_path).jsonBody()
423 >>> print task['status']401 >>> print task['status']
424 New402 Fix Committed
425 >>> print task['importance']403 >>> print task['importance']
426 Low404 High
427405
428 >>> patch = {u'importance': 'High', u'status': u'No Such Status'}406 >>> patch = {u'importance': 'High', u'status': u'No Such Status'}
429 >>> print webservice.patch(bugtask_path, 'application/json', dumps(patch))407 >>> print webservice.patch(bugtask_path, 'application/json', dumps(patch))
@@ -431,12 +409,11 @@
431409
432 >>> task = webservice.get(bugtask_path).jsonBody()410 >>> task = webservice.get(bugtask_path).jsonBody()
433 >>> print task['status']411 >>> print task['status']
434 New412 Fix Committed
435 >>> print task['importance']413 >>> print task['importance']
436 Low414 High
437415
438Like the importance, the milestone can be set either directly or via a416The milestone can only be set by appropriately privileged users.
439named operation, and only by appropriately privileged users.
440417
441 >>> print webservice.get(bugtask_path).jsonBody()['milestone_link']418 >>> print webservice.get(bugtask_path).jsonBody()['milestone_link']
442 None419 None
@@ -449,20 +426,12 @@
449 >>> print webservice.get(bugtask_path).jsonBody()['milestone_link']426 >>> print webservice.get(bugtask_path).jsonBody()['milestone_link']
450 http://.../debian/+milestone/3.1427 http://.../debian/+milestone/3.1
451428
452 >>> print webservice.named_post(
453 ... bugtask_path, 'transitionToMilestone',
454 ... milestone=webservice.getAbsoluteUrl('/debian/+milestone/3.1-rc1'))
455 HTTP/1.1 200 Ok...
456
457 >>> print webservice.get(bugtask_path).jsonBody()['milestone_link']
458 http://.../debian/+milestone/3.1-rc1
459
460 >>> print user_webservice.patch(429 >>> print user_webservice.patch(
461 ... bugtask_path, 'application/json', dumps(patch))430 ... bugtask_path, 'application/json', dumps(patch))
462 HTTP/1.1 401 Unauthorized...431 HTTP/1.1 401 Unauthorized...
463432
464 >>> print webservice.get(bugtask_path).jsonBody()['milestone_link']433 >>> print webservice.get(bugtask_path).jsonBody()['milestone_link']
465 http://.../debian/+milestone/3.1-rc1434 http://.../debian/+milestone/3.1
466435
467We can change the task's target. Here we change the task's target from436We can change the task's target. Here we change the task's target from
468the mozilla-firefox package to alsa-utils.437the mozilla-firefox package to alsa-utils.
469438
=== modified file 'lib/lp/registry/browser/productseries.py'
--- lib/lp/registry/browser/productseries.py 2010-02-08 20:11:17 +0000
+++ lib/lp/registry/browser/productseries.py 2010-03-11 21:49:26 +0000
@@ -309,7 +309,7 @@
309 @property309 @property
310 def request_import_link(self):310 def request_import_link(self):
311 """A link to the page for requesting a new code import."""311 """A link to the page for requesting a new code import."""
312 return canonical_url(getUtility(ICodeImportSet), view_name='+new')312 return canonical_url(self.context.product, view_name='+new-import')
313313
314 @property314 @property
315 def user_branch_visible(self):315 def user_branch_visible(self):
316316
=== modified file 'lib/lp/registry/browser/tests/productseries-views.txt'
--- lib/lp/registry/browser/tests/productseries-views.txt 2010-02-09 05:13:05 +0000
+++ lib/lp/registry/browser/tests/productseries-views.txt 2010-03-11 21:49:26 +0000
@@ -107,6 +107,11 @@
107 >>> print view.latest_release_with_download_files.version107 >>> print view.latest_release_with_download_files.version
108 0.9.2108 0.9.2
109109
110The view also provides a link to register a new code import.
111
112 >>> print view.request_import_link
113 http://launchpad.dev/firefox/+new-import
114
110115
111Edit ProductSeries116Edit ProductSeries
112------------------117------------------
113118
=== modified file 'lib/lp/registry/templates/productseries-codesummary.pt'
--- lib/lp/registry/templates/productseries-codesummary.pt 2009-11-13 20:14:41 +0000
+++ lib/lp/registry/templates/productseries-codesummary.pt 2010-03-11 21:49:26 +0000
@@ -54,7 +54,7 @@
54 </li>54 </li>
5555
56 <li>56 <li>
57 If the code is in git, CVS or Subversion you can57 If the code is in Git, Mercurial, CVS or Subversion you can
58 <a tal:attributes="href view/request_import_link">request that the branch be imported to Bazaar</a>.58 <a tal:attributes="href view/request_import_link">request that the branch be imported to Bazaar</a>.
59 </li>59 </li>
60 </ul>60 </ul>
6161
=== renamed file 'lib/lp/soyuz/scripts/expire_ppa_binaries.py' => 'lib/lp/soyuz/scripts/expire_archive_files.py'
--- lib/lp/soyuz/scripts/expire_ppa_binaries.py 2010-01-31 19:36:27 +0000
+++ lib/lp/soyuz/scripts/expire_archive_files.py 2010-03-11 21:49:26 +0000
@@ -34,7 +34,7 @@
34""".split()34""".split()
3535
3636
37class PPABinaryExpirer(LaunchpadCronScript):37class ArchiveExpirer(LaunchpadCronScript):
38 """Helper class for expiring old PPA binaries.38 """Helper class for expiring old PPA binaries.
3939
40 Any PPA binary older than 30 days that is superseded or deleted40 Any PPA binary older than 30 days that is superseded or deleted
@@ -60,6 +60,7 @@
60 from lp.soyuz.interfaces.archive import ArchivePurpose60 from lp.soyuz.interfaces.archive import ArchivePurpose
6161
62 stay_of_execution = '%d days' % num_days62 stay_of_execution = '%d days' % num_days
63 archive_types = (ArchivePurpose.PPA, ArchivePurpose.PARTNER)
6364
64 # The subquery here has to repeat the checks for privacy and65 # The subquery here has to repeat the checks for privacy and
65 # blacklisting on *other* publications that are also done in66 # blacklisting on *other* publications that are also done in
@@ -79,7 +80,7 @@
79 AND spph.dateremoved < (80 AND spph.dateremoved < (
80 CURRENT_TIMESTAMP AT TIME ZONE 'UTC' - interval %s)81 CURRENT_TIMESTAMP AT TIME ZONE 'UTC' - interval %s)
81 AND spph.archive = archive.id82 AND spph.archive = archive.id
82 AND archive.purpose = %s83 AND archive.purpose IN %s
83 AND lfa.expires IS NULL84 AND lfa.expires IS NULL
84 EXCEPT85 EXCEPT
85 SELECT sprf.libraryfile86 SELECT sprf.libraryfile
@@ -95,15 +96,15 @@
95 AND spph.archive = a.id96 AND spph.archive = a.id
96 AND p.id = a.owner97 AND p.id = a.owner
97 AND (98 AND (
98 p.name IN %s99 (p.name IN %s AND a.purpose = %s)
99 OR a.private IS TRUE100 OR a.private IS TRUE
100 OR a.purpose != %s101 OR a.purpose NOT IN %s
101 OR dateremoved >102 OR dateremoved >
102 CURRENT_TIMESTAMP AT TIME ZONE 'UTC' - interval %s103 CURRENT_TIMESTAMP AT TIME ZONE 'UTC' - interval %s
103 OR dateremoved IS NULL);104 OR dateremoved IS NULL);
104 """ % sqlvalues(105 """ % sqlvalues(
105 stay_of_execution, ArchivePurpose.PPA, self.blacklist,106 stay_of_execution, archive_types, self.blacklist,
106 ArchivePurpose.PPA, stay_of_execution))107 ArchivePurpose.PPA, archive_types, stay_of_execution))
107108
108 lfa_ids = results.get_all()109 lfa_ids = results.get_all()
109 return lfa_ids110 return lfa_ids
@@ -114,6 +115,7 @@
114 from lp.soyuz.interfaces.archive import ArchivePurpose115 from lp.soyuz.interfaces.archive import ArchivePurpose
115116
116 stay_of_execution = '%d days' % num_days117 stay_of_execution = '%d days' % num_days
118 archive_types = (ArchivePurpose.PPA, ArchivePurpose.PARTNER)
117119
118 # The subquery here has to repeat the checks for privacy and120 # The subquery here has to repeat the checks for privacy and
119 # blacklisting on *other* publications that are also done in121 # blacklisting on *other* publications that are also done in
@@ -131,9 +133,10 @@
131 AND bpr.id = bpf.binarypackagerelease133 AND bpr.id = bpf.binarypackagerelease
132 AND bpph.binarypackagerelease = bpr.id134 AND bpph.binarypackagerelease = bpr.id
133 AND bpph.dateremoved < (135 AND bpph.dateremoved < (
134 CURRENT_TIMESTAMP AT TIME ZONE 'UTC' - interval %s)136 CURRENT_TIMESTAMP AT TIME ZONE 'UTC' -
137 interval %(stay_of_execution)s)
135 AND bpph.archive = archive.id138 AND bpph.archive = archive.id
136 AND archive.purpose = %s139 AND archive.purpose IN %(archive_types)s
137 AND lfa.expires IS NULL140 AND lfa.expires IS NULL
138 EXCEPT141 EXCEPT
139 SELECT bpf.libraryfile142 SELECT bpf.libraryfile
@@ -149,15 +152,18 @@
149 AND bpph.archive = a.id152 AND bpph.archive = a.id
150 AND p.id = a.owner153 AND p.id = a.owner
151 AND (154 AND (
152 p.name IN %s155 (p.name IN %(blacklist)s AND a.purpose = %(ppa)s)
153 OR a.private IS TRUE156 OR a.private IS TRUE
154 OR a.purpose != %s157 OR a.purpose NOT IN %(archive_types)s
155 OR dateremoved >158 OR dateremoved > (
156 CURRENT_TIMESTAMP AT TIME ZONE 'UTC' - interval %s159 CURRENT_TIMESTAMP AT TIME ZONE 'UTC' -
157 OR dateremoved IS NULL);160 interval %(stay_of_execution)s)
161 OR dateremoved IS NULL)
158 """ % sqlvalues(162 """ % sqlvalues(
159 stay_of_execution, ArchivePurpose.PPA, self.blacklist,163 stay_of_execution=stay_of_execution,
160 ArchivePurpose.PPA, stay_of_execution))164 archive_types=archive_types,
165 blacklist=self.blacklist,
166 ppa=ArchivePurpose.PPA))
161167
162 lfa_ids = results.get_all()168 lfa_ids = results.get_all()
163 return lfa_ids169 return lfa_ids
164170
=== renamed file 'lib/lp/soyuz/scripts/tests/test_expire_ppa_bins.py' => 'lib/lp/soyuz/scripts/tests/test_expire_archive_files.py'
--- lib/lp/soyuz/scripts/tests/test_expire_ppa_bins.py 2010-02-27 20:20:03 +0000
+++ lib/lp/soyuz/scripts/tests/test_expire_archive_files.py 2010-03-11 21:49:26 +0000
@@ -1,12 +1,10 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Test the expire-ppa-binaries.py script. """4"""Test the expire-archive-files.py script. """
55
6from datetime import datetime, timedelta
6import pytz7import pytz
7
8from datetime import datetime, timedelta
9
10import unittest8import unittest
119
12from zope.component import getUtility10from zope.component import getUtility
@@ -15,35 +13,20 @@
15from canonical.launchpad.scripts import QuietFakeLogger13from canonical.launchpad.scripts import QuietFakeLogger
16from canonical.testing.layers import LaunchpadZopelessLayer14from canonical.testing.layers import LaunchpadZopelessLayer
17from lp.registry.interfaces.distribution import IDistributionSet15from lp.registry.interfaces.distribution import IDistributionSet
18from lp.registry.interfaces.person import IPersonSet16from lp.soyuz.interfaces.archive import ArchivePurpose
19from lp.soyuz.scripts.expire_ppa_binaries import PPABinaryExpirer17from lp.soyuz.scripts.expire_archive_files import ArchiveExpirer
20from lp.soyuz.tests.test_publishing import SoyuzTestPublisher18from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
21from lp.testing import TestCaseWithFactory19from lp.testing import TestCaseWithFactory
2220
2321
24class TestPPABinaryExpiry(TestCaseWithFactory):22class ArchiveExpiryTestBase(TestCaseWithFactory):
25 """Test the expire-ppa-binaries.py script."""23 """base class for the expire-archive-files.py script tests."""
26
27 layer = LaunchpadZopelessLayer24 layer = LaunchpadZopelessLayer
28 dbuser = config.binaryfile_expire.dbuser25 dbuser = config.binaryfile_expire.dbuser
2926
30 # We need to test several cases are handled properly:
31 # - publications with no "dateremoved" are not expired
32 # - publications with dateremoved <= 30 days ago are not expired
33 # - publications with dateremoved > 30 days ago are expired
34 # - publications with dateremoved > 30 days ago but refer to a
35 # binary published elsewhere with no dateremoved are not
36 # expired
37 # - publications with dateremoved > 30 days ago but refer to a
38 # binary published elsewhere with dateremoved <= 30 days ago
39 # are not expired
40 # - publications with dateremoved > 30 days ago but refer to a
41 # binary published elsewhere with dateremoved > 30 days ago
42 # are expired.
43
44 def setUp(self):27 def setUp(self):
45 """Set up some test publications."""28 """Set up some test publications."""
46 super(TestPPABinaryExpiry, self).setUp()29 super(ArchiveExpiryTestBase, self).setUp()
47 # Configure the test publisher.30 # Configure the test publisher.
48 self.layer.switchDbUser("launchpad")31 self.layer.switchDbUser("launchpad")
49 self.stp = SoyuzTestPublisher()32 self.stp = SoyuzTestPublisher()
@@ -54,16 +37,12 @@
54 self.under_threshold_date = self.now - timedelta(days=29)37 self.under_threshold_date = self.now - timedelta(days=29)
55 self.over_threshold_date = self.now - timedelta(days=31)38 self.over_threshold_date = self.now - timedelta(days=31)
5639
57 # Prepare two PPAs for the tests to use.
58 self.ppa = self.factory.makeArchive()
59 self.ppa2 = self.factory.makeArchive()
60
61 def getScript(self, test_args=None):40 def getScript(self, test_args=None):
62 """Return a PPABinaryExpirer instance."""41 """Return a ArchiveExpirer instance."""
63 if test_args is None:42 if test_args is None:
64 test_args = []43 test_args = []
65 test_args.extend(['--expire-after', '30'])44 test_args.extend(['--expire-after', '30'])
66 script = PPABinaryExpirer("test expirer", test_args=test_args)45 script = ArchiveExpirer("test expirer", test_args=test_args)
67 script.logger = QuietFakeLogger()46 script.logger = QuietFakeLogger()
68 script.txn = self.layer.txn47 script.txn = self.layer.txn
69 return script48 return script
@@ -75,6 +54,24 @@
75 self.layer.switchDbUser(self.dbuser)54 self.layer.switchDbUser(self.dbuser)
76 script.main()55 script.main()
7756
57 def _setUpExpirablePublications(self, archive=None):
58 """Helper to set up two publications that are both expirable."""
59 if archive is None:
60 archive = self.archive
61 pkg5 = self.stp.getPubSource(
62 sourcename="pkg5", architecturehintlist="i386", archive=archive,
63 dateremoved=self.over_threshold_date)
64 other_source = pkg5.copyTo(
65 pkg5.distroseries, pkg5.pocket, self.archive2)
66 other_source.dateremoved = self.over_threshold_date
67 [pub] = self.stp.getPubBinaries(
68 pub_source=pkg5, dateremoved=self.over_threshold_date,
69 archive=archive)
70 [other_binary] = pub.copyTo(
71 pub.distroarchseries.distroseries, pub.pocket, self.archive2)
72 other_binary.dateremoved = self.over_threshold_date
73 return pkg5, pub
74
78 def assertBinaryExpired(self, publication):75 def assertBinaryExpired(self, publication):
79 self.assertNotEqual(76 self.assertNotEqual(
80 publication.binarypackagerelease.files[0].libraryfile.expires,77 publication.binarypackagerelease.files[0].libraryfile.expires,
@@ -99,13 +96,19 @@
99 None,96 None,
100 "lfa.expires should be None, but it's not.")97 "lfa.expires should be None, but it's not.")
10198
99
100class ArchiveExpiryCommonTests(object):
101 """Common source/binary expiration test cases.
102
103 These will be shared irrespective of archive type (ppa/partner).
104 """
102 def testNoExpirationWithNoDateremoved(self):105 def testNoExpirationWithNoDateremoved(self):
103 """Test that no expiring happens if no dateremoved set."""106 """Test that no expiring happens if no dateremoved set."""
104 pkg1 = self.stp.getPubSource(107 pkg1 = self.stp.getPubSource(
105 sourcename="pkg1", architecturehintlist="i386", archive=self.ppa,108 sourcename="pkg1", architecturehintlist="i386",
106 dateremoved=None)109 archive=self.archive, dateremoved=None)
107 [pub] = self.stp.getPubBinaries(110 [pub] = self.stp.getPubBinaries(
108 pub_source=pkg1, dateremoved=None, archive=self.ppa)111 pub_source=pkg1, dateremoved=None, archive=self.archive)
109112
110 self.runScript()113 self.runScript()
111 self.assertSourceNotExpired(pkg1)114 self.assertSourceNotExpired(pkg1)
@@ -114,11 +117,11 @@
114 def testNoExpirationWithDateUnderThreshold(self):117 def testNoExpirationWithDateUnderThreshold(self):
115 """Test no expiring if dateremoved too recent."""118 """Test no expiring if dateremoved too recent."""
116 pkg2 = self.stp.getPubSource(119 pkg2 = self.stp.getPubSource(
117 sourcename="pkg2", architecturehintlist="i386", archive=self.ppa,120 sourcename="pkg2", architecturehintlist="i386",
118 dateremoved=self.under_threshold_date)121 archive=self.archive, dateremoved=self.under_threshold_date)
119 [pub] = self.stp.getPubBinaries(122 [pub] = self.stp.getPubBinaries(
120 pub_source=pkg2, dateremoved=self.under_threshold_date,123 pub_source=pkg2, dateremoved=self.under_threshold_date,
121 archive=self.ppa)124 archive=self.archive)
122125
123 self.runScript()126 self.runScript()
124 self.assertSourceNotExpired(pkg2)127 self.assertSourceNotExpired(pkg2)
@@ -127,11 +130,11 @@
127 def testExpirationWithDateOverThreshold(self):130 def testExpirationWithDateOverThreshold(self):
128 """Test expiring works if dateremoved old enough."""131 """Test expiring works if dateremoved old enough."""
129 pkg3 = self.stp.getPubSource(132 pkg3 = self.stp.getPubSource(
130 sourcename="pkg3", architecturehintlist="i386", archive=self.ppa,133 sourcename="pkg3", architecturehintlist="i386",
131 dateremoved=self.over_threshold_date)134 archive=self.archive, dateremoved=self.over_threshold_date)
132 [pub] = self.stp.getPubBinaries(135 [pub] = self.stp.getPubBinaries(
133 pub_source=pkg3, dateremoved=self.over_threshold_date,136 pub_source=pkg3, dateremoved=self.over_threshold_date,
134 archive=self.ppa)137 archive=self.archive)
135138
136 self.runScript()139 self.runScript()
137 self.assertSourceExpired(pkg3)140 self.assertSourceExpired(pkg3)
@@ -140,16 +143,16 @@
140 def testNoExpirationWithDateOverThresholdAndOtherValidPublication(self):143 def testNoExpirationWithDateOverThresholdAndOtherValidPublication(self):
141 """Test no expiry if dateremoved old enough but other publication."""144 """Test no expiry if dateremoved old enough but other publication."""
142 pkg4 = self.stp.getPubSource(145 pkg4 = self.stp.getPubSource(
143 sourcename="pkg4", architecturehintlist="i386", archive=self.ppa,146 sourcename="pkg4", architecturehintlist="i386",
144 dateremoved=self.over_threshold_date)147 archive=self.archive, dateremoved=self.over_threshold_date)
145 other_source = pkg4.copyTo(148 other_source = pkg4.copyTo(
146 pkg4.distroseries, pkg4.pocket, self.ppa2)149 pkg4.distroseries, pkg4.pocket, self.archive2)
147 other_source.dateremoved = None150 other_source.dateremoved = None
148 [pub] = self.stp.getPubBinaries(151 [pub] = self.stp.getPubBinaries(
149 pub_source=pkg4, dateremoved=self.over_threshold_date,152 pub_source=pkg4, dateremoved=self.over_threshold_date,
150 archive=self.ppa)153 archive=self.archive)
151 [other_binary] = pub.copyTo(154 [other_binary] = pub.copyTo(
152 pub.distroarchseries.distroseries, pub.pocket, self.ppa2)155 pub.distroarchseries.distroseries, pub.pocket, self.archive2)
153 other_binary.dateremoved = None156 other_binary.dateremoved = None
154157
155 self.runScript()158 self.runScript()
@@ -163,40 +166,22 @@
163 not over date threshold.166 not over date threshold.
164 """167 """
165 pkg5 = self.stp.getPubSource(168 pkg5 = self.stp.getPubSource(
166 sourcename="pkg5", architecturehintlist="i386", archive=self.ppa,169 sourcename="pkg5", architecturehintlist="i386",
167 dateremoved=self.over_threshold_date)170 archive=self.archive, dateremoved=self.over_threshold_date)
168 other_source = pkg5.copyTo(171 other_source = pkg5.copyTo(
169 pkg5.distroseries, pkg5.pocket, self.ppa2)172 pkg5.distroseries, pkg5.pocket, self.archive2)
170 other_source.dateremoved = self.under_threshold_date173 other_source.dateremoved = self.under_threshold_date
171 [pub] = self.stp.getPubBinaries(174 [pub] = self.stp.getPubBinaries(
172 pub_source=pkg5, dateremoved=self.over_threshold_date,175 pub_source=pkg5, dateremoved=self.over_threshold_date,
173 archive=self.ppa)176 archive=self.archive)
174 [other_binary] = pub.copyTo(177 [other_binary] = pub.copyTo(
175 pub.distroarchseries.distroseries, pub.pocket, self.ppa2)178 pub.distroarchseries.distroseries, pub.pocket, self.archive2)
176 other_binary.dateremoved = self.under_threshold_date179 other_binary.dateremoved = self.under_threshold_date
177180
178 self.runScript()181 self.runScript()
179 self.assertSourceNotExpired(pkg5)182 self.assertSourceNotExpired(pkg5)
180 self.assertBinaryNotExpired(pub)183 self.assertBinaryNotExpired(pub)
181184
182 def _setUpExpirablePublications(self, archive=None):
183 """Helper to set up two publications that are both expirable."""
184 if archive is None:
185 archive = self.ppa
186 pkg5 = self.stp.getPubSource(
187 sourcename="pkg5", architecturehintlist="i386", archive=archive,
188 dateremoved=self.over_threshold_date)
189 other_source = pkg5.copyTo(
190 pkg5.distroseries, pkg5.pocket, self.ppa2)
191 other_source.dateremoved = self.over_threshold_date
192 [pub] = self.stp.getPubBinaries(
193 pub_source=pkg5, dateremoved=self.over_threshold_date,
194 archive=archive)
195 [other_binary] = pub.copyTo(
196 pub.distroarchseries.distroseries, pub.pocket, self.ppa2)
197 other_binary.dateremoved = self.over_threshold_date
198 return pkg5, pub
199
200 def testNoExpirationWithDateOverThresholdAndOtherPubOverThreshold(self):185 def testNoExpirationWithDateOverThresholdAndOtherPubOverThreshold(self):
201 """Test expiring works.186 """Test expiring works.
202187
@@ -208,26 +193,6 @@
208 self.assertSourceExpired(source)193 self.assertSourceExpired(source)
209 self.assertBinaryExpired(binary)194 self.assertBinaryExpired(binary)
210195
211 def testBlacklistingWorks(self):
212 """Test that blacklisted PPAs are not expired."""
213 source, binary = self._setUpExpirablePublications(archive=self.ppa)
214 script = self.getScript()
215 script.blacklist = [self.ppa.owner.name, ]
216 self.layer.txn.commit()
217 self.layer.switchDbUser(self.dbuser)
218 script.main()
219 self.assertSourceNotExpired(source)
220 self.assertBinaryNotExpired(binary)
221
222 def testPrivatePPAsNotExpired(self):
223 """Test that private PPAs are not expired."""
224 self.ppa.private = True
225 self.ppa.buildd_secret = "foo"
226 source, binary = self._setUpExpirablePublications()
227 self.runScript()
228 self.assertSourceNotExpired(source)
229 self.assertBinaryNotExpired(binary)
230
231 def testDryRun(self):196 def testDryRun(self):
232 """Test that when dryrun is specified, nothing is expired."""197 """Test that when dryrun is specified, nothing is expired."""
233 source, binary = self._setUpExpirablePublications()198 source, binary = self._setUpExpirablePublications()
@@ -240,7 +205,7 @@
240 self.assertSourceNotExpired(source)205 self.assertSourceNotExpired(source)
241 self.assertBinaryNotExpired(binary)206 self.assertBinaryNotExpired(binary)
242207
243 def testDoesNotAffectNonPPA(self):208 def testDoesNotAffectPrimary(self):
244 """Test that expiry does not happen for non-PPA publications."""209 """Test that expiry does not happen for non-PPA publications."""
245 ubuntu_archive = getUtility(IDistributionSet)['ubuntu'].main_archive210 ubuntu_archive = getUtility(IDistributionSet)['ubuntu'].main_archive
246 source, binary = self._setUpExpirablePublications(ubuntu_archive)211 source, binary = self._setUpExpirablePublications(ubuntu_archive)
@@ -249,5 +214,55 @@
249 self.assertBinaryNotExpired(binary)214 self.assertBinaryNotExpired(binary)
250215
251216
217class TestPPAExpiry(ArchiveExpiryTestBase, ArchiveExpiryCommonTests):
218 """Test the expire-archive-files.py script.
219
220 Here we make use of the common test cases defined in the base class but
221 also add tests specific to PPAs (excluding particular PPAs from expiry
222 based on a "black list" or on the fact that PPA is private).
223 """
224
225 def setUp(self):
226 """Set up some test publications."""
227 super(TestPPAExpiry, self).setUp()
228 # Prepare two PPAs for the tests to use.
229 self.archive = self.factory.makeArchive()
230 self.archive2 = self.factory.makeArchive()
231
232 def testBlacklistingWorks(self):
233 """Test that blacklisted PPAs are not expired."""
234 source, binary = self._setUpExpirablePublications(
235 archive=self.archive)
236 script = self.getScript()
237 script.blacklist = [self.archive.owner.name, ]
238 self.layer.txn.commit()
239 self.layer.switchDbUser(self.dbuser)
240 script.main()
241 self.assertSourceNotExpired(source)
242 self.assertBinaryNotExpired(binary)
243
244 def testPrivatePPAsNotExpired(self):
245 """Test that private PPAs are not expired."""
246 self.archive.private = True
247 self.archive.buildd_secret = "foo"
248 source, binary = self._setUpExpirablePublications()
249 self.runScript()
250 self.assertSourceNotExpired(source)
251 self.assertBinaryNotExpired(binary)
252
253
254class TestPartnerExpiry(ArchiveExpiryTestBase, ArchiveExpiryCommonTests):
255 """Test the expire-archive-files.py script on partner archives."""
256
257 def setUp(self):
258 """Set up the partner archives under test."""
259 super(TestPartnerExpiry, self).setUp()
260 # Prepare two partner archives for the tests to use.
261 self.archive = self.factory.makeArchive(
262 purpose=ArchivePurpose.PARTNER)
263 self.archive2 = self.factory.makeArchive(
264 purpose=ArchivePurpose.PARTNER)
265
266
252def test_suite():267def test_suite():
253 return unittest.TestLoader().loadTestsFromName(__name__)268 return unittest.TestLoader().loadTestsFromName(__name__)
254269
=== modified file 'versions.cfg'
--- versions.cfg 2010-03-08 22:26:29 +0000
+++ versions.cfg 2010-03-11 21:49:26 +0000
@@ -21,14 +21,14 @@
21grokcore.component = 1.621grokcore.component = 1.6
22httplib2 = 0.6.022httplib2 = 0.6.0
23ipython = 0.9.123ipython = 0.9.1
24launchpadlib = 1.5.524launchpadlib = 1.5.6
25lazr.authentication = 0.1.125lazr.authentication = 0.1.1
26lazr.batchnavigator = 1.126lazr.batchnavigator = 1.1
27lazr.config = 1.1.327lazr.config = 1.1.3
28lazr.delegates = 1.1.028lazr.delegates = 1.1.0
29lazr.enum = 1.1.229lazr.enum = 1.1.2
30lazr.lifecycle = 1.130lazr.lifecycle = 1.1
31lazr.restful = 0.9.2131lazr.restful = 0.9.22
32lazr.restfulclient = 0.9.1132lazr.restfulclient = 0.9.11
33lazr.smtptest = 1.133lazr.smtptest = 1.1
34lazr.testing = 0.1.134lazr.testing = 0.1.1

Subscribers

People subscribed via source and target branches

to status/vote changes: