Merge lp:~jml/launchpad/branch-sample-data-unit-tests into lp:launchpad

Proposed by Jonathan Lange
Status: Merged
Approved by: Robert Collins
Approved revision: no longer in the source branch.
Merged at revision: 11124
Proposed branch: lp:~jml/launchpad/branch-sample-data-unit-tests
Merge into: lp:launchpad
Prerequisite: lp:~jml/launchpad/more-login-helpers
Diff against target: 696 lines (+159/-132)
9 files modified
database/schema/Makefile (+2/-2)
lib/canonical/launchpad/scripts/tests/test_garbo.py (+8/-1)
lib/canonical/launchpad/tests/test_launchpadlib.py (+13/-10)
lib/lp/code/browser/tests/test_branch.py (+9/-16)
lib/lp/code/interfaces/codeimportjob.py (+0/-2)
lib/lp/code/model/tests/test_codeimportjob.py (+67/-96)
lib/lp/testing/factory.py (+8/-5)
lib/lp/testing/sampledata.py (+18/-0)
lib/lp/testing/tests/test_factory.py (+34/-0)
To merge this branch: bzr merge lp:~jml/launchpad/branch-sample-data-unit-tests
Reviewer Review Type Date Requested Status
Robert Collins (community) Approve
Review via email: mp+29652@code.launchpad.net

Commit message

Fix some unit tests to not need sample data. Add "sampledata" module and tests for Launchpad object factory.

Description of the change

This branch fixes up a bunch of unit tests to not use sample data.

The tests that I've changed are tests that would fail if all branch-related sample data were removed.

There's also a new "lp.testing.sampledata" module. The idea is that rather than using magic literal strings or numbers, we define constants in the file. Doing so also makes it much easier to statically analyze the code-base to find tests that use sampledata.

I have also used this branch as an opportunity to start testing the Launchpad object factory. I haven't written complete tests, but I have written tests to cover the changes I made. Now that tests exists, I suggest that we insist on tests for any changes made to the factory.

There are some incidental cleanups:
  * Change the sampledata header to have the correct copyright date, and change the Makefile to generate the correct copyright date.
  * Many tests changed to use DatabaseFunctionalLayer instead of LaunchpadFunctionalLayer
  * Removed "verifyObject" from the lp.testing namespace. I have no idea why it was there in the first place.

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote :

I think this is useful; thanks for doing it.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'database/schema/Makefile'
2--- database/schema/Makefile 2010-03-26 07:37:50 +0000
3+++ database/schema/Makefile 2010-07-13 10:02:50 +0000
4@@ -1,4 +1,4 @@
5-# Copyright 2009 Canonical Ltd. This software is licensed under the
6+# Copyright 2010 Canonical Ltd. This software is licensed under the
7 # GNU Affero General Public License version 3 (see the file LICENSE).
8 #
9 # Quick hack makefile to (re)create the Launchpad database.
10@@ -42,7 +42,7 @@
11 # The command we use to drop (if exists) and recreate a database.
12 CREATEDB=${PYTHON} ../../utilities/pgmassacre.py -t
13
14-HEADER="-- Copyright 2009 Canonical Ltd. This software is licensed under \
15+HEADER="-- Copyright 2010 Canonical Ltd. This software is licensed under \
16 the\n-- GNU Affero General Public License version 3 (see the file \
17 LICENSE)."
18
19
20=== modified file 'lib/canonical/launchpad/scripts/tests/test_garbo.py'
21--- lib/canonical/launchpad/scripts/tests/test_garbo.py 2010-05-26 01:48:12 +0000
22+++ lib/canonical/launchpad/scripts/tests/test_garbo.py 2010-07-13 10:02:50 +0000
23@@ -175,11 +175,18 @@
24 results_to_keep_count = (
25 config.codeimport.consecutive_failure_limit - 1)
26
27+ LaunchpadZopelessLayer.switchDbUser('testadmin')
28+ code_import_id = self.factory.makeCodeImport().id
29+ machine_id = self.factory.makeCodeImportMachine().id
30+ requester_id = self.factory.makePerson().id
31+ transaction.commit()
32+
33 def new_code_import_result(timestamp):
34 LaunchpadZopelessLayer.switchDbUser('testadmin')
35 CodeImportResult(
36 date_created=timestamp,
37- code_importID=1, machineID=1, requesting_userID=1,
38+ code_importID=code_import_id, machineID=machine_id,
39+ requesting_userID=requester_id,
40 status=CodeImportResultStatus.FAILURE,
41 date_job_started=timestamp)
42 transaction.commit()
43
44=== modified file 'lib/canonical/launchpad/tests/test_launchpadlib.py'
45--- lib/canonical/launchpad/tests/test_launchpadlib.py 2009-06-25 05:30:52 +0000
46+++ lib/canonical/launchpad/tests/test_launchpadlib.py 2010-07-13 10:02:50 +0000
47@@ -5,22 +5,22 @@
48
49 import unittest
50
51+import transaction
52+
53 from launchpadlib.testing.helpers import salgado_with_full_permissions
54 from canonical.testing import AppServerLayer
55-
56-
57-class TestLaunchpadLib(unittest.TestCase):
58+from lp.testing import TestCaseWithFactory
59+
60+
61+class TestLaunchpadLib(TestCaseWithFactory):
62 """Tests for the launchpadlib client for the REST API."""
63
64 layer = AppServerLayer
65- launchpad = None
66- project = None
67
68 def setUp(self):
69- if self.launchpad is None:
70- self.launchpad = salgado_with_full_permissions.login()
71- if self.project is None:
72- self.project = self.launchpad.projects['firefox']
73+ super(TestLaunchpadLib, self).setUp()
74+ self.launchpad = salgado_with_full_permissions.login()
75+ self.project = self.launchpad.projects['firefox']
76
77 def verifyAttributes(self, element):
78 """Verify that launchpadlib can parse the element's attributes."""
79@@ -43,7 +43,10 @@
80
81 def test_branch(self):
82 """Test branch attributes."""
83- branch = self.project.getBranches()[0]
84+ branch_name = self.factory.makeBranch().unique_name
85+ transaction.commit()
86+ branch = self.launchpad.branches.getByUniqueName(
87+ unique_name=branch_name)
88 self.verifyAttributes(branch)
89
90 def test_milestone(self):
91
92=== modified file 'lib/lp/code/browser/tests/test_branch.py'
93--- lib/lp/code/browser/tests/test_branch.py 2010-06-14 02:37:06 +0000
94+++ lib/lp/code/browser/tests/test_branch.py 2010-07-13 10:02:50 +0000
95@@ -6,7 +6,6 @@
96 from __future__ import with_statement
97
98 __metaclass__ = type
99-__all__ = ['TestBranchView', 'test_suite']
100
101 from datetime import datetime, timedelta
102 from textwrap import dedent
103@@ -16,7 +15,6 @@
104 import simplejson
105
106
107-from zope.component import getUtility
108 from zope.security.proxy import removeSecurityProxy
109
110 from canonical.config import config
111@@ -32,9 +30,6 @@
112 from lp.code.interfaces.branchtarget import IBranchTarget
113 from canonical.launchpad.helpers import truncate_text
114 from lp.code.enums import BranchLifecycleStatus, BranchType
115-from lp.registry.interfaces.person import IPersonSet
116-from lp.registry.interfaces.product import IProductSet
117-from lp.code.interfaces.branchlookup import IBranchLookup
118 from lp.testing import (
119 login, login_person, logout, person_logged_in, ANONYMOUS,
120 TestCaseWithFactory)
121@@ -122,20 +117,18 @@
122
123 class TestBranchView(TestCaseWithFactory):
124
125- layer = LaunchpadFunctionalLayer
126+ layer = DatabaseFunctionalLayer
127
128 def setUp(self):
129 super(TestBranchView, self).setUp()
130- login(ANONYMOUS)
131 self.request = LaunchpadTestRequest()
132
133- def tearDown(self):
134- logout()
135- super(TestBranchView, self).tearDown()
136-
137 def testMirrorStatusMessageIsTruncated(self):
138 """mirror_status_message is truncated if the text is overly long."""
139- branch = getUtility(IBranchLookup).get(28)
140+ branch = self.factory.makeBranch()
141+ branch.mirrorFailed(
142+ "on quick brown fox the dog jumps to" *
143+ BranchMirrorStatusView.MAXIMUM_STATUS_MESSAGE_LENGTH)
144 branch_view = BranchMirrorStatusView(branch, self.request)
145 self.assertEqual(
146 truncate_text(branch.mirror_status_message,
147@@ -144,7 +137,7 @@
148
149 def testMirrorStatusMessage(self):
150 """mirror_status_message on the view is the same as on the branch."""
151- branch = getUtility(IBranchLookup).get(5)
152+ branch = self.factory.makeBranch()
153 branch.mirrorFailed("This is a short error message.")
154 branch_view = BranchMirrorStatusView(branch, self.request)
155 self.assertTrue(
156@@ -160,8 +153,8 @@
157
158 def testBranchAddRequestsMirror(self):
159 """Registering a mirrored branch requests a mirror."""
160- arbitrary_person = getUtility(IPersonSet).get(1)
161- arbitrary_product = getUtility(IProductSet).get(1)
162+ arbitrary_person = self.factory.makePerson()
163+ arbitrary_product = self.factory.makeProduct()
164 login(arbitrary_person.preferredemail.email)
165 try:
166 add_view = BranchAddView(arbitrary_person, self.request)
167@@ -195,7 +188,7 @@
168 # The merge links are shown on projects that have multiple branches.
169 product = self.factory.makeProduct(name='super-awesome-project')
170 branch1 = self.factory.makeAnyBranch(product=product)
171- branch2 = self.factory.makeAnyBranch(product=product)
172+ self.factory.makeAnyBranch(product=product)
173 view = BranchView(branch1, self.request)
174 view.initialize()
175 self.assertTrue(view.show_merge_links)
176
177=== modified file 'lib/lp/code/interfaces/codeimportjob.py'
178--- lib/lp/code/interfaces/codeimportjob.py 2010-03-16 01:34:38 +0000
179+++ lib/lp/code/interfaces/codeimportjob.py 2010-07-13 10:02:50 +0000
180@@ -16,8 +16,6 @@
181 'ICodeImportJobWorkflow',
182 ]
183
184-import datetime
185-
186 from zope.interface import Interface
187 from zope.schema import Choice, Datetime, Int, Object, Text
188
189
190=== modified file 'lib/lp/code/model/tests/test_codeimportjob.py'
191--- lib/lp/code/model/tests/test_codeimportjob.py 2010-07-13 10:02:48 +0000
192+++ lib/lp/code/model/tests/test_codeimportjob.py 2010-07-13 10:02:50 +0000
193@@ -5,7 +5,9 @@
194
195 __metaclass__ = type
196
197-__all__ = ['NewEvents', 'test_suite']
198+__all__ = [
199+ 'NewEvents',
200+ ]
201
202 from datetime import datetime
203 from pytz import UTC
204@@ -24,7 +26,6 @@
205 from canonical.config import config
206 from canonical.database.constants import UTC_NOW
207 from lp.code.model.codeimportjob import CodeImportJob
208-from lp.code.model.codeimportmachine import CodeImportMachine
209 from lp.code.model.codeimportresult import CodeImportResult
210 from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet
211 from lp.code.enums import (
212@@ -38,12 +39,14 @@
213 from lp.registry.interfaces.person import IPersonSet
214 from lp.testing import (
215 ANONYMOUS, login, login_celebrity, logout, TestCaseWithFactory)
216+from lp.testing.sampledata import NO_PRIVILEGE_EMAIL, VCS_IMPORTS_MEMBER_EMAIL
217 from canonical.launchpad.testing.codeimporthelpers import (
218 make_finished_import, make_running_import)
219 from canonical.launchpad.testing.pages import get_feedback_messages
220 from canonical.launchpad.webapp import canonical_url
221 from canonical.librarian.interfaces import ILibrarianClient
222-from canonical.testing import LaunchpadFunctionalLayer
223+from canonical.testing import (
224+ DatabaseFunctionalLayer, LaunchpadFunctionalLayer)
225
226
227 def login_for_code_imports():
228@@ -52,28 +55,29 @@
229 CodeImports are currently hidden from regular users currently. Members of
230 the vcs-imports team and can access the objects freely.
231 """
232- login_celebrity('vcs_imports')
233-
234-
235-class TestCodeImportJobSet(unittest.TestCase):
236+ return login_celebrity('vcs_imports')
237+
238+
239+class TestCodeImportJobSet(TestCaseWithFactory):
240 """Unit tests for the CodeImportJobSet utility."""
241
242- layer = LaunchpadFunctionalLayer
243+ layer = DatabaseFunctionalLayer
244
245 def setUp(self):
246+ super(TestCodeImportJobSet, self).setUp()
247 login_for_code_imports()
248
249 def test_getByIdExisting(self):
250 # CodeImportJobSet.getById retrieves a CodeImportJob by database id.
251- job = getUtility(ICodeImportJobSet).getById(1)
252- self.assertNotEqual(job, None)
253- self.assertEqual(job.id, 1)
254+ made_job = self.factory.makeCodeImportJob()
255+ found_job = getUtility(ICodeImportJobSet).getById(made_job.id)
256+ self.assertEqual(made_job, found_job)
257
258 def test_getByIdNotExisting(self):
259 # CodeImportJobSet.getById returns None if there is not CodeImportJob
260 # with the specified id.
261 no_job = getUtility(ICodeImportJobSet).getById(-1)
262- self.assertEqual(no_job, None)
263+ self.assertIs(None, no_job)
264
265
266 class TestCodeImportJobSetGetJobForMachine(TestCaseWithFactory):
267@@ -88,7 +92,7 @@
268 method makeJob() creates actual CodeImportJob objects from these specs.
269 """
270
271- layer = LaunchpadFunctionalLayer
272+ layer = DatabaseFunctionalLayer
273
274 def setUp(self):
275 # Login so we can access the code import system, delete all jobs in
276@@ -115,7 +119,7 @@
277 def assertJobIsSelected(self, desired_job):
278 """Assert that the expected job is chosen by getJobForMachine."""
279 observed_job = getUtility(ICodeImportJobSet).getJobForMachine(
280- self.machine.hostname, 10)
281+ self.machine.hostname, worker_limit=10)
282 self.assert_(observed_job is not None, "No job was selected.")
283 self.assertEqual(desired_job, observed_job,
284 "Expected job not selected.")
285@@ -123,7 +127,7 @@
286 def assertNoJobSelected(self):
287 """Assert that no job is selected."""
288 observed_job = getUtility(ICodeImportJobSet).getJobForMachine(
289- 'machine', 10)
290+ 'machine', worker_limit=10)
291 self.assert_(observed_job is None, "Job unexpectedly selected.")
292
293 def test_nothingSelectedIfNothingCreated(self):
294@@ -231,7 +235,7 @@
295 class TestCodeImportJobSetGetReclaimableJobs(ReclaimableJobTests):
296 """Tests for the CodeImportJobSet.getReclaimableJobs method."""
297
298- layer = LaunchpadFunctionalLayer
299+ layer = DatabaseFunctionalLayer
300
301 def test_upToDateJob(self):
302 # A job that was updated recently is not considered reclaimable.
303@@ -264,7 +268,7 @@
304 class TestCodeImportJobSetGetJobForMachineGardening(ReclaimableJobTests):
305 """Test that getJobForMachine gardens stale code import jobs."""
306
307- layer = LaunchpadFunctionalLayer
308+ layer = DatabaseFunctionalLayer
309
310 def test_getJobForMachineGardens(self):
311 # getJobForMachine reclaims all reclaimable jobs each time it is
312@@ -275,7 +279,7 @@
313 machine = self.factory.makeCodeImportMachine(set_online=True)
314 login(ANONYMOUS)
315 getUtility(ICodeImportJobSet).getJobForMachine(
316- machine.hostname, 10)
317+ machine.hostname, worker_limit=10)
318 login_for_code_imports()
319 # Now there are no reclaimable jobs.
320 self.assertReclaimableJobs([])
321@@ -364,7 +368,7 @@
322 AssertFailureMixin):
323 """Unit tests for the CodeImportJobWorkflow.newJob method."""
324
325- layer = LaunchpadFunctionalLayer
326+ layer = DatabaseFunctionalLayer
327
328 def setUp(self):
329 super(TestCodeImportJobWorkflowNewJob, self).setUp()
330@@ -373,50 +377,31 @@
331 def test_wrongReviewStatus(self):
332 # CodeImportJobWorkflow.newJob fails if the CodeImport review_status
333 # is different from REVIEWED.
334- new_import = getUtility(ICodeImportSet).get(2)
335- # Checking sampledata expectations.
336- self.assertEqual(new_import.branch.unique_name,
337- '~vcs-imports/evolution/import')
338- NEW = CodeImportReviewStatus.NEW
339- self.assertEqual(new_import.review_status, NEW)
340+ new_import = self.factory.makeCodeImport()
341+ branch_name = new_import.branch.unique_name
342 # Testing newJob failure.
343 self.assertFailure(
344- "Review status of ~vcs-imports/evolution/import "
345- "is not REVIEWED: NEW",
346+ "Review status of %s is not REVIEWED: NEW" % (branch_name,),
347 getUtility(ICodeImportJobWorkflow).newJob, new_import)
348
349 def test_existingJob(self):
350 # CodeImportJobWorkflow.newJob fails if the CodeImport is already
351 # associated to a CodeImportJob.
352- reviewed_import = getUtility(ICodeImportSet).get(1)
353- # Checking sampledata expectations.
354- self.assertEqual(reviewed_import.branch.unique_name,
355- '~vcs-imports/gnome-terminal/import')
356- REVIEWED = CodeImportReviewStatus.REVIEWED
357- self.assertEqual(reviewed_import.review_status, REVIEWED)
358- self.assertNotEqual(reviewed_import.import_job, None)
359- # Testing newJob failure.
360+ job = self.factory.makeCodeImportJob()
361+ reviewed_import = job.code_import
362+ branch_name = reviewed_import.branch.unique_name
363 self.assertFailure(
364- "Already associated to a CodeImportJob: "
365- "~vcs-imports/gnome-terminal/import",
366+ "Already associated to a CodeImportJob: %s" % (branch_name,),
367 getUtility(ICodeImportJobWorkflow).newJob, reviewed_import)
368
369 def getCodeImportForDateDueTest(self):
370 """Return a `CodeImport` object for testing how date_due is set.
371
372- We check that it is not associated to any `CodeImportJob` or
373- `CodeImportResult`, and we ensure its review_status is REVIEWED.
374+ It is not associated to any `CodeImportJob` or `CodeImportResult`, and
375+ its review_status is REVIEWED.
376 """
377- new_import = getUtility(ICodeImportSet).get(2)
378- # Checking sampledata expectations.
379- self.assertEqual(new_import.import_job, None)
380- self.assertEqual(
381- CodeImportResult.selectBy(code_importID=new_import.id).count(), 0)
382- # We need to set review_status to REVIEWED before calling newJob, and
383- # the interface marks review_status as read-only.
384- REVIEWED = CodeImportReviewStatus.REVIEWED
385- removeSecurityProxy(new_import).review_status = REVIEWED
386- return new_import
387+ return self.factory.makeCodeImport(
388+ review_status=CodeImportReviewStatus.REVIEWED)
389
390 def test_dateDueNoPreviousResult(self):
391 # If there is no CodeImportResult for the CodeImport, then the new
392@@ -432,7 +417,7 @@
393 code_import = self.getCodeImportForDateDueTest()
394 # Create a CodeImportResult that started a long time ago. This one
395 # must be superseded by the more recent one created below.
396- machine = CodeImportMachine.get(1)
397+ machine = self.factory.makeCodeImportMachine()
398 FAILURE = CodeImportResultStatus.FAILURE
399 CodeImportResult(
400 code_import=code_import, machine=machine, status=FAILURE,
401@@ -467,7 +452,7 @@
402 # set to UTC_NOW.
403 code_import = self.getCodeImportForDateDueTest()
404 # Create a CodeImportResult that started a long time ago.
405- machine = CodeImportMachine.get(1)
406+ machine = self.factory.makeCodeImportMachine()
407 FAILURE = CodeImportResultStatus.FAILURE
408 CodeImportResult(
409 code_import=code_import, machine=machine, status=FAILURE,
410@@ -478,78 +463,66 @@
411 self.assertSqlAttributeEqualsDate(job, 'date_due', UTC_NOW)
412
413
414-class TestCodeImportJobWorkflowDeletePendingJob(unittest.TestCase,
415+class TestCodeImportJobWorkflowDeletePendingJob(TestCaseWithFactory,
416 AssertFailureMixin):
417 """Unit tests for CodeImportJobWorkflow.deletePendingJob."""
418
419- layer = LaunchpadFunctionalLayer
420+ layer = DatabaseFunctionalLayer
421
422 def setUp(self):
423 super(TestCodeImportJobWorkflowDeletePendingJob, self).setUp()
424- login_for_code_imports()
425+ self.import_admin = login_for_code_imports()
426
427 def test_wrongReviewStatus(self):
428 # CodeImportJobWorkflow.deletePendingJob fails if the
429 # CodeImport review_status is equal to REVIEWED.
430- reviewed_import = getUtility(ICodeImportSet).get(1)
431- # Checking sampledata expectations.
432- self.assertEqual(reviewed_import.branch.unique_name,
433- '~vcs-imports/gnome-terminal/import')
434- REVIEWED = CodeImportReviewStatus.REVIEWED
435- self.assertEqual(reviewed_import.review_status, REVIEWED)
436+ reviewed_import = self.factory.makeCodeImport()
437+ reviewed_import.updateFromData(
438+ {'review_status': CodeImportReviewStatus.REVIEWED},
439+ self.import_admin)
440+ branch_name = reviewed_import.branch.unique_name
441 # Testing deletePendingJob failure.
442 self.assertFailure(
443- "The review status of ~vcs-imports/gnome-terminal/import "
444- "is REVIEWED.",
445+ "The review status of %s is REVIEWED." % (branch_name,),
446 getUtility(ICodeImportJobWorkflow).deletePendingJob,
447 reviewed_import)
448
449 def test_noJob(self):
450 # CodeImportJobWorkflow.deletePendingJob fails if the
451 # CodeImport is not associated to a CodeImportJob.
452- new_import = getUtility(ICodeImportSet).get(2)
453- # Checking sampledata expectations.
454- self.assertEqual(new_import.branch.unique_name,
455- '~vcs-imports/evolution/import')
456- NEW = CodeImportReviewStatus.NEW
457- self.assertEqual(new_import.review_status, NEW)
458- self.assertEqual(new_import.import_job, None)
459+ new_import = self.factory.makeCodeImport()
460+ branch_name = new_import.branch.unique_name
461 # Testing deletePendingJob failure.
462 self.assertFailure(
463- "Not associated to a CodeImportJob: "
464- "~vcs-imports/evolution/import",
465+ "Not associated to a CodeImportJob: %s" % (branch_name,),
466 getUtility(ICodeImportJobWorkflow).deletePendingJob,
467 new_import)
468
469 def test_wrongJobState(self):
470 # CodeImportJobWorkflow.deletePendingJob fails if the state of
471 # the CodeImportJob is different from PENDING.
472- reviewed_import = getUtility(ICodeImportSet).get(1)
473- # Checking sampledata expectations.
474- self.assertEqual(reviewed_import.branch.unique_name,
475- '~vcs-imports/gnome-terminal/import')
476- # ICodeImport does not allow setting any attribute, so we need to use
477- # removeSecurityProxy to set the review_status attribute.
478+ job = self.factory.makeCodeImportJob()
479+ code_import = job.code_import
480+ branch_name = job.code_import.branch.unique_name
481+ # ICodeImport does not allow setting 'review_status', so we must use
482+ # removeSecurityProxy.
483 INVALID = CodeImportReviewStatus.INVALID
484- removeSecurityProxy(reviewed_import).review_status = INVALID
485- self.assertNotEqual(reviewed_import.import_job, None)
486+ removeSecurityProxy(code_import).review_status = INVALID
487 # ICodeImportJob does not allow setting 'state', so we must
488 # use removeSecurityProxy.
489 RUNNING = CodeImportJobState.RUNNING
490- removeSecurityProxy(reviewed_import.import_job).state = RUNNING
491+ removeSecurityProxy(code_import.import_job).state = RUNNING
492 # Testing deletePendingJob failure.
493 self.assertFailure(
494- "The CodeImportJob associated to "
495- "~vcs-imports/gnome-terminal/import is RUNNING.",
496- getUtility(ICodeImportJobWorkflow).deletePendingJob,
497- reviewed_import)
498+ "The CodeImportJob associated to %s is RUNNING." % (branch_name,),
499+ getUtility(ICodeImportJobWorkflow).deletePendingJob, code_import)
500
501
502 class TestCodeImportJobWorkflowRequestJob(TestCaseWithFactory,
503 AssertFailureMixin, AssertEventMixin):
504 """Unit tests for CodeImportJobWorkflow.requestJob."""
505
506- layer = LaunchpadFunctionalLayer
507+ layer = DatabaseFunctionalLayer
508
509 def setUp(self):
510 super(TestCodeImportJobWorkflowRequestJob, self).setUp()
511@@ -641,7 +614,7 @@
512 AssertFailureMixin, AssertEventMixin):
513 """Unit tests for CodeImportJobWorkflow.startJob."""
514
515- layer = LaunchpadFunctionalLayer
516+ layer = DatabaseFunctionalLayer
517
518 def setUp(self):
519 super(TestCodeImportJobWorkflowStartJob, self).setUp()
520@@ -679,7 +652,7 @@
521 AssertFailureMixin, AssertEventMixin):
522 """Unit tests for CodeImportJobWorkflow.updateHeartbeat."""
523
524- layer = LaunchpadFunctionalLayer
525+ layer = DatabaseFunctionalLayer
526
527 def setUp(self):
528 super(TestCodeImportJobWorkflowUpdateHeartbeat, self).setUp()
529@@ -705,7 +678,7 @@
530
531 def setUp(self):
532 super(TestCodeImportJobWorkflowFinishJob, self).setUp()
533- login_for_code_imports()
534+ self.vcs_imports = login_for_code_imports()
535 self.machine = self.factory.makeCodeImportMachine(set_online=True)
536
537 def makeRunningJob(self, code_import=None):
538@@ -804,10 +777,9 @@
539 # unless the CodeImport has been suspended or marked invalid.
540 running_job = self.makeRunningJob()
541 code_import = running_job.code_import
542- ddaa = getUtility(IPersonSet).getByEmail(
543- 'david.allouche@canonical.com')
544 code_import.updateFromData(
545- {'review_status': CodeImportReviewStatus.SUSPENDED}, ddaa)
546+ {'review_status': CodeImportReviewStatus.SUSPENDED},
547+ self.vcs_imports)
548 getUtility(ICodeImportJobWorkflow).finishJob(
549 running_job, CodeImportResultStatus.SUCCESS, None)
550 self.assertTrue(code_import.import_job is None)
551@@ -920,8 +892,7 @@
552 log_alias = getUtility(ILibraryFileAliasSet)[log_alias_id]
553 result = self.getResultForJob(job, log_alias=log_alias)
554
555- self.assertEqual(
556- result.log_file.read(), log_data)
557+ self.assertEqual(result.log_file.read(), log_data)
558
559 def test_createsFinishCodeImportEvent(self):
560 # finishJob() creates a FINISH CodeImportEvent.
561@@ -1005,7 +976,7 @@
562
563 # This is a dependence on the sample data: David Allouche is a member of the
564 # ~vcs-imports celebrity team.
565-logged_in_for_code_imports = logged_in_as('david.allouche@canonical.com')
566+logged_in_for_code_imports = logged_in_as(VCS_IMPORTS_MEMBER_EMAIL)
567
568
569 class TestRequestJobUIRaces(TestCaseWithFactory):
570@@ -1016,7 +987,7 @@
571 the button and check that appropriate notifications are displayed.
572 """
573
574- layer = LaunchpadFunctionalLayer
575+ layer = DatabaseFunctionalLayer
576
577 @logged_in_for_code_imports
578 def getNewCodeImportIDAndBranchURL(self):
579@@ -1027,7 +998,7 @@
580 code_import_id = code_import.id
581 return code_import_id, branch_url
582
583- @logged_in_as('no-priv@canonical.com')
584+ @logged_in_as(NO_PRIVILEGE_EMAIL)
585 def requestJobByUserWithDisplayName(self, code_import_id, displayname):
586 """Record a request for the job by a user with the given name."""
587 getUtility(ICodeImportJobWorkflow).requestJob(
588
589=== modified file 'lib/lp/testing/factory.py'
590--- lib/lp/testing/factory.py 2010-07-08 11:54:57 +0000
591+++ lib/lp/testing/factory.py 2010-07-13 10:02:50 +0000
592@@ -1436,7 +1436,7 @@
593 def makeCodeImport(self, svn_branch_url=None, cvs_root=None,
594 cvs_module=None, target=None, branch_name=None,
595 git_repo_url=None, hg_repo_url=None, registrant=None,
596- rcs_type=None):
597+ rcs_type=None, review_status=None):
598 """Create and return a new, arbitrary code import.
599
600 The type of code import will be inferred from the source details
601@@ -1461,26 +1461,29 @@
602 else:
603 assert rcs_type in (RevisionControlSystems.SVN,
604 RevisionControlSystems.BZR_SVN)
605- return code_import_set.new(
606+ code_import = code_import_set.new(
607 registrant, target, branch_name, rcs_type=rcs_type,
608 url=svn_branch_url)
609 elif git_repo_url is not None:
610 assert rcs_type in (None, RevisionControlSystems.GIT)
611- return code_import_set.new(
612+ code_import = code_import_set.new(
613 registrant, target, branch_name,
614 rcs_type=RevisionControlSystems.GIT,
615 url=git_repo_url)
616 elif hg_repo_url is not None:
617- return code_import_set.new(
618+ code_import = code_import_set.new(
619 registrant, target, branch_name,
620 rcs_type=RevisionControlSystems.HG,
621 url=hg_repo_url)
622 else:
623 assert rcs_type in (None, RevisionControlSystems.CVS)
624- return code_import_set.new(
625+ code_import = code_import_set.new(
626 registrant, target, branch_name,
627 rcs_type=RevisionControlSystems.CVS,
628 cvs_root=cvs_root, cvs_module=cvs_module)
629+ if review_status:
630+ removeSecurityProxy(code_import).review_status = review_status
631+ return code_import
632
633 def makeCodeImportEvent(self):
634 """Create and return a CodeImportEvent."""
635
636=== added file 'lib/lp/testing/sampledata.py'
637--- lib/lp/testing/sampledata.py 1970-01-01 00:00:00 +0000
638+++ lib/lp/testing/sampledata.py 2010-07-13 10:02:50 +0000
639@@ -0,0 +1,18 @@
640+# Copyright 2010 Canonical Ltd. This software is licensed under the
641+# GNU Affero General Public License version 3 (see the file LICENSE).
642+
643+"""Constants that refer to values in sampledata.
644+
645+If ever you use a literal in a test that refers to sample data, even if it's
646+just a small number, then you should define it as a constant here.
647+"""
648+
649+__metaclass__ = type
650+__all__ = [
651+ 'NO_PRIVILEGE_EMAIL',
652+ 'VCS_IMPORTS_MEMBER_EMAIL',
653+ ]
654+
655+
656+NO_PRIVILEGE_EMAIL = 'no-priv@canonical.com'
657+VCS_IMPORTS_MEMBER_EMAIL = 'david.allouche@canonical.com'
658
659=== added file 'lib/lp/testing/tests/test_factory.py'
660--- lib/lp/testing/tests/test_factory.py 1970-01-01 00:00:00 +0000
661+++ lib/lp/testing/tests/test_factory.py 2010-07-13 10:02:50 +0000
662@@ -0,0 +1,34 @@
663+# Copyright 2010 Canonical Ltd. This software is licensed under the
664+# GNU Affero General Public License version 3 (see the file LICENSE).
665+
666+"""Tests for the Launchpad object factory."""
667+
668+__metaclass__ = type
669+
670+import unittest
671+
672+from canonical.testing.layers import DatabaseFunctionalLayer
673+from lp.code.enums import CodeImportReviewStatus
674+from lp.testing import TestCaseWithFactory
675+
676+
677+class TestFactory(TestCaseWithFactory):
678+
679+ layer = DatabaseFunctionalLayer
680+
681+ def test_makeCodeImportNoStatus(self):
682+ # If makeCodeImport is not given a review status, it defaults to NEW.
683+ code_import = self.factory.makeCodeImport()
684+ self.assertEqual(
685+ CodeImportReviewStatus.NEW, code_import.review_status)
686+
687+ def test_makeCodeImportReviewStatus(self):
688+ # If makeCodeImport is given a review status, then that is the status
689+ # of the created import.
690+ status = CodeImportReviewStatus.REVIEWED
691+ code_import = self.factory.makeCodeImport(review_status=status)
692+ self.assertEqual(status, code_import.review_status)
693+
694+
695+def test_suite():
696+ return unittest.TestLoader().loadTestsFromName(__name__)