launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #07285
[Merge] lp:~abentley/launchpad/celery-everywhere-8 into lp:launchpad
Aaron Bentley has proposed merging lp:~abentley/launchpad/celery-everywhere-8 into lp:launchpad with lp:~abentley/launchpad/celery-everywhere-7 as a prerequisite.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~abentley/launchpad/celery-everywhere-8/+merge/103545
= Summary =
Support running PersonTransferJob via Celery.
== Pre-implementation notes ==
None
== LOC Rationale ==
Part of a resourced arc that will ultimately remove code.
== Implementation details ==
PersonTransferJob now provides makeDerived.
PersonTransferJobDerived now uses the EnumeratedSubclass metatype, so it can turn a PersonTransferJob into the appropriate subclass.
PersonTransferJobDerived.create now requests the job to run via Celery.
UniversalJobSource now supports PersonTransferJob.
PersonMergeJob and MembershipNotificationJob both provide configs.
== Tests ==
bin/test --layer=CeleryJobLayer -m 'membership_notification|person_merge'
== Demo and Q/A ==
None
= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:
lib/lp/translations/tests/test_pofilestatsjob.py
lib/lp/registry/tests/test_membership_notification_job.py
lib/lp/translations/model/pofilestatsjob.py
lib/lp/registry/model/persontransferjob.py
lib/lp/registry/tests/test_person_merge_job.py
lib/lp/services/job/model/job.py
--
https://code.launchpad.net/~abentley/launchpad/celery-everywhere-8/+merge/103545
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~abentley/launchpad/celery-everywhere-8 into lp:launchpad.
=== modified file 'lib/lp/registry/model/persontransferjob.py'
--- lib/lp/registry/model/persontransferjob.py 2012-01-27 11:12:53 +0000
+++ lib/lp/registry/model/persontransferjob.py 2012-04-25 18:50:05 +0000
@@ -52,7 +52,10 @@
IStore,
)
from lp.services.database.stormbase import StormBase
-from lp.services.job.model.job import Job
+from lp.services.job.model.job import (
+ EnumeratedSubclass,
+ Job,
+ )
from lp.services.job.runner import BaseRunnableJob
from lp.services.mail.helpers import (
get_contact_email_addresses,
@@ -115,6 +118,9 @@
# but the DB representation is unicode.
self._json_data = json_data.decode('utf-8')
+ def makeDerived(self):
+ return PersonTransferJobDerived.makeSubclass(self)
+
class PersonTransferJobDerived(BaseRunnableJob):
"""Intermediate class for deriving from PersonTransferJob.
@@ -126,6 +132,7 @@
the run() method.
"""
+ __metaclass__ = EnumeratedSubclass
delegates(IPersonTransferJob)
classProvides(IPersonTransferJobSource)
@@ -146,7 +153,9 @@
major_person=major_person,
job_type=cls.class_job_type,
metadata=metadata)
- return cls(job)
+ derived = cls(job)
+ derived.celeryRunOnCommit()
+ return derived
@classmethod
def iterReady(cls):
@@ -176,6 +185,8 @@
class_job_type = PersonTransferJobType.MEMBERSHIP_NOTIFICATION
+ config = config.IMembershipNotificationJobSource
+
@classmethod
def create(cls, member, team, reviewer, old_status, new_status,
last_change_comment=None):
@@ -342,6 +353,8 @@
class_job_type = PersonTransferJobType.MERGE
+ config = config.IPersonMergeJobSource
+
@classmethod
def create(cls, from_person, to_person, reviewer=None, delete=False):
"""See `IPersonMergeJobSource`."""
=== modified file 'lib/lp/registry/tests/test_membership_notification_job.py'
--- lib/lp/registry/tests/test_membership_notification_job.py 2012-01-01 02:58:52 +0000
+++ lib/lp/registry/tests/test_membership_notification_job.py 2012-04-25 18:50:05 +0000
@@ -19,14 +19,22 @@
TeamMembershipStatus,
)
from lp.registry.model.persontransferjob import MembershipNotificationJob
+from lp.services.features.testing import FeatureFixture
from lp.services.job.interfaces.job import JobStatus
+from lp.services.job.tests import (
+ block_on_job,
+ pop_remote_notifications,
+ )
from lp.testing import (
login_person,
person_logged_in,
run_script,
TestCaseWithFactory,
)
-from lp.testing.layers import DatabaseFunctionalLayer
+from lp.testing.layers import (
+ CeleryJobLayer,
+ DatabaseFunctionalLayer,
+ )
from lp.testing.sampledata import ADMIN_EMAIL
@@ -110,3 +118,38 @@
self.assertEqual(0, exit_code)
self.assertTrue(job_repr in err, err)
self.assertTrue("MembershipNotificationJob sent email" in err, err)
+
+
+class TestViaCelery(TestCaseWithFactory):
+
+ layer = CeleryJobLayer
+
+ def test_smoke_admining_team(self):
+ # Smoke test, primarily for DB permissions needed by queries to work
+ # with admining users and teams
+ # Check the oopses in /var/tmp/lperr.test if the assertions fail.
+ self.useFixture(FeatureFixture({
+ 'jobs.celery.enabled_classes': 'MembershipNotificationJob'
+ }))
+ team = self.factory.makeTeam(name='a-team')
+ with person_logged_in(team.teamowner):
+ # This implicitly creates a job, but it is not the job under test.
+ admining_team = self.factory.makeTeam()
+ team.addMember(
+ admining_team, team.teamowner, force_team_add=True)
+ membership = getUtility(ITeamMembershipSet).getByPersonAndTeam(
+ admining_team, team)
+ membership.setStatus(
+ TeamMembershipStatus.ADMIN, team.teamowner)
+ person = self.factory.makePerson(name='murdock')
+ with block_on_job(self):
+ transaction.commit()
+ pop_remote_notifications()
+ job = getUtility(IMembershipNotificationJobSource).create(
+ person, team, team.teamowner,
+ TeamMembershipStatus.APPROVED, TeamMembershipStatus.ADMIN)
+ with block_on_job(self):
+ transaction.commit()
+ self.assertEqual(JobStatus.COMPLETED, job.status)
+ (notification,) = pop_remote_notifications()
+ self.assertIn('murdock made admin by', notification['Subject'])
=== modified file 'lib/lp/registry/tests/test_person_merge_job.py'
--- lib/lp/registry/tests/test_person_merge_job.py 2012-01-01 02:58:52 +0000
+++ lib/lp/registry/tests/test_person_merge_job.py 2012-04-25 18:50:05 +0000
@@ -1,4 +1,4 @@
-# Copyright 2011 Canonical Ltd. This software is licensed under the
+# Copyright 2012 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tests of `PersonMergeJob`."""
@@ -20,9 +20,11 @@
IMasterObject,
IStore,
)
+from lp.services.features.testing import FeatureFixture
from lp.services.identity.interfaces.emailaddress import EmailAddressStatus
from lp.services.job.interfaces.job import JobStatus
from lp.services.job.model.job import Job
+from lp.services.job.tests import block_on_job
from lp.services.log.logger import BufferLogger
from lp.services.mail.sendmail import format_address_for_person
from lp.services.scripts import log
@@ -31,7 +33,33 @@
run_script,
TestCaseWithFactory,
)
-from lp.testing.layers import DatabaseFunctionalLayer
+from lp.testing.layers import (
+ CeleryJobLayer,
+ DatabaseFunctionalLayer,
+ )
+
+
+def create_job(factory):
+ """Create a PersonMergeJob for testing purposes.
+
+ :param factory: A LaunchpadObjectFactory.
+ """
+ from_person = factory.makePerson(name='void')
+ to_person = factory.makePerson(name='gestalt')
+ return getUtility(IPersonMergeJobSource).create(
+ from_person=from_person, to_person=to_person)
+
+
+def transfer_email(job):
+ """Reassign email address using the people specified in the job.
+
+ IPersonSet.merge() does not (yet) promise to do this.
+ """
+ from_email = IMasterObject(job.from_person.preferredemail)
+ removeSecurityProxy(from_email).personID = job.to_person.id
+ removeSecurityProxy(from_email).accountID = job.to_person.accountID
+ removeSecurityProxy(from_email).status = EmailAddressStatus.NEW
+ IStore(from_email).flush()
class TestPersonMergeJob(TestCaseWithFactory):
@@ -40,11 +68,10 @@
def setUp(self):
super(TestPersonMergeJob, self).setUp()
- self.from_person = self.factory.makePerson(name='void')
- self.to_person = self.factory.makePerson(name='gestalt')
self.job_source = getUtility(IPersonMergeJobSource)
- self.job = self.job_source.create(
- from_person=self.from_person, to_person=self.to_person)
+ self.job = create_job(self.factory)
+ self.from_person = self.job.from_person
+ self.to_person = self.job.to_person
def test_interface(self):
# PersonMergeJob implements IPersonMergeJob.
@@ -90,11 +117,7 @@
def transfer_email(self):
# Reassign from_person's email address over to to_person because
# IPersonSet.merge() does not (yet) promise to do that.
- from_email = IMasterObject(self.from_person.preferredemail)
- removeSecurityProxy(from_email).personID = self.to_person.id
- removeSecurityProxy(from_email).accountID = self.to_person.accountID
- removeSecurityProxy(from_email).status = EmailAddressStatus.NEW
- IStore(from_email).flush()
+ transfer_email(self.job)
def test_run(self):
# When run it merges from_person into to_person.
@@ -179,3 +202,21 @@
self.assertEqual([self.job], self.find())
else:
self.assertEqual([], self.find())
+
+
+class TestViaCelery(TestCaseWithFactory):
+ """Test that PersonMergeJob runs under Celery."""
+
+ layer = CeleryJobLayer
+
+ def test_run(self):
+ # When run it merges from_person into to_person.
+ self.useFixture(FeatureFixture({
+ 'jobs.celery.enabled_classes': 'PersonMergeJob',
+ }))
+ job = create_job(self.factory)
+ transfer_email(job)
+ from_person = job.from_person
+ with block_on_job(self):
+ transaction.commit()
+ self.assertEqual(job.to_person, from_person.merged)
=== modified file 'lib/lp/services/job/model/job.py'
--- lib/lp/services/job/model/job.py 2012-04-25 18:49:35 +0000
+++ lib/lp/services/job/model/job.py 2012-04-25 18:50:05 +0000
@@ -276,6 +276,7 @@
from lp.code.model.branchmergeproposaljob import (
BranchMergeProposalJob,
)
+ from lp.registry.model.persontransferjob import PersonTransferJob
from lp.soyuz.model.distributionjob import DistributionJob
from lp.translations.model.pofilestatsjob import POFileStatsJob
from lp.translations.model.translationsharingjob import (
@@ -286,7 +287,7 @@
for baseclass in [
ApportJob, BranchJob, BranchMergeProposalJob, DistributionJob,
- POFileStatsJob, TranslationSharingJob,
+ PersonTransferJob, POFileStatsJob, TranslationSharingJob,
]:
derived, base_class, store = cls._getDerived(job_id, baseclass)
if derived is not None:
Follow ups