Merge lp:~cjwatson/launchpad/faster-archive-signing-key-tests into lp:launchpad
- faster-archive-signing-key-tests
- Merge into devel
Proposed by
Colin Watson
Status: | Merged |
---|---|
Merged at revision: | 18380 |
Proposed branch: | lp:~cjwatson/launchpad/faster-archive-signing-key-tests |
Merge into: | lp:launchpad |
Prerequisite: | lp:~cjwatson/launchpad/composeBuildRequest-deferred |
Diff against target: |
594 lines (+222/-56) 9 files modified
lib/lp/archivepublisher/archivesigningkey.py (+44/-15) lib/lp/archivepublisher/interfaces/archivesigningkey.py (+5/-2) lib/lp/archivepublisher/tests/test_archivesigningkey.py (+10/-4) lib/lp/archivepublisher/tests/test_publishdistro.py (+18/-14) lib/lp/archivepublisher/tests/test_publisher.py (+17/-15) lib/lp/archivepublisher/tests/test_signing.py (+12/-5) lib/lp/testing/keyserver/__init__.py (+3/-1) lib/lp/testing/keyserver/inprocess.py (+69/-0) lib/lp/testing/keyserver/tests/test_inprocess.py (+44/-0) |
To merge this branch: | bzr merge lp:~cjwatson/launchpad/faster-archive-signing-key-tests |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
William Grant | code | Approve | |
Review via email: mp+323429@code.launchpad.net |
Commit message
Speed up tests that use archive signing keys using an in-process keyserver fixture.
Description of the change
This only works for tests that only talk to the keyserver asynchronously, but for those that do it's very much faster to start one up in-process rather than using a .tac file: it saves on the order of 10 seconds per affected test on my laptop.
The tests for the fixture itself seem to hit some slightly buggy bit of Twisted and require a couple of extra spins through the reactor to clear up cancelled DelayedCalls, but fortunately testtools.
To post a comment you must log in.
Revision history for this message
William Grant (wgrant) : | # |
review:
Approve
(code)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/lp/archivepublisher/archivesigningkey.py' |
2 | --- lib/lp/archivepublisher/archivesigningkey.py 2016-06-17 21:38:32 +0000 |
3 | +++ lib/lp/archivepublisher/archivesigningkey.py 2017-04-29 15:42:19 +0000 |
4 | @@ -1,4 +1,4 @@ |
5 | -# Copyright 2009-2016 Canonical Ltd. This software is licensed under the |
6 | +# Copyright 2009-2017 Canonical Ltd. This software is licensed under the |
7 | # GNU Affero General Public License version 3 (see the file LICENSE). |
8 | |
9 | """ArchiveSigningKey implementation.""" |
10 | @@ -13,8 +13,13 @@ |
11 | import os |
12 | |
13 | import gpgme |
14 | +from twisted.internet.threads import deferToThread |
15 | from zope.component import getUtility |
16 | from zope.interface import implementer |
17 | +from zope.security.proxy import ( |
18 | + ProxyFactory, |
19 | + removeSecurityProxy, |
20 | + ) |
21 | |
22 | from lp.app.interfaces.launchpad import ILaunchpadCelebrities |
23 | from lp.archivepublisher.config import getPubConfig |
24 | @@ -78,7 +83,7 @@ |
25 | secret_key = getUtility(IGPGHandler).generateKey(key_displayname) |
26 | self._setupSigningKey(secret_key) |
27 | |
28 | - def setSigningKey(self, key_path): |
29 | + def setSigningKey(self, key_path, async_keyserver=False): |
30 | """See `IArchiveSigningKey`.""" |
31 | assert self.archive.signing_key is None, ( |
32 | "Cannot override signing_keys.") |
33 | @@ -88,22 +93,21 @@ |
34 | with open(key_path) as key_file: |
35 | secret_key_export = key_file.read() |
36 | secret_key = getUtility(IGPGHandler).importSecretKey(secret_key_export) |
37 | - self._setupSigningKey(secret_key) |
38 | - |
39 | - def _setupSigningKey(self, secret_key): |
40 | - """Mandatory setup for signing keys. |
41 | - |
42 | - * Export the secret key into the protected disk location. |
43 | - * Upload public key to the keyserver. |
44 | - * Store the public GPGKey reference in the database and update |
45 | - the context archive.signing_key. |
46 | - """ |
47 | - self.exportSecretKey(secret_key) |
48 | - |
49 | - gpghandler = getUtility(IGPGHandler) |
50 | + return self._setupSigningKey( |
51 | + secret_key, async_keyserver=async_keyserver) |
52 | + |
53 | + def _uploadPublicSigningKey(self, secret_key): |
54 | + """Upload the public half of a signing key to the keyserver.""" |
55 | + # The handler's security proxying doesn't protect anything useful |
56 | + # here, and when we're running in a thread we don't have an |
57 | + # interaction. |
58 | + gpghandler = removeSecurityProxy(getUtility(IGPGHandler)) |
59 | pub_key = gpghandler.retrieveKey(secret_key.fingerprint) |
60 | gpghandler.uploadPublicKey(pub_key.fingerprint) |
61 | + return pub_key |
62 | |
63 | + def _storeSigningKey(self, pub_key): |
64 | + """Store signing key reference in the database.""" |
65 | key_owner = getUtility(ILaunchpadCelebrities).ppa_key_guard |
66 | key, _ = getUtility(IGPGKeySet).activate( |
67 | key_owner, pub_key, pub_key.can_encrypt) |
68 | @@ -111,6 +115,31 @@ |
69 | self.archive.signing_key_fingerprint = key.fingerprint |
70 | del get_property_cache(self.archive).signing_key |
71 | |
72 | + def _setupSigningKey(self, secret_key, async_keyserver=False): |
73 | + """Mandatory setup for signing keys. |
74 | + |
75 | + * Export the secret key into the protected disk location. |
76 | + * Upload public key to the keyserver. |
77 | + * Store the public GPGKey reference in the database and update |
78 | + the context archive.signing_key. |
79 | + """ |
80 | + self.exportSecretKey(secret_key) |
81 | + if async_keyserver: |
82 | + # If we have an asynchronous keyserver running in the current |
83 | + # thread using Twisted, then we need some contortions to ensure |
84 | + # that the GPG handler doesn't deadlock. This is most easily |
85 | + # done by deferring the GPG handler work to another thread. |
86 | + # Since that thread won't have a Zope interaction, we need to |
87 | + # unwrap the security proxy for it. |
88 | + d = deferToThread( |
89 | + self._uploadPublicSigningKey, removeSecurityProxy(secret_key)) |
90 | + d.addCallback(ProxyFactory) |
91 | + d.addCallback(self._storeSigningKey) |
92 | + return d |
93 | + else: |
94 | + pub_key = self._uploadPublicSigningKey(secret_key) |
95 | + self._storeSigningKey(pub_key) |
96 | + |
97 | def signRepository(self, suite): |
98 | """See `IArchiveSigningKey`.""" |
99 | assert self.archive.signing_key is not None, ( |
100 | |
101 | === modified file 'lib/lp/archivepublisher/interfaces/archivesigningkey.py' |
102 | --- lib/lp/archivepublisher/interfaces/archivesigningkey.py 2016-06-17 21:07:22 +0000 |
103 | +++ lib/lp/archivepublisher/interfaces/archivesigningkey.py 2017-04-29 15:42:19 +0000 |
104 | @@ -1,4 +1,4 @@ |
105 | -# Copyright 2009 Canonical Ltd. This software is licensed under the |
106 | +# Copyright 2009-2017 Canonical Ltd. This software is licensed under the |
107 | # GNU Affero General Public License version 3 (see the file LICENSE). |
108 | |
109 | """ArchiveSigningKey interface.""" |
110 | @@ -70,9 +70,12 @@ |
111 | upload to the keyserver. |
112 | """ |
113 | |
114 | - def setSigningKey(key_path): |
115 | + def setSigningKey(key_path, async_keyserver=False): |
116 | """Set a given secret key export as the context archive signing key. |
117 | |
118 | + :param key_path: full path to the secret key. |
119 | + :param async_keyserver: true if the keyserver is running |
120 | + asynchronously in the current thread. |
121 | :raises AssertionError: if the context archive already has a |
122 | `signing_key`. |
123 | :raises AssertionError: if the given 'key_path' does not exist. |
124 | |
125 | === modified file 'lib/lp/archivepublisher/tests/test_archivesigningkey.py' |
126 | --- lib/lp/archivepublisher/tests/test_archivesigningkey.py 2016-06-17 21:07:22 +0000 |
127 | +++ lib/lp/archivepublisher/tests/test_archivesigningkey.py 2017-04-29 15:42:19 +0000 |
128 | @@ -1,4 +1,4 @@ |
129 | -# Copyright 2016 Canonical Ltd. This software is licensed under the |
130 | +# Copyright 2016-2017 Canonical Ltd. This software is licensed under the |
131 | # GNU Affero General Public License version 3 (see the file LICENSE). |
132 | |
133 | """Test ArchiveSigningKey.""" |
134 | @@ -7,6 +7,8 @@ |
135 | |
136 | import os |
137 | |
138 | +from testtools.deferredruntest import AsynchronousDeferredRunTest |
139 | +from twisted.internet import defer |
140 | from zope.component import getUtility |
141 | |
142 | from lp.archivepublisher.config import getPubConfig |
143 | @@ -18,14 +20,16 @@ |
144 | from lp.soyuz.enums import ArchivePurpose |
145 | from lp.testing import TestCaseWithFactory |
146 | from lp.testing.gpgkeys import gpgkeysdir |
147 | -from lp.testing.keyserver import KeyServerTac |
148 | +from lp.testing.keyserver import InProcessKeyServerFixture |
149 | from lp.testing.layers import ZopelessDatabaseLayer |
150 | |
151 | |
152 | class TestArchiveSigningKey(TestCaseWithFactory): |
153 | |
154 | layer = ZopelessDatabaseLayer |
155 | + run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=10) |
156 | |
157 | + @defer.inlineCallbacks |
158 | def setUp(self): |
159 | super(TestArchiveSigningKey, self).setUp() |
160 | self.temp_dir = self.makeTemporaryDirectory() |
161 | @@ -38,9 +42,11 @@ |
162 | self.archive_root = getPubConfig(self.archive).archiveroot |
163 | self.suite = "distroseries" |
164 | |
165 | - with KeyServerTac(): |
166 | + with InProcessKeyServerFixture() as keyserver: |
167 | + yield keyserver.start() |
168 | key_path = os.path.join(gpgkeysdir, 'ppa-sample@canonical.com.sec') |
169 | - IArchiveSigningKey(self.archive).setSigningKey(key_path) |
170 | + yield IArchiveSigningKey(self.archive).setSigningKey( |
171 | + key_path, async_keyserver=True) |
172 | |
173 | def test_signfile_absolute_within_archive(self): |
174 | filename = os.path.join(self.archive_root, "signme") |
175 | |
176 | === modified file 'lib/lp/archivepublisher/tests/test_publishdistro.py' |
177 | --- lib/lp/archivepublisher/tests/test_publishdistro.py 2016-11-07 16:42:23 +0000 |
178 | +++ lib/lp/archivepublisher/tests/test_publishdistro.py 2017-04-29 15:42:19 +0000 |
179 | @@ -1,4 +1,4 @@ |
180 | -# Copyright 2009-2016 Canonical Ltd. This software is licensed under the |
181 | +# Copyright 2009-2017 Canonical Ltd. This software is licensed under the |
182 | # GNU Affero General Public License version 3 (see the file LICENSE). |
183 | |
184 | """Functional tests for publish-distro.py script.""" |
185 | @@ -11,10 +11,12 @@ |
186 | import subprocess |
187 | import sys |
188 | |
189 | +from testtools.deferredruntest import AsynchronousDeferredRunTest |
190 | from testtools.matchers import ( |
191 | Not, |
192 | PathExists, |
193 | ) |
194 | +from twisted.internet import defer |
195 | from zope.component import getUtility |
196 | from zope.security.proxy import removeSecurityProxy |
197 | |
198 | @@ -47,13 +49,15 @@ |
199 | from lp.testing.fakemethod import FakeMethod |
200 | from lp.testing.faketransaction import FakeTransaction |
201 | from lp.testing.gpgkeys import gpgkeysdir |
202 | -from lp.testing.keyserver import KeyServerTac |
203 | +from lp.testing.keyserver import InProcessKeyServerFixture |
204 | from lp.testing.layers import ZopelessDatabaseLayer |
205 | |
206 | |
207 | class TestPublishDistro(TestNativePublishingBase): |
208 | """Test the publish-distro.py script works properly.""" |
209 | |
210 | + run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=10) |
211 | + |
212 | def runPublishDistro(self, extra_args=None, distribution="ubuntutest"): |
213 | """Run publish-distro without invoking the script. |
214 | |
215 | @@ -222,6 +226,7 @@ |
216 | pub_source.sync() |
217 | self.assertEqual(PackagePublishingStatus.PENDING, pub_source.status) |
218 | |
219 | + @defer.inlineCallbacks |
220 | def testForPPA(self): |
221 | """Try to run publish-distro in PPA mode. |
222 | |
223 | @@ -247,11 +252,10 @@ |
224 | naked_archive.distribution = self.ubuntutest |
225 | |
226 | self.setUpRequireSigningKeys() |
227 | - tac = KeyServerTac() |
228 | - tac.setUp() |
229 | - self.addCleanup(tac.tearDown) |
230 | + yield self.useFixture(InProcessKeyServerFixture()).start() |
231 | key_path = os.path.join(gpgkeysdir, 'ppa-sample@canonical.com.sec') |
232 | - IArchiveSigningKey(cprov.archive).setSigningKey(key_path) |
233 | + yield IArchiveSigningKey(cprov.archive).setSigningKey( |
234 | + key_path, async_keyserver=True) |
235 | name16.archive.signing_key_owner = cprov.archive.signing_key_owner |
236 | name16.archive.signing_key_fingerprint = ( |
237 | cprov.archive.signing_key_fingerprint) |
238 | @@ -282,6 +286,7 @@ |
239 | 'ppa/ubuntutest/pool/main/b/bar/bar_666.dsc') |
240 | self.assertEqual('bar', open(bar_path).read().strip()) |
241 | |
242 | + @defer.inlineCallbacks |
243 | def testForPrivatePPA(self): |
244 | """Run publish-distro in private PPA mode. |
245 | |
246 | @@ -299,11 +304,10 @@ |
247 | self.layer.txn.commit() |
248 | |
249 | self.setUpRequireSigningKeys() |
250 | - tac = KeyServerTac() |
251 | - tac.setUp() |
252 | - self.addCleanup(tac.tearDown) |
253 | + yield self.useFixture(InProcessKeyServerFixture()).start() |
254 | key_path = os.path.join(gpgkeysdir, 'ppa-sample@canonical.com.sec') |
255 | - IArchiveSigningKey(private_ppa).setSigningKey(key_path) |
256 | + yield IArchiveSigningKey(private_ppa).setSigningKey( |
257 | + key_path, async_keyserver=True) |
258 | |
259 | # Try a plain PPA run, to ensure the private one is NOT published. |
260 | self.runPublishDistro(['--ppa']) |
261 | @@ -398,17 +402,17 @@ |
262 | self.config.distsroot) |
263 | self.assertNotExists(index_path) |
264 | |
265 | + @defer.inlineCallbacks |
266 | def testCarefulRelease(self): |
267 | """publish-distro can be asked to just rewrite Release files.""" |
268 | archive = self.factory.makeArchive(distribution=self.ubuntutest) |
269 | pub_source = self.getPubSource(filecontent='foo', archive=archive) |
270 | |
271 | self.setUpRequireSigningKeys() |
272 | - tac = KeyServerTac() |
273 | - tac.setUp() |
274 | - self.addCleanup(tac.tearDown) |
275 | + yield self.useFixture(InProcessKeyServerFixture()).start() |
276 | key_path = os.path.join(gpgkeysdir, 'ppa-sample@canonical.com.sec') |
277 | - IArchiveSigningKey(archive).setSigningKey(key_path) |
278 | + yield IArchiveSigningKey(archive).setSigningKey( |
279 | + key_path, async_keyserver=True) |
280 | |
281 | self.layer.txn.commit() |
282 | |
283 | |
284 | === modified file 'lib/lp/archivepublisher/tests/test_publisher.py' |
285 | --- lib/lp/archivepublisher/tests/test_publisher.py 2016-11-07 16:42:23 +0000 |
286 | +++ lib/lp/archivepublisher/tests/test_publisher.py 2017-04-29 15:42:19 +0000 |
287 | @@ -1,4 +1,4 @@ |
288 | -# Copyright 2009-2016 Canonical Ltd. This software is licensed under the |
289 | +# Copyright 2009-2017 Canonical Ltd. This software is licensed under the |
290 | # GNU Affero General Public License version 3 (see the file LICENSE). |
291 | |
292 | """Tests for publisher class.""" |
293 | @@ -32,6 +32,7 @@ |
294 | except ImportError: |
295 | from backports import lzma |
296 | import pytz |
297 | +from testtools.deferredruntest import AsynchronousDeferredRunTest |
298 | from testtools.matchers import ( |
299 | ContainsAll, |
300 | DirContains, |
301 | @@ -49,6 +50,7 @@ |
302 | SamePath, |
303 | ) |
304 | import transaction |
305 | +from twisted.internet import defer |
306 | from zope.component import getUtility |
307 | from zope.security.proxy import removeSecurityProxy |
308 | |
309 | @@ -101,7 +103,7 @@ |
310 | from lp.testing import TestCaseWithFactory |
311 | from lp.testing.fakemethod import FakeMethod |
312 | from lp.testing.gpgkeys import gpgkeysdir |
313 | -from lp.testing.keyserver import KeyServerTac |
314 | +from lp.testing.keyserver import InProcessKeyServerFixture |
315 | from lp.testing.layers import ( |
316 | LaunchpadZopelessLayer, |
317 | ZopelessDatabaseLayer, |
318 | @@ -2927,6 +2929,8 @@ |
319 | class TestPublisherRepositorySignatures(TestPublisherBase): |
320 | """Testing `Publisher` signature behaviour.""" |
321 | |
322 | + run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=10) |
323 | + |
324 | archive_publisher = None |
325 | |
326 | def tearDown(self): |
327 | @@ -3005,6 +3009,7 @@ |
328 | self.assertNotIn('Release.gpg', sync_args[1]) |
329 | self.assertNotIn('InRelease', sync_args[1]) |
330 | |
331 | + @defer.inlineCallbacks |
332 | def testRepositorySignatureWithSigningKey(self): |
333 | """Check publisher behaviour when signing repositories. |
334 | |
335 | @@ -3016,12 +3021,12 @@ |
336 | self.assertTrue(cprov.archive.signing_key is None) |
337 | |
338 | # Start the test keyserver, so the signing_key can be uploaded. |
339 | - tac = KeyServerTac() |
340 | - tac.setUp() |
341 | + yield self.useFixture(InProcessKeyServerFixture()).start() |
342 | |
343 | # Set a signing key for Celso's PPA. |
344 | key_path = os.path.join(gpgkeysdir, 'ppa-sample@canonical.com.sec') |
345 | - IArchiveSigningKey(cprov.archive).setSigningKey(key_path) |
346 | + yield IArchiveSigningKey(cprov.archive).setSigningKey( |
347 | + key_path, async_keyserver=True) |
348 | self.assertTrue(cprov.archive.signing_key is not None) |
349 | |
350 | self.setupPublisher(cprov.archive) |
351 | @@ -3061,9 +3066,6 @@ |
352 | self.assertThat( |
353 | sync_args[1], ContainsAll(['Release', 'Release.gpg', 'InRelease'])) |
354 | |
355 | - # All done, turn test-keyserver off. |
356 | - tac.tearDown() |
357 | - |
358 | |
359 | class TestPublisherLite(TestCaseWithFactory): |
360 | """Lightweight unit tests for the publisher.""" |
361 | @@ -3299,7 +3301,9 @@ |
362 | """Unit tests for DirectoryHash object, signing functionality.""" |
363 | |
364 | layer = ZopelessDatabaseLayer |
365 | + run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=10) |
366 | |
367 | + @defer.inlineCallbacks |
368 | def setUp(self): |
369 | super(TestDirectoryHashSigning, self).setUp() |
370 | self.temp_dir = self.makeTemporaryDirectory() |
371 | @@ -3313,13 +3317,11 @@ |
372 | self.suite = "distroseries" |
373 | |
374 | # Setup a keyserver so we can install the archive key. |
375 | - tac = KeyServerTac() |
376 | - tac.setUp() |
377 | - |
378 | - key_path = os.path.join(gpgkeysdir, 'ppa-sample@canonical.com.sec') |
379 | - IArchiveSigningKey(self.archive).setSigningKey(key_path) |
380 | - |
381 | - tac.tearDown() |
382 | + with InProcessKeyServerFixture() as keyserver: |
383 | + yield keyserver.start() |
384 | + key_path = os.path.join(gpgkeysdir, 'ppa-sample@canonical.com.sec') |
385 | + yield IArchiveSigningKey(self.archive).setSigningKey( |
386 | + key_path, async_keyserver=True) |
387 | |
388 | def test_basic_directory_add_signed(self): |
389 | tmpdir = unicode(self.makeTemporaryDirectory()) |
390 | |
391 | === modified file 'lib/lp/archivepublisher/tests/test_signing.py' |
392 | --- lib/lp/archivepublisher/tests/test_signing.py 2016-06-22 08:54:11 +0000 |
393 | +++ lib/lp/archivepublisher/tests/test_signing.py 2017-04-29 15:42:19 +0000 |
394 | @@ -1,4 +1,4 @@ |
395 | -# Copyright 2012-2016 Canonical Ltd. This software is licensed under the |
396 | +# Copyright 2012-2017 Canonical Ltd. This software is licensed under the |
397 | # GNU Affero General Public License version 3 (see the file LICENSE). |
398 | |
399 | """Test UEFI custom uploads.""" |
400 | @@ -10,6 +10,8 @@ |
401 | import tarfile |
402 | |
403 | from fixtures import MonkeyPatch |
404 | +from testtools.deferredruntest import AsynchronousDeferredRunTest |
405 | +from twisted.internet import defer |
406 | from zope.component import getUtility |
407 | |
408 | from lp.archivepublisher.config import getPubConfig |
409 | @@ -31,7 +33,7 @@ |
410 | from lp.testing import TestCaseWithFactory |
411 | from lp.testing.fakemethod import FakeMethod |
412 | from lp.testing.gpgkeys import gpgkeysdir |
413 | -from lp.testing.keyserver import KeyServerTac |
414 | +from lp.testing.keyserver import InProcessKeyServerFixture |
415 | from lp.testing.layers import ZopelessDatabaseLayer |
416 | |
417 | |
418 | @@ -87,6 +89,7 @@ |
419 | class TestSigningHelpers(TestCaseWithFactory): |
420 | |
421 | layer = ZopelessDatabaseLayer |
422 | + run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=10) |
423 | |
424 | def setUp(self): |
425 | super(TestSigningHelpers, self).setUp() |
426 | @@ -122,10 +125,13 @@ |
427 | if not os.path.exists(pubconf.temproot): |
428 | os.makedirs(pubconf.temproot) |
429 | |
430 | + @defer.inlineCallbacks |
431 | def setUpArchiveKey(self): |
432 | - with KeyServerTac(): |
433 | + with InProcessKeyServerFixture() as keyserver: |
434 | + yield keyserver.start() |
435 | key_path = os.path.join(gpgkeysdir, 'ppa-sample@canonical.com.sec') |
436 | - IArchiveSigningKey(self.archive).setSigningKey(key_path) |
437 | + yield IArchiveSigningKey(self.archive).setSigningKey( |
438 | + key_path, async_keyserver=True) |
439 | |
440 | def setUpUefiKeys(self, create=True): |
441 | self.key = os.path.join(self.signing_dir, "uefi.key") |
442 | @@ -648,11 +654,12 @@ |
443 | "1.0", "SHA256SUMS") |
444 | self.assertTrue(os.path.exists(sha256file)) |
445 | |
446 | + @defer.inlineCallbacks |
447 | def test_checksumming_tree_signed(self): |
448 | # Specifying no options should leave us with an open tree, |
449 | # confirm it is checksummed. Supply an archive signing key |
450 | # which should trigger signing of the checksum file. |
451 | - self.setUpArchiveKey() |
452 | + yield self.setUpArchiveKey() |
453 | self.setUpUefiKeys() |
454 | self.setUpKmodKeys() |
455 | self.openArchive("test", "1.0", "amd64") |
456 | |
457 | === modified file 'lib/lp/testing/keyserver/__init__.py' |
458 | --- lib/lp/testing/keyserver/__init__.py 2013-01-07 02:40:55 +0000 |
459 | +++ lib/lp/testing/keyserver/__init__.py 2017-04-29 15:42:19 +0000 |
460 | @@ -1,8 +1,10 @@ |
461 | -# Copyright 2009-2011 Canonical Ltd. This software is licensed under the GNU |
462 | +# Copyright 2009-2017 Canonical Ltd. This software is licensed under the GNU |
463 | # Affero General Public License version 3 (see the file LICENSE). |
464 | |
465 | __all__ = [ |
466 | + 'InProcessKeyServerFixture', |
467 | 'KeyServerTac', |
468 | ] |
469 | |
470 | from lp.testing.keyserver.harness import KeyServerTac |
471 | +from lp.testing.keyserver.inprocess import InProcessKeyServerFixture |
472 | |
473 | === added file 'lib/lp/testing/keyserver/inprocess.py' |
474 | --- lib/lp/testing/keyserver/inprocess.py 1970-01-01 00:00:00 +0000 |
475 | +++ lib/lp/testing/keyserver/inprocess.py 2017-04-29 15:42:19 +0000 |
476 | @@ -0,0 +1,69 @@ |
477 | +# Copyright 2017 Canonical Ltd. This software is licensed under the |
478 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
479 | + |
480 | +"""In-process keyserver fixture.""" |
481 | + |
482 | +from __future__ import absolute_import, print_function, unicode_literals |
483 | + |
484 | +__metaclass__ = type |
485 | +__all__ = [ |
486 | + 'InProcessKeyServerFixture', |
487 | + ] |
488 | + |
489 | +from textwrap import dedent |
490 | + |
491 | +from fixtures import ( |
492 | + Fixture, |
493 | + TempDir, |
494 | + ) |
495 | +from twisted.internet import ( |
496 | + defer, |
497 | + endpoints, |
498 | + reactor, |
499 | + ) |
500 | +from twisted.python.compat import nativeString |
501 | +from twisted.web import server |
502 | + |
503 | +from lp.services.config import config |
504 | +from lp.testing.keyserver.web import KeyServerResource |
505 | + |
506 | + |
507 | +class InProcessKeyServerFixture(Fixture): |
508 | + """A fixture that runs an in-process key server. |
509 | + |
510 | + This is much faster than the out-of-process `KeyServerTac`, but it can |
511 | + only be used if all the tests relying on it are asynchronous. |
512 | + |
513 | + Users of this fixture must call the `start` method, which returns a |
514 | + `Deferred`, and arrange for that to get back to the reactor. This is |
515 | + necessary because the basic fixture API does not allow `setUp` to return |
516 | + anything. For example: |
517 | + |
518 | + class TestSomething(TestCase): |
519 | + |
520 | + run_tests_with = AsynchronousDeferredRunTest.make_factory( |
521 | + timeout=10) |
522 | + |
523 | + @defer.inlineCallbacks |
524 | + def setUp(self): |
525 | + super(TestSomething, self).setUp() |
526 | + yield self.useFixture(InProcessKeyServerFixture()).start() |
527 | + """ |
528 | + |
529 | + @defer.inlineCallbacks |
530 | + def start(self): |
531 | + resource = KeyServerResource(self.useFixture(TempDir()).path) |
532 | + endpoint = endpoints.serverFromString(reactor, nativeString("tcp:0")) |
533 | + port = yield endpoint.listen(server.Site(resource)) |
534 | + self.addCleanup(port.stopListening) |
535 | + config.push("in-process-key-server-fixture", dedent(""" |
536 | + [gpghandler] |
537 | + port: %s |
538 | + """) % port.getHost().port) |
539 | + self.addCleanup(config.pop, "in-process-key-server-fixture") |
540 | + |
541 | + @property |
542 | + def url(self): |
543 | + """The URL that the web server will be running on.""" |
544 | + return ("http://%s:%d" % ( |
545 | + config.gpghandler.host, config.gpghandler.port)).encode("UTF-8") |
546 | |
547 | === added file 'lib/lp/testing/keyserver/tests/test_inprocess.py' |
548 | --- lib/lp/testing/keyserver/tests/test_inprocess.py 1970-01-01 00:00:00 +0000 |
549 | +++ lib/lp/testing/keyserver/tests/test_inprocess.py 2017-04-29 15:42:19 +0000 |
550 | @@ -0,0 +1,44 @@ |
551 | +# Copyright 2017 Canonical Ltd. This software is licensed under the |
552 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
553 | + |
554 | +"""In-process keyserver fixture tests.""" |
555 | + |
556 | +from __future__ import absolute_import, print_function, unicode_literals |
557 | + |
558 | +__metaclass__ = type |
559 | + |
560 | +from testtools.deferredruntest import ( |
561 | + AsynchronousDeferredRunTestForBrokenTwisted, |
562 | + ) |
563 | +from twisted.internet import defer |
564 | +from twisted.web.client import getPage |
565 | + |
566 | +from lp.services.config import config |
567 | +from lp.testing import TestCase |
568 | +from lp.testing.keyserver import InProcessKeyServerFixture |
569 | +from lp.testing.keyserver.web import GREETING |
570 | + |
571 | + |
572 | +class TestInProcessKeyServerFixture(TestCase): |
573 | + |
574 | + run_tests_with = AsynchronousDeferredRunTestForBrokenTwisted.make_factory( |
575 | + timeout=10) |
576 | + |
577 | + @defer.inlineCallbacks |
578 | + def test_url(self): |
579 | + # The url is the one that gpghandler is configured to hit. |
580 | + fixture = self.useFixture(InProcessKeyServerFixture()) |
581 | + yield fixture.start() |
582 | + self.assertEqual( |
583 | + ("http://%s:%d" % ( |
584 | + config.gpghandler.host, |
585 | + config.gpghandler.port)).encode("UTF-8"), |
586 | + fixture.url) |
587 | + |
588 | + @defer.inlineCallbacks |
589 | + def test_starts_properly(self): |
590 | + # The fixture starts properly and we can load the page. |
591 | + fixture = self.useFixture(InProcessKeyServerFixture()) |
592 | + yield fixture.start() |
593 | + content = yield getPage(fixture.url) |
594 | + self.assertEqual(GREETING, content) |