Merge ~cjwatson/launchpad:remove-lp-testing-run-script into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 73ee6eb63e28166a23a7216a6d272dfde9f26b8d
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:remove-lp-testing-run-script
Merge into: launchpad:master
Diff against target: 711 lines (+161/-114)
15 files modified
lib/lp/answers/tests/test_questionjob.py (+10/-5)
lib/lp/archivepublisher/tests/test_publish_ftpmaster.py (+5/-2)
lib/lp/codehosting/scripts/tests/test_upgrade_all_branches.py (+9/-6)
lib/lp/registry/tests/test_distributionmirror_prober.py (+17/-7)
lib/lp/registry/tests/test_membership_notification_job.py (+10/-9)
lib/lp/registry/tests/test_person_merge_job.py (+10/-4)
lib/lp/registry/tests/test_productjob.py (+10/-5)
lib/lp/registry/tests/test_sharingjob.py (+10/-9)
lib/lp/services/scripts/tests/test_all_scripts.py (+3/-3)
lib/lp/soyuz/tests/test_packagecopyjob.py (+7/-4)
lib/lp/soyuz/tests/test_packagediffjob.py (+10/-4)
lib/lp/soyuz/tests/test_packagetranslationsuploadjob.py (+10/-9)
lib/lp/soyuz/tests/test_processacceptedbugsjob.py (+8/-4)
lib/lp/testing/__init__.py (+2/-34)
lib/lp/testing/script.py (+40/-9)
Reviewer Review Type Date Requested Status
Guruprasad Approve
Review via email: mp+436843@code.launchpad.net

Commit message

Remove lp.testing.run_script

Description of the change

`lp.testing.script.run_script` has a better API, since it expects arguments as a list rather than embedded in a string that's passed to a shell. I made some small adjustments to give us the union of the good bits of both functions.

To post a comment you must log in.
Revision history for this message
Guruprasad (lgp171188) wrote :

LGTM 👍

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/answers/tests/test_questionjob.py b/lib/lp/answers/tests/test_questionjob.py
2index 214b83a..3c3a7f7 100644
3--- a/lib/lp/answers/tests/test_questionjob.py
4+++ b/lib/lp/answers/tests/test_questionjob.py
5@@ -3,6 +3,8 @@
6
7 """Tests for QuestionJobs classes."""
8
9+import os
10+
11 import transaction
12 from testtools.content import text_content
13 from zope.component import getUtility
14@@ -26,9 +28,10 @@ from lp.services.mail import stub
15 from lp.services.mail.sendmail import format_address, format_address_for_person
16 from lp.services.scripts import log
17 from lp.services.worlddata.interfaces.language import ILanguageSet
18-from lp.testing import TestCaseWithFactory, person_logged_in, run_script
19+from lp.testing import TestCaseWithFactory, person_logged_in
20 from lp.testing.dbuser import dbuser
21 from lp.testing.layers import CeleryJobLayer, DatabaseFunctionalLayer
22+from lp.testing.script import run_script
23
24
25 class QuestionJobTestCase(TestCaseWithFactory):
26@@ -352,9 +355,12 @@ class QuestionEmailJobTestCase(TestCaseWithFactory):
27 question.target.addAnswerContact(user, user)
28 transaction.commit()
29
30- out, err, exit_code = run_script(
31- "LP_DEBUG_SQL=1 cronscripts/process-job-source.py -vv %s"
32- % (IQuestionEmailJobSource.getName())
33+ env = os.environ.copy()
34+ env["LP_DEBUG_SQL"] = "1"
35+ exit_code, out, err = run_script(
36+ "cronscripts/process-job-source.py",
37+ args=["-vv", IQuestionEmailJobSource.getName()],
38+ env=env,
39 )
40 self.addDetail("stdout", text_content(out))
41 self.addDetail("stderr", text_content(err))
42@@ -372,7 +378,6 @@ class QuestionEmailJobTestCase(TestCaseWithFactory):
43
44
45 class TestViaCelery(TestCaseWithFactory):
46-
47 layer = CeleryJobLayer
48
49 def test_run(self):
50diff --git a/lib/lp/archivepublisher/tests/test_publish_ftpmaster.py b/lib/lp/archivepublisher/tests/test_publish_ftpmaster.py
51index 5f686ad..770c667 100644
52--- a/lib/lp/archivepublisher/tests/test_publish_ftpmaster.py
53+++ b/lib/lp/archivepublisher/tests/test_publish_ftpmaster.py
54@@ -45,9 +45,10 @@ from lp.soyuz.enums import (
55 PackageUploadCustomFormat,
56 )
57 from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
58-from lp.testing import TestCase, TestCaseWithFactory, run_script
59+from lp.testing import TestCase, TestCaseWithFactory
60 from lp.testing.fakemethod import FakeMethod
61 from lp.testing.layers import LaunchpadZopelessLayer
62+from lp.testing.script import run_script
63
64
65 def path_exists(*path_components):
66@@ -229,7 +230,9 @@ class TestPublishFTPMasterScript(
67 def test_script_runs_successfully(self):
68 self.prepareUbuntu()
69 self.layer.txn.commit()
70- stdout, stderr, retval = run_script(self.SCRIPT_PATH + " -d ubuntu")
71+ retval, stdout, stderr = run_script(
72+ self.SCRIPT_PATH, args=["-d", "ubuntu"]
73+ )
74 self.assertEqual(0, retval, "Script failure:\n" + stderr)
75
76 def test_getConfigs_maps_distro_and_purpose_to_matching_config(self):
77diff --git a/lib/lp/codehosting/scripts/tests/test_upgrade_all_branches.py b/lib/lp/codehosting/scripts/tests/test_upgrade_all_branches.py
78index 87752a6..fe9590e 100644
79--- a/lib/lp/codehosting/scripts/tests/test_upgrade_all_branches.py
80+++ b/lib/lp/codehosting/scripts/tests/test_upgrade_all_branches.py
81@@ -12,8 +12,9 @@ from fixtures import TempDir
82 from lp.code.bzr import branch_changed
83 from lp.codehosting.upgrade import Upgrader
84 from lp.services.config import config
85-from lp.testing import TestCaseWithFactory, person_logged_in, run_script
86+from lp.testing import TestCaseWithFactory, person_logged_in
87 from lp.testing.layers import AppServerLayer
88+from lp.testing.script import run_script
89
90
91 class TestUpgradeAllBranchesScript(TestCaseWithFactory):
92@@ -29,11 +30,13 @@ class TestUpgradeAllBranchesScript(TestCaseWithFactory):
93 """Run the script to upgrade all branches."""
94 transaction.commit()
95 if finish:
96- flags = " --finish "
97+ flags = ["--finish"]
98 else:
99- flags = " "
100+ flags = []
101 return run_script(
102- "scripts/upgrade_all_branches.py" + flags + target, cwd=self.cwd
103+ "scripts/upgrade_all_branches.py",
104+ args=flags + [target],
105+ cwd=self.cwd,
106 )
107
108 def prepare(self):
109@@ -52,7 +55,7 @@ class TestUpgradeAllBranchesScript(TestCaseWithFactory):
110 def test_start_upgrade(self):
111 """Test that starting the upgrade behaves as expected."""
112 upgrader = self.prepare()
113- stdout, stderr, retcode = self.upgrade_all_branches(
114+ retcode, stdout, stderr = self.upgrade_all_branches(
115 upgrader.target_dir
116 )
117 self.assertIn(
118@@ -68,7 +71,7 @@ class TestUpgradeAllBranchesScript(TestCaseWithFactory):
119 """Test that finishing the upgrade behaves as expected."""
120 upgrader = self.prepare()
121 upgrader.start_upgrade()
122- stdout, stderr, retcode = self.upgrade_all_branches(
123+ retcode, stdout, stderr = self.upgrade_all_branches(
124 upgrader.target_dir, finish=True
125 )
126 self.assertIn(
127diff --git a/lib/lp/registry/tests/test_distributionmirror_prober.py b/lib/lp/registry/tests/test_distributionmirror_prober.py
128index 11cbc98..4b4203f 100644
129--- a/lib/lp/registry/tests/test_distributionmirror_prober.py
130+++ b/lib/lp/registry/tests/test_distributionmirror_prober.py
131@@ -84,13 +84,13 @@ from lp.testing import (
132 TestCaseWithFactory,
133 admin_logged_in,
134 clean_up_reactor,
135- run_script,
136 )
137 from lp.testing.layers import (
138 LaunchpadZopelessLayer,
139 TwistedLayer,
140 ZopelessDatabaseLayer,
141 )
142+from lp.testing.script import run_script
143
144
145 class HTTPServerTestSetup(TacTestSetup):
146@@ -1324,9 +1324,14 @@ class TestDistroMirrorProberFunctional(TestCaseWithFactory):
147 mirror = self.makeMirror(content_type=MirrorContent.RELEASE)
148 transaction.commit()
149
150- out, err, exit_code = run_script(
151- "cronscripts/distributionmirror-prober.py --no-remote-hosts "
152- "--content-type=cdimage --no-owner-notification --force"
153+ exit_code, out, err = run_script(
154+ "cronscripts/distributionmirror-prober.py",
155+ args=[
156+ "--no-remote-hosts",
157+ "--content-type=cdimage",
158+ "--no-owner-notification",
159+ "--force",
160+ ],
161 )
162 self.assertEqual(0, exit_code, err)
163
164@@ -1376,9 +1381,14 @@ class TestDistroMirrorProberFunctional(TestCaseWithFactory):
165 )
166 transaction.commit()
167
168- out, err, exit_code = run_script(
169- "cronscripts/distributionmirror-prober.py --no-remote-hosts "
170- "--content-type=archive --no-owner-notification --force"
171+ exit_code, out, err = run_script(
172+ "cronscripts/distributionmirror-prober.py",
173+ args=[
174+ "--no-remote-hosts",
175+ "--content-type=archive",
176+ "--no-owner-notification",
177+ "--force",
178+ ],
179 )
180 self.assertEqual(0, exit_code, err)
181
182diff --git a/lib/lp/registry/tests/test_membership_notification_job.py b/lib/lp/registry/tests/test_membership_notification_job.py
183index ef9d7e4..9becfe6 100644
184--- a/lib/lp/registry/tests/test_membership_notification_job.py
185+++ b/lib/lp/registry/tests/test_membership_notification_job.py
186@@ -3,6 +3,8 @@
187
188 """Tests of `MembershipNotificationJob`."""
189
190+import os
191+
192 import transaction
193 from testtools.content import text_content
194 from zope.component import getUtility
195@@ -19,14 +21,10 @@ from lp.registry.model.persontransferjob import MembershipNotificationJob
196 from lp.services.features.testing import FeatureFixture
197 from lp.services.job.interfaces.job import JobStatus
198 from lp.services.job.tests import block_on_job, pop_remote_notifications
199-from lp.testing import (
200- TestCaseWithFactory,
201- login_person,
202- person_logged_in,
203- run_script,
204-)
205+from lp.testing import TestCaseWithFactory, login_person, person_logged_in
206 from lp.testing.layers import CeleryJobLayer, DatabaseFunctionalLayer
207 from lp.testing.sampledata import ADMIN_EMAIL
208+from lp.testing.script import run_script
209
210
211 class MembershipNotificationJobTest(TestCaseWithFactory):
212@@ -116,9 +114,12 @@ class MembershipNotificationJobTest(TestCaseWithFactory):
213 )
214 job_repr = repr(job)
215 transaction.commit()
216- out, err, exit_code = run_script(
217- "LP_DEBUG_SQL=1 cronscripts/process-job-source.py -vv %s"
218- % (IMembershipNotificationJobSource.getName())
219+ env = os.environ.copy()
220+ env["LP_DEBUG_SQL"] = "1"
221+ exit_code, out, err = run_script(
222+ "cronscripts/process-job-source.py",
223+ args=["-vv", IMembershipNotificationJobSource.getName()],
224+ env=env,
225 )
226 self.addDetail("stdout", text_content(out))
227 self.addDetail("stderr", text_content(err))
228diff --git a/lib/lp/registry/tests/test_person_merge_job.py b/lib/lp/registry/tests/test_person_merge_job.py
229index 1a39e6b..c536471 100644
230--- a/lib/lp/registry/tests/test_person_merge_job.py
231+++ b/lib/lp/registry/tests/test_person_merge_job.py
232@@ -3,6 +3,8 @@
233
234 """Tests of `PersonMergeJob`."""
235
236+import os
237+
238 import transaction
239 from testtools.content import text_content
240 from zope.component import getUtility
241@@ -23,9 +25,10 @@ from lp.services.job.tests import block_on_job
242 from lp.services.log.logger import BufferLogger
243 from lp.services.mail.sendmail import format_address_for_person
244 from lp.services.scripts import log
245-from lp.testing import TestCaseWithFactory, person_logged_in, run_script
246+from lp.testing import TestCaseWithFactory, person_logged_in
247 from lp.testing.dbuser import dbuser
248 from lp.testing.layers import CeleryJobLayer, DatabaseFunctionalLayer
249+from lp.testing.script import run_script
250
251
252 def create_job(factory):
253@@ -141,9 +144,12 @@ class TestPersonMergeJob(TestCaseWithFactory):
254 )
255 transaction.commit()
256
257- out, err, exit_code = run_script(
258- "LP_DEBUG_SQL=1 cronscripts/process-job-source.py -vv %s"
259- % (IPersonMergeJobSource.getName())
260+ env = os.environ.copy()
261+ env["LP_DEBUG_SQL"] = "1"
262+ exit_code, out, err = run_script(
263+ "cronscripts/process-job-source.py",
264+ args=["-vv", IPersonMergeJobSource.getName()],
265+ env=env,
266 )
267
268 self.addDetail("stdout", text_content(out))
269diff --git a/lib/lp/registry/tests/test_productjob.py b/lib/lp/registry/tests/test_productjob.py
270index 5de315e..bec594c 100644
271--- a/lib/lp/registry/tests/test_productjob.py
272+++ b/lib/lp/registry/tests/test_productjob.py
273@@ -3,6 +3,7 @@
274
275 """Tests for ProductJobs."""
276
277+import os
278 from datetime import datetime, timedelta, timezone
279
280 import transaction
281@@ -46,13 +47,14 @@ from lp.services.job.interfaces.job import JobStatus
282 from lp.services.log.logger import BufferLogger
283 from lp.services.propertycache import clear_property_cache
284 from lp.services.webapp.publisher import canonical_url
285-from lp.testing import TestCaseWithFactory, person_logged_in, run_script
286+from lp.testing import TestCaseWithFactory, person_logged_in
287 from lp.testing.layers import (
288 DatabaseFunctionalLayer,
289 LaunchpadZopelessLayer,
290 ZopelessAppServerLayer,
291 )
292 from lp.testing.mail_helpers import pop_notifications
293+from lp.testing.script import run_script
294
295
296 class CommercialHelpers:
297@@ -150,7 +152,7 @@ class DailyProductJobsTestCase(TestCaseWithFactory, CommercialHelpers):
298 # ProductJobManagerTestCase.test_createAllDailyJobs
299 self.make_test_products()
300 transaction.commit()
301- stdout, stderr, retcode = run_script(
302+ retcode, stdout, stderr = run_script(
303 "cronscripts/daily_product_jobs.py"
304 )
305 self.addDetail("stdout", text_content(stdout))
306@@ -621,9 +623,12 @@ class CommericialExpirationMixin(CommercialHelpers):
307 proprietary_job = self.JOB_CLASS.create(proprietary_product, reviewer)
308 transaction.commit()
309
310- out, err, exit_code = run_script(
311- "LP_DEBUG_SQL=1 cronscripts/process-job-source.py -vv %s"
312- % self.JOB_SOURCE_INTERFACE.getName()
313+ env = os.environ.copy()
314+ env["LP_DEBUG_SQL"] = "1"
315+ exit_code, out, err = run_script(
316+ "cronscripts/process-job-source.py",
317+ args=["-vv", self.JOB_SOURCE_INTERFACE.getName()],
318+ env=env,
319 )
320 self.addDetail("stdout", text_content(out))
321 self.addDetail("stderr", text_content(err))
322diff --git a/lib/lp/registry/tests/test_sharingjob.py b/lib/lp/registry/tests/test_sharingjob.py
323index e017e72..a088b02 100644
324--- a/lib/lp/registry/tests/test_sharingjob.py
325+++ b/lib/lp/registry/tests/test_sharingjob.py
326@@ -3,6 +3,8 @@
327
328 """Tests for SharingJobs."""
329
330+import os
331+
332 import transaction
333 from testtools.content import text_content
334 from zope.component import getUtility
335@@ -42,17 +44,13 @@ from lp.services.job.interfaces.job import JobStatus
336 from lp.services.job.tests import block_on_job
337 from lp.services.mail.sendmail import format_address_for_person
338 from lp.snappy.interfaces.snap import SNAP_TESTING_FLAGS
339-from lp.testing import (
340- TestCaseWithFactory,
341- login_person,
342- person_logged_in,
343- run_script,
344-)
345+from lp.testing import TestCaseWithFactory, login_person, person_logged_in
346 from lp.testing.layers import (
347 CeleryJobLayer,
348 DatabaseFunctionalLayer,
349 LaunchpadZopelessLayer,
350 )
351+from lp.testing.script import run_script
352
353
354 class SharingJobTestCase(TestCaseWithFactory):
355@@ -266,9 +264,12 @@ class TestRunViaCron(TestCaseWithFactory):
356 )
357 transaction.commit()
358
359- out, err, exit_code = run_script(
360- "LP_DEBUG_SQL=1 cronscripts/process-job-source.py -vv %s"
361- % (job_type)
362+ env = os.environ.copy()
363+ env["LP_DEBUG_SQL"] = "1"
364+ exit_code, out, err = run_script(
365+ "cronscripts/process-job-source.py",
366+ args=["-vv", job_type],
367+ env=env,
368 )
369 self.addDetail("stdout", text_content(out))
370 self.addDetail("stderr", text_content(err))
371diff --git a/lib/lp/services/scripts/tests/test_all_scripts.py b/lib/lp/services/scripts/tests/test_all_scripts.py
372index fc3be73..a5e770c 100644
373--- a/lib/lp/services/scripts/tests/test_all_scripts.py
374+++ b/lib/lp/services/scripts/tests/test_all_scripts.py
375@@ -10,7 +10,8 @@ from testscenarios import WithScenarios, load_tests_apply_scenarios
376 from testtools.matchers import DocTestMatches
377
378 from lp.services.scripts.tests import find_lp_scripts
379-from lp.testing import TestCase, run_script
380+from lp.testing import TestCase
381+from lp.testing.script import run_script
382
383
384 def make_id(script_path):
385@@ -27,8 +28,7 @@ class ScriptsTestCase(WithScenarios, TestCase):
386
387 def test_script(self):
388 # Run self.script_path with '-h' to make sure it runs cleanly.
389- cmd_line = self.script_path + " -h"
390- out, err, returncode = run_script(cmd_line)
391+ returncode, out, err = run_script(self.script_path, args=["-h"])
392 self.assertThat(err, DocTestMatches("", doctest.REPORT_NDIFF))
393 self.assertEqual("", err)
394 self.assertEqual(os.EX_OK, returncode)
395diff --git a/lib/lp/soyuz/tests/test_packagecopyjob.py b/lib/lp/soyuz/tests/test_packagecopyjob.py
396index f4d2e53..c0f3a85 100644
397--- a/lib/lp/soyuz/tests/test_packagecopyjob.py
398+++ b/lib/lp/soyuz/tests/test_packagecopyjob.py
399@@ -63,7 +63,6 @@ from lp.testing import (
400 TestCaseWithFactory,
401 admin_logged_in,
402 person_logged_in,
403- run_script,
404 verifyObject,
405 )
406 from lp.testing.dbuser import dbuser, switch_dbuser
407@@ -76,6 +75,7 @@ from lp.testing.layers import (
408 )
409 from lp.testing.mail_helpers import pop_notifications
410 from lp.testing.matchers import Provides
411+from lp.testing.script import run_script
412
413
414 def get_dsd_comments(dsd):
415@@ -726,9 +726,12 @@ class PlainPackageCopyJobTests(TestCaseWithFactory, LocalTestHelper):
416 archive2.newComponentUploader(requester, "main")
417 transaction.commit()
418
419- out, err, exit_code = run_script(
420- "LP_DEBUG_SQL=1 cronscripts/process-job-source.py -vv %s"
421- % (IPlainPackageCopyJobSource.getName())
422+ env = os.environ.copy()
423+ env["LP_DEBUG_SQL"] = "1"
424+ exit_code, out, err = run_script(
425+ "cronscripts/process-job-source.py",
426+ args=["-vv", IPlainPackageCopyJobSource.getName()],
427+ env=env,
428 )
429
430 self.addDetail("stdout", text_content(out))
431diff --git a/lib/lp/soyuz/tests/test_packagediffjob.py b/lib/lp/soyuz/tests/test_packagediffjob.py
432index b3d9b2c..54c5a65 100644
433--- a/lib/lp/soyuz/tests/test_packagediffjob.py
434+++ b/lib/lp/soyuz/tests/test_packagediffjob.py
435@@ -1,6 +1,8 @@
436 # Copyright 2013-2018 Canonical Ltd. This software is licensed under the
437 # GNU Affero General Public License version 3 (see the file LICENSE).
438
439+import os
440+
441 import transaction
442 from testtools.content import text_content
443 from zope.component import getUtility
444@@ -18,9 +20,10 @@ from lp.soyuz.interfaces.packagediffjob import (
445 )
446 from lp.soyuz.model.packagediffjob import PackageDiffJob
447 from lp.soyuz.tests.test_packagediff import create_proper_job
448-from lp.testing import TestCaseWithFactory, run_script, verifyObject
449+from lp.testing import TestCaseWithFactory, verifyObject
450 from lp.testing.fakemethod import FakeMethod
451 from lp.testing.layers import CeleryJobLayer, LaunchpadZopelessLayer
452+from lp.testing.script import run_script
453
454
455 class TestPackageDiffJob(TestCaseWithFactory):
456@@ -76,9 +79,12 @@ class TestPackageDiffJob(TestCaseWithFactory):
457 def test_smoke(self):
458 diff = create_proper_job(self.factory)
459 transaction.commit()
460- out, err, exit_code = run_script(
461- "LP_DEBUG_SQL=1 cronscripts/process-job-source.py -vv %s"
462- % (IPackageDiffJobSource.getName())
463+ env = os.environ.copy()
464+ env["LP_DEBUG_SQL"] = "1"
465+ exit_code, out, err = run_script(
466+ "cronscripts/process-job-source.py",
467+ args=["-vv", IPackageDiffJobSource.getName()],
468+ env=env,
469 )
470
471 self.addDetail("stdout", text_content(out))
472diff --git a/lib/lp/soyuz/tests/test_packagetranslationsuploadjob.py b/lib/lp/soyuz/tests/test_packagetranslationsuploadjob.py
473index 6564fe4..650f39d 100644
474--- a/lib/lp/soyuz/tests/test_packagetranslationsuploadjob.py
475+++ b/lib/lp/soyuz/tests/test_packagetranslationsuploadjob.py
476@@ -1,6 +1,8 @@
477 # Copyright 2013-2018 Canonical Ltd. This software is licensed under the
478 # GNU Affero General Public License version 3 (see the file LICENSE).
479
480+import os
481+
482 import transaction
483 from testtools.content import text_content
484 from zope.component import getUtility
485@@ -18,15 +20,11 @@ from lp.soyuz.interfaces.packagetranslationsuploadjob import (
486 from lp.soyuz.model.packagetranslationsuploadjob import (
487 PackageTranslationsUploadJob,
488 )
489-from lp.testing import (
490- TestCaseWithFactory,
491- person_logged_in,
492- run_script,
493- verifyObject,
494-)
495+from lp.testing import TestCaseWithFactory, person_logged_in, verifyObject
496 from lp.testing.dbuser import dbuser
497 from lp.testing.fakemethod import FakeMethod
498 from lp.testing.layers import CeleryJobLayer, LaunchpadZopelessLayer
499+from lp.testing.script import run_script
500 from lp.translations.interfaces.translationimportqueue import (
501 ITranslationImportQueue,
502 )
503@@ -132,9 +130,12 @@ class TestPackageTranslationsUploadJob(LocalTestHelper):
504 }
505 spr, sp, job = self.makeJob(tar_content=tar_content)
506 transaction.commit()
507- out, err, exit_code = run_script(
508- "LP_DEBUG_SQL=1 cronscripts/process-job-source.py -vv %s"
509- % (IPackageTranslationsUploadJobSource.getName())
510+ env = os.environ.copy()
511+ env["LP_DEBUG_SQL"] = "1"
512+ exit_code, out, err = run_script(
513+ "cronscripts/process-job-source.py",
514+ args=["-vv", IPackageTranslationsUploadJobSource.getName()],
515+ env=env,
516 )
517
518 self.addDetail("stdout", text_content(out))
519diff --git a/lib/lp/soyuz/tests/test_processacceptedbugsjob.py b/lib/lp/soyuz/tests/test_processacceptedbugsjob.py
520index 6ed8b1d..f2e29bf 100644
521--- a/lib/lp/soyuz/tests/test_processacceptedbugsjob.py
522+++ b/lib/lp/soyuz/tests/test_processacceptedbugsjob.py
523@@ -4,6 +4,7 @@
524 """Tests for jobs to close bugs for accepted package uploads."""
525
526 import io
527+import os
528 from itertools import product
529 from textwrap import dedent
530
531@@ -38,7 +39,6 @@ from lp.testing import (
532 TestCaseWithFactory,
533 celebrity_logged_in,
534 person_logged_in,
535- run_script,
536 verifyObject,
537 )
538 from lp.testing.fakemethod import FakeMethod
539@@ -47,6 +47,7 @@ from lp.testing.layers import (
540 DatabaseFunctionalLayer,
541 LaunchpadZopelessLayer,
542 )
543+from lp.testing.script import run_script
544
545
546 class TestBugIDsFromChangesFile(TestCaseWithFactory):
547@@ -447,9 +448,12 @@ class TestProcessAcceptedBugsJob(TestCaseWithFactory):
548 self.makeJob(spr=spr, bug_ids=[bug.id])
549 transaction.commit()
550
551- out, err, exit_code = run_script(
552- "LP_DEBUG_SQL=1 cronscripts/process-job-source.py -vv %s"
553- % (IProcessAcceptedBugsJobSource.getName())
554+ env = os.environ.copy()
555+ env["LP_DEBUG_SQL"] = "1"
556+ exit_code, out, err = run_script(
557+ "cronscripts/process-job-source.py",
558+ args=["-vv", IProcessAcceptedBugsJobSource.getName()],
559+ env=env,
560 )
561
562 self.addDetail("stdout", text_content(out))
563diff --git a/lib/lp/testing/__init__.py b/lib/lp/testing/__init__.py
564index 7bf98a4..bde4117 100644
565--- a/lib/lp/testing/__init__.py
566+++ b/lib/lp/testing/__init__.py
567@@ -33,7 +33,6 @@ __all__ = [
568 "record_statements",
569 "reset_logging",
570 "run_process",
571- "run_script",
572 "run_with_login",
573 "run_with_storm_debug",
574 "RunIsolatedTest",
575@@ -1366,42 +1365,11 @@ def time_counter(origin=None, delta=timedelta(seconds=5)):
576 now += delta
577
578
579-def run_script(cmd_line, env=None, cwd=None, universal_newlines=True):
580- """Run the given command line as a subprocess.
581-
582- :param cmd_line: A command line suitable for passing to
583- `subprocess.Popen`.
584- :param env: An optional environment dict. If none is given, the
585- script will get a copy of your present environment. Either way,
586- PYTHONPATH will be removed from it because it will break the
587- script.
588- :param universal_newlines: If True, return stdout and stderr as text.
589- Defaults to True.
590- :return: A 3-tuple of stdout, stderr, and the process' return code.
591- """
592- if env is None:
593- env = os.environ.copy()
594- env.pop("PYTHONPATH", None)
595- process = subprocess.Popen(
596- cmd_line,
597- shell=True,
598- stdin=subprocess.PIPE,
599- stdout=subprocess.PIPE,
600- stderr=subprocess.PIPE,
601- env=env,
602- cwd=cwd,
603- universal_newlines=universal_newlines,
604- )
605- (out, err) = process.communicate()
606- return out, err, process.returncode
607-
608-
609 def run_process(cmd, env=None, universal_newlines=True):
610 """Run the given command as a subprocess.
611
612- This differs from `run_script` in that it does not execute via a shell and
613- it explicitly connects stdin to /dev/null so that processes will not be
614- able to hang, waiting for user input.
615+ This explicitly connects stdin to /dev/null so that processes will not
616+ be able to hang, waiting for user input.
617
618 :param cmd_line: A command suitable for passing to `subprocess.Popen`.
619 :param env: An optional environment dict. If none is given, the script
620diff --git a/lib/lp/testing/script.py b/lib/lp/testing/script.py
621index ee010dc..4f4e5e9 100644
622--- a/lib/lp/testing/script.py
623+++ b/lib/lp/testing/script.py
624@@ -8,16 +8,28 @@ __all__ = [
625 "run_script",
626 ]
627
628+import os
629 import subprocess
630-import sys
631+from typing import Dict, List, Optional, Union
632
633
634-def run_command(command, args=None, input=None, universal_newlines=True):
635+# XXX cjwatson 2023-02-03: This type could be stricter: the type of `input`
636+# depends on the value of `universal_newlines`.
637+def run_command(
638+ command: str,
639+ args: Optional[List[str]] = None,
640+ env: Optional[Dict[str, str]] = None,
641+ cwd: Optional[str] = None,
642+ input: Optional[Union[bytes, str]] = None,
643+ universal_newlines: bool = True,
644+):
645 """Run an external command in a separate process.
646
647 :param command: executable to run.
648 :param args: optional list of command-line arguments.
649 :param input: optional text to feed to command's standard input.
650+ :param env: optional, passed to `subprocess.Popen`.
651+ :param cwd: optional, passed to `subprocess.Popen`.
652 :param universal_newlines: passed to `subprocess.Popen`, defaulting to
653 True.
654 :return: tuple of returncode, standard output, and standard error.
655@@ -35,6 +47,8 @@ def run_command(command, args=None, input=None, universal_newlines=True):
656 stdin=stdin,
657 stdout=subprocess.PIPE,
658 stderr=subprocess.PIPE,
659+ env=env,
660+ cwd=cwd,
661 universal_newlines=universal_newlines,
662 )
663 stdout, stderr = child.communicate(input)
664@@ -42,23 +56,40 @@ def run_command(command, args=None, input=None, universal_newlines=True):
665 return (returncode, stdout, stderr)
666
667
668-def run_script(script, args=None, input=None, universal_newlines=True):
669+# XXX cjwatson 2023-02-03: This type could be stricter: the type of `input`
670+# depends on the value of `universal_newlines`.
671+def run_script(
672+ script: str,
673+ args: Optional[List[str]] = None,
674+ env: Optional[Dict[str, str]] = None,
675+ cwd: Optional[str] = None,
676+ input: Optional[Union[bytes, str]] = None,
677+ universal_newlines: bool = True,
678+):
679 """Run a Python script in a child process, using current interpreter.
680
681 :param script: Python script to run.
682 :param args: optional list of command-line arguments.
683+ :param env: optional environment dict; if none is given, the script will
684+ get a copy of the environment of the calling process. In either
685+ case, `PYTHONPATH` is removed since inheriting it may break some
686+ scripts.
687+ :param env: optional, passed to `subprocess.Popen`.
688+ :param cwd: optional, passed to `subprocess.Popen`.
689 :param input: optional string to feed to standard input.
690 :param universal_newlines: passed to `subprocess.Popen`, defaulting to
691 True.
692 :return: tuple of return value, standard output, and standard error.
693 """
694- interpreter_args = [script]
695- if args:
696- interpreter_args.extend(args)
697+ if env is None:
698+ env = os.environ.copy()
699+ env.pop("PYTHONPATH", None)
700
701 return run_command(
702- sys.executable,
703- interpreter_args,
704- input,
705+ script,
706+ args=args,
707+ env=env,
708+ cwd=cwd,
709+ input=input,
710 universal_newlines=universal_newlines,
711 )

Subscribers

People subscribed via source and target branches

to status/vote changes: