Merge lp:~stub/launchpad/librarian-layer into lp:launchpad

Proposed by Stuart Bishop
Status: Merged
Approved by: Stuart Bishop
Approved revision: no longer in the source branch.
Merged at revision: 12232
Proposed branch: lp:~stub/launchpad/librarian-layer
Merge into: lp:launchpad
Prerequisite: lp:~lifeless/launchpad/librarian
Diff against target: 1015 lines (+139/-136)
40 files modified
lib/canonical/config/fixture.py (+0/-1)
lib/canonical/config/tests/test_fixture.py (+3/-6)
lib/canonical/launchpad/doc/canonical-config.txt (+0/-8)
lib/canonical/launchpad/doc/librarian.txt (+25/-18)
lib/canonical/launchpad/doc/message.txt (+0/-2)
lib/canonical/launchpad/doc/old-testing.txt (+2/-1)
lib/canonical/launchpad/pagetests/webservice/xx-hostedfile.txt (+3/-3)
lib/canonical/launchpad/scripts/ftests/librarianformatter.txt (+6/-6)
lib/canonical/librarian/ftests/test_web.py (+9/-20)
lib/canonical/librarian/testing/server.py (+17/-3)
lib/canonical/librarian/testing/tests/test_server_fixture.py (+17/-6)
lib/canonical/testing/ftests/test_layers.py (+2/-2)
lib/canonical/testing/layers.py (+10/-7)
lib/lp/bugs/browser/tests/test_bugattachment_file_access.py (+5/-5)
lib/lp/bugs/stories/webservice/xx-bug.txt (+1/-1)
lib/lp/code/stories/branches/xx-person-portlet-teambranches.txt (+1/-1)
lib/lp/hardwaredb/stories/hwdb/02-view-submissions.txt (+3/-3)
lib/lp/hardwaredb/stories/webservice/xx-hwdb.txt (+1/-1)
lib/lp/registry/stories/product/xx-product-files.txt (+4/-4)
lib/lp/registry/stories/webservice/xx-project-registry.txt (+2/-2)
lib/lp/registry/tests/test_distroseriesdifference.py (+1/-2)
lib/lp/soyuz/doc/distroarchseries.txt (+1/-1)
lib/lp/soyuz/doc/soyuz-files.txt (+2/-2)
lib/lp/soyuz/stories/ppa/xx-ppa-files.txt (+2/-2)
lib/lp/soyuz/stories/soyuz/xx-distro-package-pages.txt (+1/-1)
lib/lp/soyuz/stories/soyuz/xx-distroarchseries-binpackages.txt (+1/-1)
lib/lp/soyuz/stories/soyuz/xx-distroseries-sources.txt (+1/-1)
lib/lp/soyuz/stories/soyuz/xx-queue-pages-delayed-copies.txt (+1/-1)
lib/lp/soyuz/stories/soyuz/xx-queue-pages.txt (+2/-2)
lib/lp/soyuz/stories/webservice/xx-distroarchseries.txt (+1/-1)
lib/lp/soyuz/tests/test_publishing_models.py (+4/-6)
lib/lp/testing/__init__.py (+1/-6)
lib/lp/translations/doc/poexport-queue.txt (+1/-1)
lib/lp/translations/doc/poexport-request-productseries.txt (+1/-1)
lib/lp/translations/doc/poexport-request.txt (+2/-2)
lib/lp/translations/doc/poimport-pofile-not-exported-from-rosetta.txt (+1/-1)
lib/lp/translations/doc/poimport-pofile-old-po-imported.txt (+1/-1)
lib/lp/translations/doc/poimport-pofile-syntax-error.txt (+1/-1)
lib/lp/translations/doc/poimport-potemplate-syntax-error.txt (+2/-2)
lib/lp/translations/stories/standalone/xx-translations-xpi-import.txt (+1/-1)
To merge this branch: bzr merge lp:~stub/launchpad/librarian-layer
Reviewer Review Type Date Requested Status
Stuart Bishop (community) Approve
Review via email: mp+44466@code.launchpad.net

Commit message

[r=stub][ui=none][bug=661009,692872] Numerous Librarian test infrastructure improvements.

Description of the change

Fixes required to get lp:~lifeless/launchpad/librarian landed

To post a comment you must log in.
Revision history for this message
Stuart Bishop (stub) wrote :

Subunit stream of remaining failures (4) at http://paste.ubuntu.com/546626/

Includes some launchpadlib failures that need to be fixed in that tree.

Revision history for this message
Stuart Bishop (stub) wrote :

lp:~stub/launchpadlib/dynamiclibrarian needs to land and new egg prepared to fix a launchpadlib test that relies on the Librarian running on port 58000.

Revision history for this message
Stuart Bishop (stub) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/config/fixture.py'
2--- lib/canonical/config/fixture.py 2010-10-30 19:22:58 +0000
3+++ lib/canonical/config/fixture.py 2011-01-19 13:41:53 +0000
4@@ -28,7 +28,6 @@
5 _extend_str = dedent("""\
6 [meta]
7 extends: ../%s/launchpad-lazr.conf
8-
9 """)
10
11 def __init__(self, instance_name, copy_from_instance):
12
13=== modified file 'lib/canonical/config/tests/test_fixture.py'
14--- lib/canonical/config/tests/test_fixture.py 2010-10-19 19:23:19 +0000
15+++ lib/canonical/config/tests/test_fixture.py 2011-01-19 13:41:53 +0000
16@@ -50,11 +50,8 @@
17 confpath = 'configs/testtestconfig/launchpad-lazr.conf'
18 lazr_config = open(confpath, 'rb').read()
19 self.assertEqual(
20- dedent("""\
21- [meta]
22- extends: ../testrunner/launchpad-lazr.conf
23-
24- """),
25- lazr_config)
26+ "[meta]\n"
27+ "extends: ../testrunner/launchpad-lazr.conf",
28+ lazr_config.strip())
29 finally:
30 fixture.cleanUp()
31
32=== modified file 'lib/canonical/launchpad/doc/canonical-config.txt'
33--- lib/canonical/launchpad/doc/canonical-config.txt 2010-11-27 21:42:32 +0000
34+++ lib/canonical/launchpad/doc/canonical-config.txt 2011-01-19 13:41:53 +0000
35@@ -24,14 +24,6 @@
36 'launchpad_main'
37 >>> config.librarian.dbuser
38 'librarian'
39- >>> config.librarian.upload_host
40- 'localhost'
41- >>> config.librarian.upload_port
42- 59090
43- >>> config.librarian.download_host
44- 'localhost'
45- >>> config.librarian.download_port
46- 58000
47
48 Configs are kept from the 'configs' directory.
49
50
51=== modified file 'lib/canonical/launchpad/doc/librarian.txt'
52--- lib/canonical/launchpad/doc/librarian.txt 2011-01-19 02:05:39 +0000
53+++ lib/canonical/launchpad/doc/librarian.txt 2011-01-19 13:41:53 +0000
54@@ -78,9 +78,11 @@
55
56 We can get its URL too
57
58+ >>> from canonical.config import config
59 >>> import re
60 >>> re.search(
61- ... r'^http://localhost:58000/\d+/text.txt$', alias.http_url
62+ ... r'^%s\d+/text.txt$' % config.librarian.download_url,
63+ ... alias.http_url
64 ... ) is not None
65 True
66
67@@ -88,19 +90,17 @@
68 and similar inline-presented objects which would trigger security warnings on
69 https pages otherwise.
70
71- >>> re.search(
72- ... r'^https://localhost:58000/\d+/text.txt$', alias.https_url
73- ... ) is not None
74+ >>> re.search(r'^https://.+/\d+/text.txt$', alias.https_url) is not None
75 True
76
77 And we even have a convenient method which returns either the http URL or the
78 https one, depending on a config value.
79
80- >>> from canonical.config import config
81 >>> config.vhosts.use_https
82 False
83 >>> re.search(
84- ... r'^http://localhost:58000/\d+/text.txt$', alias.getURL()
85+ ... r'^%s\d+/text.txt$' % config.librarian.download_url,
86+ ... alias.getURL()
87 ... ) is not None
88 True
89
90@@ -111,7 +111,7 @@
91 ... """)
92 >>> config.push('test', test_data)
93 >>> re.search(
94- ... r'^https://localhost:58000/\d+/text.txt$', alias.https_url
95+ ... r'^https://.+/\d+/text.txt$', alias.https_url
96 ... ) is not None
97 True
98
99@@ -208,15 +208,17 @@
100 >>> f.read()
101 'This is some data'
102 >>> url = client.getURLForAlias(aid)
103- >>> re.search(r'^http://localhost:58000/\d+/text.txt$', url) is not None
104+ >>> re.search(
105+ ... r'^%s\d+/text.txt$' % config.librarian.download_url, url
106+ ... ) is not None
107 True
108
109 When secure=True, the returned url has the id as part of the domain name and
110 the protocol is https:
111
112- >>> expected = 'https://i%d.restricted.localhost:58000/%d/text.txt' % (
113- ... aid, aid)
114- >>> expected == client.getURLForAlias(aid, secure=True)
115+ >>> expected = r'^https://i%d\..+:\d+/%d/text.txt$' % (aid, aid)
116+ >>> found = client.getURLForAlias(aid, secure=True)
117+ >>> re.search(expected, found) is not None
118 True
119
120
121@@ -250,7 +252,7 @@
122 ... 'text.txt', len(data), StringIO(data), 'text/plain'
123 ... )
124 >>> print url
125- http://localhost:58000/.../text.txt
126+ http://.../text.txt
127 >>> from urllib2 import urlopen
128 >>> urlopen(url).read()
129 'This is some data'
130@@ -277,7 +279,7 @@
131 client can't see the database records yet).
132
133 >>> import re
134- >>> match = re.search('^http://localhost:\d+/(\d+)/', url)
135+ >>> match = re.search('/(\d+)/', url)
136 >>> alias_id = int(match.group(1))
137 >>> alias = lfas[alias_id]
138 >>> print alias.expires.isoformat()
139@@ -311,7 +313,10 @@
140 True
141
142 >>> print file_alias.http_url
143- http://localhost:58005/.../private.txt
144+ http://.../private.txt
145+ >>> file_alias.http_url.startswith(
146+ ... config.librarian.restricted_download_url)
147+ True
148
149 >>> transaction.commit()
150 >>> file_alias.open()
151@@ -339,7 +344,7 @@
152
153 >>> file_url = restricted_client.getURLForAlias(private_file_id)
154 >>> print file_url
155- http://localhost:58005/.../private.txt
156+ http://.../private.txt
157
158 Trying to access that file directly on the normal librarian will fail
159 (by switching the port)
160@@ -386,7 +391,9 @@
161 ... 'another-private.txt', len(private_content),
162 ... StringIO(private_content), 'text/plain')
163 >>> print url
164- http://localhost:58005/.../another-private.txt
165+ http://.../another-private.txt
166+ >>> url.startswith(config.librarian.restricted_download_url)
167+ True
168
169 The file can then immediately be retrieved:
170
171@@ -459,7 +466,7 @@
172 >>> f.read()
173 'This is some data'
174 >>> url = client.getURLForAlias(aid)
175- >>> re.search(r'^http://localhost:58000/\d+/hot%20dog$', url) is not None
176+ >>> re.search(r'/\d+/hot%20dog$', url) is not None
177 True
178
179 Unicode file names work. Note that the filename in the resulting URL
180@@ -472,7 +479,7 @@
181 >>> f.read()
182 'This is some data'
183 >>> url = client.getURLForAlias(aid)
184- >>> re.search(r'^http://localhost:58000/\d+/Yow%E2%80%BD$', url) is not None
185+ >>> re.search(r'/\d+/Yow%E2%80%BD$', url) is not None
186 True
187
188 Files will get garbage collected on production systems as per
189
190=== modified file 'lib/canonical/launchpad/doc/message.txt'
191--- lib/canonical/launchpad/doc/message.txt 2010-10-18 22:24:59 +0000
192+++ lib/canonical/launchpad/doc/message.txt 2011-01-19 13:41:53 +0000
193@@ -175,8 +175,6 @@
194 >>> blob = chunks[1].blob
195 >>> blob.filename
196 u'anna.jpg.exe'
197- >>> blob.http_url.startswith(u'http://localhost:58000/')
198- True
199 >>> blob.http_url.endswith(u'/anna.jpg.exe')
200 True
201
202
203=== modified file 'lib/canonical/launchpad/doc/old-testing.txt'
204--- lib/canonical/launchpad/doc/old-testing.txt 2011-01-19 13:41:25 +0000
205+++ lib/canonical/launchpad/doc/old-testing.txt 2011-01-19 13:41:53 +0000
206@@ -153,7 +153,8 @@
207 >>> from canonical.librarian.interfaces import ILibrarianClient
208 >>> from StringIO import StringIO
209
210->>> librarian = LibrarianServerFixture()
211+>>> from canonical.testing.layers import BaseLayer
212+>>> librarian = LibrarianServerFixture(BaseLayer.config_fixture)
213 >>> librarian.setUp()
214 >>> login(ANONYMOUS)
215
216
217=== modified file 'lib/canonical/launchpad/pagetests/webservice/xx-hostedfile.txt'
218--- lib/canonical/launchpad/pagetests/webservice/xx-hostedfile.txt 2009-04-17 10:32:16 +0000
219+++ lib/canonical/launchpad/pagetests/webservice/xx-hostedfile.txt 2011-01-19 13:41:53 +0000
220@@ -57,21 +57,21 @@
221 >>> print result
222 HTTP/1.1 303 See Other
223 ...
224- Location: http://localhost:58000/.../icon
225+ Location: http://.../icon
226 ...
227
228 >>> result = webservice.get(project['logo_link'])
229 >>> print result
230 HTTP/1.1 303 See Other
231 ...
232- Location: http://localhost:58000/.../logo
233+ Location: http://.../logo
234 ...
235
236 >>> result = webservice.get(project['brand_link'])
237 >>> print result
238 HTTP/1.1 303 See Other
239 ...
240- Location: http://localhost:58000/.../brand
241+ Location: http://.../brand
242 ...
243
244
245
246=== modified file 'lib/canonical/launchpad/scripts/ftests/librarianformatter.txt'
247--- lib/canonical/launchpad/scripts/ftests/librarianformatter.txt 2010-11-06 12:50:22 +0000
248+++ lib/canonical/launchpad/scripts/ftests/librarianformatter.txt 2011-01-19 13:41:53 +0000
249@@ -72,10 +72,10 @@
250 >>> librarian_log.error('Oops', exc_info=exception)
251 >>> print librarian_out.getvalue()
252 ERROR Oops
253- -> http://localhost:58000/...txt (An Exception)
254+ -> http://.../....txt (An Exception)
255 >>> url = librarian_out.getvalue().splitlines()[-1].split()[1:2][0]
256 >>> print url
257-http://localhost:58000/...txt
258+http://.../....txt
259 >>> print urlopen(url).read()
260 Traceback (most recent call last):
261 ...
262@@ -116,9 +116,9 @@
263 ... librarian_log.exception('Dud2')
264 >>> print librarian_out.getvalue()
265 ERROR Dud1
266- -> http://localhost:58000/...txt (Dud)
267+ -> http://.../....txt (Dud)
268 ERROR Dud2
269- -> http://localhost:58000/...txt (Dud)
270+ -> http://.../....txt (Dud)
271 <BLANKLINE>
272
273 The end result of this is to not have scripts display exceptions to
274@@ -134,8 +134,8 @@
275 >>> print out
276 Script Output
277 ERROR Oops
278- -> http://localhost:58000/...txt (Aargh)
279+ -> http://.../....txt (Aargh)
280 ERROR Root oops
281- -> http://localhost:58000/...txt (Aargh)
282+ -> http://.../....txt (Aargh)
283
284
285
286=== modified file 'lib/canonical/librarian/ftests/test_web.py'
287--- lib/canonical/librarian/ftests/test_web.py 2010-11-06 12:50:22 +0000
288+++ lib/canonical/librarian/ftests/test_web.py 2011-01-19 13:41:53 +0000
289@@ -149,23 +149,12 @@
290 url = client.getURLForAlias(aid)
291 self.assertEqual(urlopen(url).read(), 'sample')
292
293- old_url = 'http://%s:%d/42/%d/%s' % (
294- config.librarian.download_host,
295- config.librarian.download_port,
296- aid, filename)
297+ old_url = url.replace(str(aid), '42/%d' % aid)
298 self.assertEqual(urlopen(old_url).read(), 'sample')
299
300 # If the content id is not an integer, a 404 is raised
301- old_url = 'http://%s:%d/foo/%d/%s' % (
302- config.librarian.download_host,
303- config.librarian.download_port,
304- aid, filename)
305- self.require404(self._makeURL(aid, 'different.txt'))
306-
307- def _makeURL(self, aliasID, filename):
308- host = config.librarian.download_host
309- port = config.librarian.download_port
310- return 'http://%s:%d/%d/%s' % (host, port, aliasID, filename)
311+ old_url = url.replace(str(aid), 'foo/%d' % aid)
312+ self.require404(old_url)
313
314 def test_404(self):
315 client = LibrarianClient()
316@@ -175,13 +164,13 @@
317 url = client.getURLForAlias(aid)
318 self.assertEqual(urlopen(url).read(), 'sample')
319
320- # Ensure our helper is working
321- self.failUnlessEqual(url, self._makeURL(aid, filename))
322-
323 # Change the aliasid and assert we get a 404
324- self.require404(self._makeURL(aid+1, filename))
325+ self.failUnless(str(aid) in url)
326+ self.require404(url.replace(str(aid), str(aid+1)))
327+
328 # Change the filename and assert we get a 404
329- self.require404(self._makeURL(aid, 'different.txt'))
330+ self.failUnless(str(filename) in url)
331+ self.require404(url.replace(filename, 'different.txt'))
332
333 def test_duplicateuploads(self):
334 client = LibrarianClient()
335@@ -284,7 +273,7 @@
336 connection.request("GET", path, headers={'Host': good_host})
337 response = connection.getresponse()
338 response.read()
339- self.assertEqual(200, response.status)
340+ self.assertEqual(200, response.status, response)
341 # A subdomain based URL trying to put fileAlias into the restricted
342 # domain of fileAlias2 must not work.
343 hostile_host = template_host % fileAlias2
344
345=== modified file 'lib/canonical/librarian/testing/server.py'
346--- lib/canonical/librarian/testing/server.py 2011-01-19 13:41:25 +0000
347+++ lib/canonical/librarian/testing/server.py 2011-01-19 13:41:53 +0000
348@@ -44,11 +44,18 @@
349 :ivar pid: pid of the external process.
350 """
351
352- def __init__(self):
353+ def __init__(self, config_fixture):
354+ """Initialize the LibrarianServerFixture.
355+
356+ :param config_fixture: The ConfigFixture in use by our tests.
357+ In the layered environment, this is
358+ BaseLayer.config_fixture.
359+ """
360 Fixture.__init__(self)
361 self._pid = None
362 # Track whether the fixture has been setup or not.
363 self._setup = False
364+ self.config_fixture = config_fixture
365
366 def setUp(self):
367 """Start both librarian instances."""
368@@ -69,6 +76,11 @@
369 self._setup = True
370 self.addCleanup(setattr, self, '_setup', False)
371
372+ # Update the config our tests are using to know about the
373+ # correct ports.
374+ self.config_fixture.add_section(self.service_config)
375+ config.reloadConfig()
376+
377 def cleanUp(self):
378 """Shut downs both librarian instances."""
379 if self._persistent_servers():
380@@ -164,17 +176,19 @@
381 [librarian]
382 download_port: %s
383 upload_port: %s
384- download_url: http://launchpad.dev:%s/
385+ download_url: http://%s:%s/
386 restricted_download_port: %s
387 restricted_upload_port: %s
388- restricted_download_url: http://launchpad_dev:%s/
389+ restricted_download_url: http://%s:%s/
390 """) % (
391 self.root,
392 self.download_port,
393 self.upload_port,
394+ config.librarian.download_host,
395 self.download_port,
396 self.restricted_download_port,
397 self.restricted_upload_port,
398+ config.librarian.restricted_download_host,
399 self.restricted_download_port,
400 )
401
402
403=== modified file 'lib/canonical/librarian/testing/tests/test_server_fixture.py'
404--- lib/canonical/librarian/testing/tests/test_server_fixture.py 2011-01-19 13:41:25 +0000
405+++ lib/canonical/librarian/testing/tests/test_server_fixture.py 2011-01-19 13:41:53 +0000
406@@ -16,6 +16,7 @@
407 from testtools.content_type import UTF8_TEXT
408
409 from canonical.config import config
410+from canonical.config.fixture import ConfigFixture
411 from canonical.librarian.testing.server import LibrarianServerFixture
412 from canonical.testing.ftests.test_layers import (
413 BaseLayerIsolator,
414@@ -34,12 +35,20 @@
415 self.skip('persistent server running.')
416
417 def test_on_init_no_pid(self):
418- fixture = LibrarianServerFixture()
419+ fixture = LibrarianServerFixture(BaseLayer.config_fixture)
420 self.skip_if_persistent(fixture)
421 self.assertEqual(None, fixture.pid)
422
423 def test_setUp_allocates_resources(self):
424- fixture = LibrarianServerFixture()
425+ # We need a new ConfigFixture, and create a
426+ # LibrarianServerFixture using it. We can then confirm that new
427+ # resources have been allocated by comparing with the currently
428+ # in use ConfigFixture and config.
429+ config_fixture = ConfigFixture(
430+ 'foo', BaseLayer.config_fixture.instance_name)
431+ self.addCleanup(config_fixture.cleanUp)
432+ config_fixture.setUp()
433+ fixture = LibrarianServerFixture(config_fixture)
434 self.skip_if_persistent(fixture)
435 with fixture:
436 try:
437@@ -63,17 +72,19 @@
438 [librarian]
439 download_port: %s
440 upload_port: %s
441- download_url: http://launchpad.dev:%s/
442+ download_url: http://%s:%s/
443 restricted_download_port: %s
444 restricted_upload_port: %s
445- restricted_download_url: http://launchpad_dev:%s/
446+ restricted_download_url: http://%s:%s/
447 """) % (
448 fixture.root,
449 fixture.download_port,
450 fixture.upload_port,
451+ config.librarian.download_host,
452 fixture.download_port,
453 fixture.restricted_download_port,
454 fixture.restricted_upload_port,
455+ config.librarian.restricted_download_host,
456 fixture.restricted_download_port,
457 )
458 self.assertEqual(expected_config, fixture.service_config)
459@@ -82,7 +93,7 @@
460 raise
461
462 def test_getLogChunks(self):
463- fixture = LibrarianServerFixture()
464+ fixture = LibrarianServerFixture(BaseLayer.config_fixture)
465 with fixture:
466 chunks = fixture.getLogChunks()
467 self.assertIsInstance(chunks, list)
468@@ -96,7 +107,7 @@
469 # Avoid indefinite hangs:
470 self.addCleanup(socket.setdefaulttimeout, socket.getdefaulttimeout())
471 socket.setdefaulttimeout(1)
472- fixture = LibrarianServerFixture()
473+ fixture = LibrarianServerFixture(BaseLayer.config_fixture)
474 with fixture:
475 librarian_url = "http://%s:%d" % (
476 config.librarian.download_host,
477
478=== modified file 'lib/canonical/testing/ftests/test_layers.py'
479--- lib/canonical/testing/ftests/test_layers.py 2011-01-19 13:41:25 +0000
480+++ lib/canonical/testing/ftests/test_layers.py 2011-01-19 13:41:53 +0000
481@@ -55,7 +55,7 @@
482
483 class BaseLayerIsolator(Fixture):
484 """A fixture for isolating BaseLayer.
485-
486+
487 This is useful to test interactions with LP_PERSISTENT_TEST_SERVICES
488 which makes tests within layers unable to test that easily.
489 """
490@@ -113,7 +113,7 @@
491 self.assertEqual(None, os.environ.get('LP_TEST_INSTANCE'))
492
493 def test_persist_test_services_disables_LP_TEST_INSTANCE(self):
494- self.useFixture(BaseLayerIsolator())
495+ self.useFixture(BaseLayerIsolator(with_persistent=True))
496 with LayerFixture(BaseLayer):
497 self.assertEqual(None, os.environ.get('LP_TEST_INSTANCE'))
498 self.assertEqual(None, os.environ.get('LP_TEST_INSTANCE'))
499
500=== modified file 'lib/canonical/testing/layers.py'
501--- lib/canonical/testing/layers.py 2011-01-19 13:41:25 +0000
502+++ lib/canonical/testing/layers.py 2011-01-19 13:41:53 +0000
503@@ -820,12 +820,16 @@
504 "_reset_between_tests changed before LibrarianLayer "
505 "was actually used."
506 )
507- cls.librarian_fixture = LibrarianServerFixture()
508+ cls.librarian_fixture = LibrarianServerFixture(
509+ BaseLayer.config_fixture)
510 cls.librarian_fixture.setUp()
511- BaseLayer.config.add_section(cls.librarian_fixture.service_config)
512- config.reloadConfig()
513 cls._check_and_reset()
514
515+ # Make sure things using the appserver config know the
516+ # correct Librarian port numbers.
517+ cls.appserver_config_fixture.add_section(
518+ cls.librarian_fixture.service_config)
519+
520 @classmethod
521 @profiled
522 def tearDown(cls):
523@@ -841,9 +845,8 @@
524 try:
525 if not cls._reset_between_tests:
526 raise LayerInvariantError(
527- "_reset_between_tests not reset before LibrarianLayer "
528- "shutdown"
529- )
530+ "_reset_between_tests not reset before "
531+ "LibrarianLayer shutdown")
532 finally:
533 librarian.cleanUp()
534
535@@ -947,7 +950,7 @@
536 @profiled
537 def tearDown(cls):
538 pass
539-
540+
541 @classmethod
542 @profiled
543 def testSetUp(cls):
544
545=== modified file 'lib/lp/bugs/browser/tests/test_bugattachment_file_access.py'
546--- lib/lp/bugs/browser/tests/test_bugattachment_file_access.py 2011-01-06 11:49:00 +0000
547+++ lib/lp/bugs/browser/tests/test_bugattachment_file_access.py 2011-01-19 13:41:53 +0000
548@@ -88,7 +88,7 @@
549 next_view, traversal_path = view.browserDefault(request)
550 self.assertIsInstance(next_view, RedirectionView)
551 mo = re.match(
552- '^http://localhost:58000/\d+/foo.txt$', next_view.target)
553+ '^http://.*/\d+/foo.txt$', next_view.target)
554 self.assertIsNot(None, mo)
555
556 def test_access_to_restricted_file(self):
557@@ -213,13 +213,13 @@
558 self.assertEqual(303, response.status)
559
560 # The Librarian URL has, for our test case, the form
561- # "https://NNNN.restricted.localhost:58000/NNNN/foo.txt?token=..."
562- # where NNNN is an integer.
563+ # "https://NNNN.restricted.launchpad.dev:PORT/NNNN/foo.txt?token=..."
564+ # where NNNN and PORT are integers.
565 parsed_url = urlparse(response.getHeader('location'))
566 self.assertEqual('https', parsed_url.scheme)
567 mo = re.search(
568- r'^i\d+\.restricted\.localhost:58000$', parsed_url.netloc)
569- self.assertIsNot(None, mo)
570+ r'^i\d+\.restricted\..+:\d+$', parsed_url.netloc)
571+ self.assertIsNot(None, mo, parsed_url.netloc)
572 mo = re.search(r'^/\d+/foo\.txt$', parsed_url.path)
573 self.assertIsNot(None, mo)
574 params = parse_qs(parsed_url.query)
575
576=== modified file 'lib/lp/bugs/stories/webservice/xx-bug.txt'
577--- lib/lp/bugs/stories/webservice/xx-bug.txt 2010-12-20 17:42:47 +0000
578+++ lib/lp/bugs/stories/webservice/xx-bug.txt 2011-01-19 13:41:53 +0000
579@@ -1278,7 +1278,7 @@
580 HTTP/1.1 303 See Other...
581 Content-Length: 0
582 Content-Type: text/plain
583- Location: http://localhost:58000/.../numbers.txt
584+ Location: http://.../numbers.txt
585 ...
586
587 >>> from urllib2 import urlopen
588
589=== modified file 'lib/lp/code/stories/branches/xx-person-portlet-teambranches.txt'
590--- lib/lp/code/stories/branches/xx-person-portlet-teambranches.txt 2010-04-20 04:14:18 +0000
591+++ lib/lp/code/stories/branches/xx-person-portlet-teambranches.txt 2011-01-19 13:41:53 +0000
592@@ -36,6 +36,6 @@
593 Branches owned by
594 >>> print tb.li
595 <li>
596- <img src="http://localhost:58000/.../vikings.png" width="14" height="14" />
597+ <img src="http://.../vikings.png" width="14" height="14" />
598 <a href="/~vikings">Vikings</a>
599 </li>
600
601=== modified file 'lib/lp/hardwaredb/stories/hwdb/02-view-submissions.txt'
602--- lib/lp/hardwaredb/stories/hwdb/02-view-submissions.txt 2010-02-02 17:12:29 +0000
603+++ lib/lp/hardwaredb/stories/hwdb/02-view-submissions.txt 2011-01-19 13:41:53 +0000
604@@ -28,7 +28,7 @@
605
606 >>> download_link = anon_browser.getLink('test.txt')
607 >>> download_link.url
608- 'http://localhost:58000/.../test.txt'
609+ 'http://.../test.txt'
610
611 >>> raw_link = anon_browser.getLink('text')
612 >>> raw_link.url
613@@ -158,7 +158,7 @@
614 Distribution-Series: 5.04
615 Architecture: i386
616 System: Fujitsu_CY26
617- Submission URL: http://localhost:58000/.../test.txt
618+ Submission URL: http://.../test.txt
619
620 Private submissions can't be viewed anonymously:
621
622@@ -181,7 +181,7 @@
623 Distribution-Series: 5.04
624 Architecture: i386
625 System: Black Box 42
626- Submission URL: http://localhost:58000/.../teamtest.txt
627+ Submission URL: http://.../teamtest.txt
628
629
630 == Submissions listed by fingerprint ==
631
632=== modified file 'lib/lp/hardwaredb/stories/webservice/xx-hwdb.txt'
633--- lib/lp/hardwaredb/stories/webservice/xx-hwdb.txt 2010-02-02 17:12:29 +0000
634+++ lib/lp/hardwaredb/stories/webservice/xx-hwdb.txt 2011-01-19 13:41:53 +0000
635@@ -540,7 +540,7 @@
636 HTTP/1.1 303 See Other...
637 Content-Length: 0
638 Content-Type: text/plain
639- Location: http://localhost:58000/92/sample-submission-2.xml
640+ Location: http://.../92/sample-submission-2.xml
641 ...
642
643 A 404 error is returned when a client tries to access a non-existent
644
645=== modified file 'lib/lp/registry/stories/product/xx-product-files.txt'
646--- lib/lp/registry/stories/product/xx-product-files.txt 2010-09-24 20:49:42 +0000
647+++ lib/lp/registry/stories/product/xx-product-files.txt 2011-01-19 13:41:53 +0000
648@@ -516,7 +516,7 @@
649 >>> location = redirect_resp.getOutput().split("\n")[3]
650 >>> redirect_url = location.split()[1]
651 >>> print redirect_url
652- https://localhost:58000/.../foo.txt
653+ https://.../foo.txt
654
655 However if the original scheme is http then the redirect URL should be
656 over http.
657@@ -528,7 +528,7 @@
658 >>> location = redirect_resp.getOutput().split("\n")[3]
659 >>> redirect_url = location.split()[1]
660 >>> print redirect_url
661- http://localhost:58000/.../foo.txt
662+ http://.../foo.txt
663
664 When 'use_https' is False the result will always be http.
665
666@@ -548,7 +548,7 @@
667 >>> location = redirect_resp.getOutput().split("\n")[3]
668 >>> redirect_url = location.split()[1]
669 >>> print redirect_url
670- http://localhost:58000/.../foo.txt
671+ http://.../foo.txt
672
673 >>> redirect_resp = http(dedent("""\
674 ... GET %s HTTP/1.1
675@@ -557,7 +557,7 @@
676 >>> location = redirect_resp.getOutput().split("\n")[3]
677 >>> redirect_url = location.split()[1]
678 >>> print redirect_url
679- http://localhost:58000/.../foo.txt
680+ http://.../foo.txt
681
682 Return 'use_https' to its original value to not mess up future tests.
683
684
685=== modified file 'lib/lp/registry/stories/webservice/xx-project-registry.txt'
686--- lib/lp/registry/stories/webservice/xx-project-registry.txt 2010-11-22 21:36:21 +0000
687+++ lib/lp/registry/stories/webservice/xx-project-registry.txt 2011-01-19 13:41:53 +0000
688@@ -1112,7 +1112,7 @@
689 >>> print result
690 HTTP/1.1 303 See Other
691 ...
692- Location: http://localhost:58000/.../firefox_0.9.2.orig.tar.gz
693+ Location: http://.../firefox_0.9.2.orig.tar.gz
694 ...
695
696 The signature file will redirect too, if found. In this case there is
697@@ -1207,7 +1207,7 @@
698 >>> print result
699 HTTP/1.1 303 See Other
700 ...
701- Location: http://localhost:58000/.../filename.txt
702+ Location: http://.../filename.txt
703 ...
704
705 Project release files can be deleted using the 'delete' method. The
706
707=== modified file 'lib/lp/registry/tests/test_distroseriesdifference.py'
708--- lib/lp/registry/tests/test_distroseriesdifference.py 2010-10-29 19:28:14 +0000
709+++ lib/lp/registry/tests/test_distroseriesdifference.py 2011-01-19 13:41:53 +0000
710@@ -540,8 +540,7 @@
711 naked_dsdiff.parent_package_diff = self.factory.makePackageDiff()
712
713 self.assertEqual(None, ds_diff.package_diff_url)
714- self.assertTrue(ds_diff.parent_package_diff_url.startswith(
715- 'http://localhost:58000/'))
716+ self.assertTrue(ds_diff.parent_package_diff_url is not None)
717
718
719 class DistroSeriesDifferenceSourceTestCase(TestCaseWithFactory):
720
721=== modified file 'lib/lp/soyuz/doc/distroarchseries.txt'
722--- lib/lp/soyuz/doc/distroarchseries.txt 2010-11-02 21:44:42 +0000
723+++ lib/lp/soyuz/doc/distroarchseries.txt 2011-01-19 13:41:53 +0000
724@@ -367,7 +367,7 @@
725 the file.
726
727 >>> print hoary.getDistroArchSeries('hppa').chroot_url
728- http://localhost:58000/.../filename...
729+ http://.../filename...
730 >>> hoary.getDistroArchSeries('hppa').chroot_url == \
731 ... chroot.http_url
732 True
733
734=== modified file 'lib/lp/soyuz/doc/soyuz-files.txt'
735--- lib/lp/soyuz/doc/soyuz-files.txt 2010-10-19 18:44:31 +0000
736+++ lib/lp/soyuz/doc/soyuz-files.txt 2011-01-19 13:41:53 +0000
737@@ -48,7 +48,7 @@
738 u'firefox_0.9.2.orig.tar.gz'
739
740 >>> srcfile.libraryfile.http_url
741- 'http://localhost:58000/3/firefox_0.9.2.orig.tar.gz'
742+ 'http://.../3/firefox_0.9.2.orig.tar.gz'
743
744
745 == Binary Files ==
746@@ -76,7 +76,7 @@
747 u'pmount_1.9-1_all.deb'
748
749 >>> debfile.libraryfile.http_url
750- 'http://localhost:58000/37/pmount_1.9-1_all.deb'
751+ 'http://.../37/pmount_1.9-1_all.deb'
752
753
754 == Utilities ==
755
756=== modified file 'lib/lp/soyuz/stories/ppa/xx-ppa-files.txt'
757--- lib/lp/soyuz/stories/ppa/xx-ppa-files.txt 2011-01-12 23:07:40 +0000
758+++ lib/lp/soyuz/stories/ppa/xx-ppa-files.txt 2011-01-19 13:41:53 +0000
759@@ -350,14 +350,14 @@
760 >>> logout()
761
762 >>> print file_librarian_url
763- http://localhost:58000/.../test-pkg_1.0.dsc
764+ http://.../test-pkg_1.0.dsc
765
766 >>> print http(r"""
767 ... GET %s HTTP/1.1
768 ... """ % file_lp_url.replace('http://launchpad.dev', ''))
769 HTTP/1.1 303 See Other
770 ...
771- Location: http://localhost:58000/.../test-pkg_1.0.dsc
772+ Location: http://.../test-pkg_1.0.dsc
773 ...
774
775
776
777=== modified file 'lib/lp/soyuz/stories/soyuz/xx-distro-package-pages.txt'
778--- lib/lp/soyuz/stories/soyuz/xx-distro-package-pages.txt 2009-09-03 16:53:49 +0000
779+++ lib/lp/soyuz/stories/soyuz/xx-distro-package-pages.txt 2011-01-19 13:41:53 +0000
780@@ -47,5 +47,5 @@
781 ... """ % path)
782 HTTP/1.1 303 See Other
783 ...
784- Location: http://localhost:58000/68/commercialpackage_1.0-1.dsc
785+ Location: http://.../68/commercialpackage_1.0-1.dsc
786 ...
787
788=== modified file 'lib/lp/soyuz/stories/soyuz/xx-distroarchseries-binpackages.txt'
789--- lib/lp/soyuz/stories/soyuz/xx-distroarchseries-binpackages.txt 2009-12-11 15:27:08 +0000
790+++ lib/lp/soyuz/stories/soyuz/xx-distroarchseries-binpackages.txt 2011-01-19 13:41:53 +0000
791@@ -107,7 +107,7 @@
792 >>> dfiles_element = find_tag_by_id(
793 ... browser.contents, 'downloadable-files')
794 >>> print dfiles_element.find(name='a')['href']
795- http://localhost:58000/40/mozilla-firefox_0.9_i386.deb
796+ http://.../40/mozilla-firefox_0.9_i386.deb
797
798 If the binary package did produce files, but those files have been
799 subsequently deleted, this will also be indicated and the file will
800
801=== modified file 'lib/lp/soyuz/stories/soyuz/xx-distroseries-sources.txt'
802--- lib/lp/soyuz/stories/soyuz/xx-distroseries-sources.txt 2010-11-11 21:48:20 +0000
803+++ lib/lp/soyuz/stories/soyuz/xx-distroseries-sources.txt 2011-01-19 13:41:53 +0000
804@@ -387,7 +387,7 @@
805 With the possibility to download the entire changesfile (if available):
806
807 >>> print browser.getLink('View changes file').url
808- http://localhost:58000/65/commercialpackage_1.0-1_source.changes
809+ http://.../65/commercialpackage_1.0-1_source.changes
810
811 And also download the files contained in this source, like '.orig',
812 '.diff' and the DSC:
813
814=== modified file 'lib/lp/soyuz/stories/soyuz/xx-queue-pages-delayed-copies.txt'
815--- lib/lp/soyuz/stories/soyuz/xx-queue-pages-delayed-copies.txt 2010-10-18 22:24:59 +0000
816+++ lib/lp/soyuz/stories/soyuz/xx-queue-pages-delayed-copies.txt 2011-01-19 13:41:53 +0000
817@@ -122,7 +122,7 @@
818 >>> anon_browser.getControl("Update").click()
819
820 >>> print anon_browser.getLink('foo, foo').url
821- http://localhost:58000/.../foo_666_source.changes
822+ http://.../.../foo_666_source.changes
823
824 >>> extra_information = find_tags_by_class(
825 ... anon_browser.contents, 'queue-%s' % delayed_copy.id)
826
827=== modified file 'lib/lp/soyuz/stories/soyuz/xx-queue-pages.txt'
828--- lib/lp/soyuz/stories/soyuz/xx-queue-pages.txt 2011-01-19 13:41:25 +0000
829+++ lib/lp/soyuz/stories/soyuz/xx-queue-pages.txt 2011-01-19 13:41:53 +0000
830@@ -229,11 +229,11 @@
831
832 >>> for row in filelist:
833 ... print row.find('a')
834- <a href="http://localhost:58000/.../alsa-utils_1.0.9a-4ubuntu1.dsc">
835+ <a href="http://.../alsa-utils_1.0.9a-4ubuntu1.dsc">
836 alsa-utils_1.0.9a-4ubuntu1.dsc
837 </a>
838 None
839- <a href="http://localhost:58000/.../alsa-utils.diff.gz">diff from 1.0.9a-4 to 1.0.9a-4ubuntu1</a>
840+ <a href="http://.../alsa-utils.diff.gz">diff from 1.0.9a-4 to 1.0.9a-4ubuntu1</a>
841
842 On binary queue items we also present the stamp 'NEW' for files never
843 published in the archive (it helps archive admins when reviewing
844
845=== modified file 'lib/lp/soyuz/stories/webservice/xx-distroarchseries.txt'
846--- lib/lp/soyuz/stories/webservice/xx-distroarchseries.txt 2010-02-22 10:37:13 +0000
847+++ lib/lp/soyuz/stories/webservice/xx-distroarchseries.txt 2011-01-19 13:41:53 +0000
848@@ -34,7 +34,7 @@
849 >>> from lazr.restful.testing.webservice import pprint_entry
850 >>> pprint_entry(distroarchseries)
851 architecture_tag: u'i386'
852- chroot_url: u'http://localhost:58000/.../filename...'
853+ chroot_url: u'http://.../.../filename...'
854 display_name: u'Ubuntu Hoary i386'
855 distroseries_link: u'http://.../ubuntu/hoary'
856 is_nominated_arch_indep: True
857
858=== modified file 'lib/lp/soyuz/tests/test_publishing_models.py'
859--- lib/lp/soyuz/tests/test_publishing_models.py 2010-10-04 19:50:45 +0000
860+++ lib/lp/soyuz/tests/test_publishing_models.py 2011-01-19 13:41:53 +0000
861@@ -82,9 +82,7 @@
862 self.publishing_set.getChangesFileLFA(hist.sourcepackagerelease)
863 for hist in self.sources)
864 urls = [lfa.http_url for lfa in lfas]
865- self.assertEqual(urls, [
866- 'http://localhost:58000/94/gedit_666_source.changes',
867- 'http://localhost:58000/96/firefox_666_source.changes',
868- ('http://localhost:58000/98/'
869- 'getting-things-gnome_666_source.changes'),
870- ])
871+ self.assert_(urls[0].endswith('/94/gedit_666_source.changes'))
872+ self.assert_(urls[1].endswith('/96/firefox_666_source.changes'))
873+ self.assert_(urls[2].endswith(
874+ '/98/getting-things-gnome_666_source.changes'))
875
876=== modified file 'lib/lp/testing/__init__.py'
877--- lib/lp/testing/__init__.py 2011-01-19 13:41:25 +0000
878+++ lib/lp/testing/__init__.py 2011-01-19 13:41:53 +0000
879@@ -512,13 +512,8 @@
880 """Include the logChunks from fixture in the test details."""
881 # Evaluate the log when called, not later, to permit the librarian to
882 # be shutdown before the detail is rendered.
883-<<<<<<< TREE
884- chunks = fixture.logChunks()
885+ chunks = fixture.getLogChunks()
886 content = Content(UTF8_TEXT, lambda: chunks)
887-=======
888- chunks = fixture.getLogChunks()
889- content = Content(UTF8_TEXT, lambda:chunks)
890->>>>>>> MERGE-SOURCE
891 self.addDetail('librarian-log', content)
892
893 def setUp(self):
894
895=== modified file 'lib/lp/translations/doc/poexport-queue.txt'
896--- lib/lp/translations/doc/poexport-queue.txt 2011-01-13 18:09:48 +0000
897+++ lib/lp/translations/doc/poexport-queue.txt 2011-01-19 13:41:53 +0000
898@@ -304,7 +304,7 @@
899 The translation files you requested from Launchpad are ready for
900 download from the following location:
901 <BLANKLINE>
902- http://localhost:58000/.../po_evolution-2.2.pot
903+ http://.../.../po_evolution-2.2.pot
904 <BLANKLINE>
905 Note: this link will expire in about 1 week. If you want to
906 download these translations again, you will have to request
907
908=== modified file 'lib/lp/translations/doc/poexport-request-productseries.txt'
909--- lib/lp/translations/doc/poexport-request-productseries.txt 2010-12-22 20:46:21 +0000
910+++ lib/lp/translations/doc/poexport-request-productseries.txt 2011-01-19 13:41:53 +0000
911@@ -60,7 +60,7 @@
912 The translation files you requested from Launchpad are ready for
913 download from the following location:
914 <BLANKLINE>
915- http://localhost:58000/.../launchpad-export.tar.gz
916+ http://.../launchpad-export.tar.gz
917 <BLANKLINE>
918 Note: this link will expire in about 1 week. If you want to
919 download these translations again, you will have to request
920
921=== modified file 'lib/lp/translations/doc/poexport-request.txt'
922--- lib/lp/translations/doc/poexport-request.txt 2010-12-22 20:46:21 +0000
923+++ lib/lp/translations/doc/poexport-request.txt 2011-01-19 13:41:53 +0000
924@@ -62,7 +62,7 @@
925 The translation files you requested from Launchpad are ready for
926 download from the following location:
927 <BLANKLINE>
928- http://localhost:58000/.../launchpad-export.tar.gz
929+ http://.../launchpad-export.tar.gz
930 <BLANKLINE>
931 Note: this link will expire in about 1 week. If you want to
932 download these translations again, you will have to request
933@@ -194,7 +194,7 @@
934 The translation files you requested from Launchpad are ready for
935 download from the following location:
936 <BLANKLINE>
937- http://localhost:58000/.../cs_LC_MESSAGES_pmount.mo
938+ http://.../cs_LC_MESSAGES_pmount.mo
939 <BLANKLINE>
940 Note: this link will expire in about 1 week. If you want to
941 download these translations again, you will have to request
942
943=== modified file 'lib/lp/translations/doc/poimport-pofile-not-exported-from-rosetta.txt'
944--- lib/lp/translations/doc/poimport-pofile-not-exported-from-rosetta.txt 2010-12-02 16:13:51 +0000
945+++ lib/lp/translations/doc/poimport-pofile-not-exported-from-rosetta.txt 2011-01-19 13:41:53 +0000
946@@ -118,7 +118,7 @@
947 apply your changes and upload the merged file.
948 <BLANKLINE>
949 For your convenience, you can get the file you uploaded at:
950- http://localhost:58000/.../firefox-cy.po
951+ http://.../firefox-cy.po
952 <BLANKLINE>
953 Thank you,
954 <BLANKLINE>
955
956=== modified file 'lib/lp/translations/doc/poimport-pofile-old-po-imported.txt'
957--- lib/lp/translations/doc/poimport-pofile-old-po-imported.txt 2010-12-02 16:13:51 +0000
958+++ lib/lp/translations/doc/poimport-pofile-old-po-imported.txt 2011-01-19 13:41:53 +0000
959@@ -177,7 +177,7 @@
960 'PO-Revision-Date' field updated.
961 <BLANKLINE>
962 For your convenience, you can get the file you uploaded at:
963- http://localhost:58000/.../firefox-cy.po
964+ http://.../firefox-cy.po
965 <BLANKLINE>
966 Thank you,
967 <BLANKLINE>
968
969=== modified file 'lib/lp/translations/doc/poimport-pofile-syntax-error.txt'
970--- lib/lp/translations/doc/poimport-pofile-syntax-error.txt 2010-12-02 16:13:51 +0000
971+++ lib/lp/translations/doc/poimport-pofile-syntax-error.txt 2011-01-19 13:41:53 +0000
972@@ -113,7 +113,7 @@
973 answer or file a question at https://answers.launchpad.net/rosetta/
974 <BLANKLINE>
975 For your convenience, you can get the file you uploaded at:
976- http://localhost:58000/.../firefox-cy.po
977+ http://.../firefox-cy.po
978 <BLANKLINE>
979 Thank you,
980 <BLANKLINE>
981
982=== modified file 'lib/lp/translations/doc/poimport-potemplate-syntax-error.txt'
983--- lib/lp/translations/doc/poimport-potemplate-syntax-error.txt 2010-12-02 16:13:51 +0000
984+++ lib/lp/translations/doc/poimport-potemplate-syntax-error.txt 2011-01-19 13:41:53 +0000
985@@ -94,7 +94,7 @@
986 answer or file a question at https://answers.launchpad.net/rosetta/
987 <BLANKLINE>
988 For your convenience, you can get the file you uploaded at:
989- http://localhost:58000/.../firefox.pot
990+ http://.../firefox.pot
991 <BLANKLINE>
992 Thank you,
993 <BLANKLINE>
994@@ -151,7 +151,7 @@
995 'ascii' codec can't decode byte ...
996 <BLANKLINE>
997 For your convenience, you can find the file you uploaded at:
998- http://localhost:58000/.../nonascii.pot
999+ http://.../nonascii.pot
1000 <BLANKLINE>
1001 Thank you,
1002 <BLANKLINE>
1003
1004=== modified file 'lib/lp/translations/stories/standalone/xx-translations-xpi-import.txt'
1005--- lib/lp/translations/stories/standalone/xx-translations-xpi-import.txt 2009-09-14 19:00:45 +0000
1006+++ lib/lp/translations/stories/standalone/xx-translations-xpi-import.txt 2011-01-19 13:41:53 +0000
1007@@ -36,7 +36,7 @@
1008
1009 >>> browser.getLink('Translation Import Queue').click()
1010 >>> print browser.getLink(url='en-US.xpi').url
1011- http://localhost:58000/.../en-US.xpi
1012+ http://.../en-US.xpi
1013 >>> browser.getLink(url='imports/3').click()
1014 >>> print browser.url
1015 http://translations.launchpad.dev/+imports/3