launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #08838
[Merge] lp:~sinzui/launchpad/commercial-jobsource-zcml into lp:launchpad
Curtis Hovey has proposed merging lp:~sinzui/launchpad/commercial-jobsource-zcml into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1012808 in Launchpad itself: "Expiration email job sources are not registered"
https://bugs.launchpad.net/launchpad/+bug/1012808
For more details, see:
https://code.launchpad.net/~sinzui/launchpad/commercial-jobsource-zcml/+merge/110365
process-job-source.py fails because the commercial notification classes
are not registered in ZCML. Clearly, a test is missing that demonstrates
the ZCML, schema-lazr.conf, and security.cfg are configured properly.
I really botched this. I new what test was missing when I discovered the
bug. There are two cronscripts used in this process, and I only wrote
tests for the script I wrote. I need to also write a test for the script
I reused.
--------------------------------------------------------------------
RULES
Pre-implementation: no one
* Add the missing ZCML needed to register the secured utilities.
* Add tests to verify the three kinds of job are run.
* Fix any db permissions that are proven to fail.
* Fix the ICommercialExpiredJob to be ICommercialExpiredJobSource
in the schema.
QA
On qastaging, as a webops to run
* cronscripts/process-job-source.py ICommercialExpiredJobSource
* cronscripts/process-job-source.py ISevenDayCommercialExpirationJobSource
* cronscripts/process-job-source.py IThirtyDayCommercialExpirationJobSource
LINT
cronscripts/daily_product_jobs.py
database/schema/security.cfg
lib/lp/registry/configure.zcml
lib/lp/registry/model/productjob.py
lib/lp/registry/tests/test_productjob.py
lib/lp/services/config/schema-lazr.conf
TEST
./bin/test -vvc lp.registry.tests.test_productjob
IMPLEMENTATION
Fixed the class name used to lookup jobs
ICommercialExpiredJob => ICommercialExpiredJobSource
cronscripts/daily_product_jobs.py
lib/lp/services/config/schema-lazr.conf
Added a test to the test mixin to verify that the three kinds of
commercial notification job can be run by process-job-source.py. I
discovered that there is two run_script() test helpers with different
IO. I chose to use update an existing test to use the one from
lp.testing because it allows me to pass the environ to get better test
output.
lib/lp/registry/model/productjob.py
lib/lp/registry/tests/test_productjob.py
Added the missing ZCML registration that permits process-job-source.py
to lookup the job source class and then have permission to use the job
instance.
lib/lp/registry/configure.zcml
Fixed the db permissions demonstrated to be need by the new test. The
packaging/distro tables are needed because there is a sanity check in
the product deactivation code that ensure Ubuntu does not look an
upstream packaging link
database/schema/security.cfg
--
https://code.launchpad.net/~sinzui/launchpad/commercial-jobsource-zcml/+merge/110365
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~sinzui/launchpad/commercial-jobsource-zcml into lp:launchpad.
=== modified file 'cronscripts/daily_product_jobs.py'
--- cronscripts/daily_product_jobs.py 2012-06-07 19:14:04 +0000
+++ cronscripts/daily_product_jobs.py 2012-06-14 16:16:22 +0000
@@ -21,7 +21,7 @@
def __init__(self):
name = 'daily_product_jobs'
- dbuser = config.ICommercialExpiredJob.dbuser
+ dbuser = config.ICommercialExpiredJobSource.dbuser
LaunchpadCronScript.__init__(self, name, dbuser)
def main(self):
=== modified file 'database/schema/security.cfg'
--- database/schema/security.cfg 2012-06-08 15:46:51 +0000
+++ database/schema/security.cfg 2012-06-14 16:16:22 +0000
@@ -2367,11 +2367,17 @@
[product-job]
groups=script
public.account = SELECT
+public.branch = SELECT
public.commercialsubscription = SELECT, UPDATE, DELETE
+public.distribution = SELECT
+public.distroseries = SELECT
public.emailaddress = SELECT
public.job = SELECT, INSERT, UPDATE
public.person = SELECT
+public.packaging = SELECT
public.product = SELECT, UPDATE
+public.productlicense = SELECT
public.productseries = SELECT, UPDATE
public.productjob = SELECT, INSERT
+public.sourcepackagename = SELECT
type=user
=== modified file 'lib/lp/registry/configure.zcml'
--- lib/lp/registry/configure.zcml 2012-05-29 03:59:16 +0000
+++ lib/lp/registry/configure.zcml 2012-06-14 16:16:22 +0000
@@ -110,6 +110,37 @@
<allow interface=".interfaces.persontransferjob.IPersonMergeJob"/>
</class>
+ <!-- IProductNotificationJob -->
+ <securedutility
+ component=".model.productjob.CommercialExpiredJob"
+ provides=".interfaces.productjob.ICommercialExpiredJobSource">
+ <allow interface=".interfaces.productjob.ICommercialExpiredJobSource"/>
+ </securedutility>
+
+ <class class=".model.productjob.CommercialExpiredJob">
+ <allow interface=".interfaces.productjob.ICommercialExpiredJob"/>
+ </class>
+
+ <securedutility
+ component=".model.productjob.SevenDayCommercialExpirationJob"
+ provides=".interfaces.productjob.ISevenDayCommercialExpirationJobSource">
+ <allow interface=".interfaces.productjob.ISevenDayCommercialExpirationJobSource"/>
+ </securedutility>
+
+ <class class=".model.productjob.SevenDayCommercialExpirationJob">
+ <allow interface=".interfaces.productjob.ISevenDayCommercialExpirationJob"/>
+ </class>
+
+ <securedutility
+ component=".model.productjob.ThirtyDayCommercialExpirationJob"
+ provides=".interfaces.productjob.IThirtyDayCommercialExpirationJobSource">
+ <allow interface=".interfaces.productjob.IThirtyDayCommercialExpirationJobSource"/>
+ </securedutility>
+
+ <class class=".model.productjob.ThirtyDayCommercialExpirationJob">
+ <allow interface=".interfaces.productjob.IThirtyDayCommercialExpirationJob"/>
+ </class>
+
<!-- INameBlacklist -->
<securedutility
class="lp.registry.model.nameblacklist.NameBlacklistSet"
=== modified file 'lib/lp/registry/model/productjob.py'
--- lib/lp/registry/model/productjob.py 2012-06-14 05:18:22 +0000
+++ lib/lp/registry/model/productjob.py 2012-06-14 16:16:22 +0000
@@ -71,6 +71,11 @@
from lp.services.mail.helpers import get_email_template
from lp.services.mail.mailwrapper import MailWrapper
from lp.services.mail.notificationrecipientset import NotificationRecipientSet
+<<<<<<< TREE
+=======
+from lp.services.mail.mailwrapper import MailWrapper
+from lp.services.scripts import log
+>>>>>>> MERGE-SOURCE
from lp.services.mail.sendmail import (
format_address,
format_address_for_person,
@@ -332,6 +337,8 @@
body, headers = self.getBodyAndHeaders(
email_template, address, self.reply_to)
simple_sendmail(from_address, address, subject, body, headers)
+ log.debug("%s has sent email to the maintainer of %s.",
+ self.log_name, self.product.name)
def run(self):
"""See `BaseRunnableJob`.
=== modified file 'lib/lp/registry/tests/test_productjob.py'
--- lib/lp/registry/tests/test_productjob.py 2012-06-14 05:18:22 +0000
+++ lib/lp/registry/tests/test_productjob.py 2012-06-14 16:16:22 +0000
@@ -12,6 +12,12 @@
import pytz
import transaction
+<<<<<<< TREE
+=======
+import pytz
+from testtools.content import Content
+from testtools.content_type import UTF8_TEXT
+>>>>>>> MERGE-SOURCE
from zope.component import getUtility
from zope.interface import (
classProvides,
@@ -53,6 +59,7 @@
from lp.services.webapp.publisher import canonical_url
from lp.testing import (
person_logged_in,
+ run_script,
TestCaseWithFactory,
)
from lp.testing.layers import (
@@ -61,6 +68,14 @@
ZopelessAppServerLayer,
)
from lp.testing.mail_helpers import pop_notifications
+<<<<<<< TREE
+=======
+from lp.services.database.lpstorm import IStore
+from lp.services.job.interfaces.job import JobStatus
+from lp.services.log.logger import BufferLogger
+from lp.services.propertycache import clear_property_cache
+from lp.services.webapp.publisher import canonical_url
+>>>>>>> MERGE-SOURCE
class CommercialHelpers:
@@ -147,8 +162,11 @@
# ProductJobManagerTestCase.test_createAllDailyJobs
self.make_test_products()
transaction.commit()
- retcode, stdout, stderr = run_script(
- 'cronscripts/daily_product_jobs.py', [])
+ stdout, stderr, retcode = run_script(
+ 'cronscripts/daily_product_jobs.py')
+ self.addDetail("stdout", Content(UTF8_TEXT, lambda: stdout))
+ self.addDetail("stderr", Content(UTF8_TEXT, lambda: stderr))
+ self.assertEqual(0, retcode)
self.assertIn('Requested 3 total product jobs.', stderr)
@@ -556,6 +574,48 @@
self.assertEqual(1, len(notifications))
self.assertIn(iso_date, notifications[0].get_payload())
+ def test_run_cronscript(self):
+ # Everything is configured: ZCML, schema-lazr.conf, and security.cfg.
+ product, reviewer = self.make_notification_data()
+ private_branch = self.factory.makeBranch(
+ owner=product.owner, product=product,
+ information_type=InformationType.USERDATA)
+ with person_logged_in(product.owner):
+ product.setPrivateBugs(True, product.owner)
+ product.development_focus.branch = private_branch
+ self.expire_commercial_subscription(product)
+ job = self.JOB_CLASS.create(product, reviewer)
+ # Create a proprietary project which will have different DB relations.
+ proprietary_product = self.factory.makeProduct(
+ licenses=[License.OTHER_PROPRIETARY])
+ self.expire_commercial_subscription(proprietary_product)
+ proprietary_job = self.JOB_CLASS.create(proprietary_product, reviewer)
+ transaction.commit()
+
+ out, err, exit_code = run_script(
+ "LP_DEBUG_SQL=1 cronscripts/process-job-source.py -vv %s" %
+ self.JOB_SOURCE_INTERFACE.getName())
+ self.addDetail("stdout", Content(UTF8_TEXT, lambda: out))
+ self.addDetail("stderr", Content(UTF8_TEXT, lambda: err))
+ self.assertEqual(0, exit_code)
+ self.assertTrue(
+ 'Traceback (most recent call last)' not in err)
+ message = (
+ '%s has sent email to the maintainer of %s.' % (
+ self.JOB_CLASS.__name__, product.name))
+ self.assertTrue(
+ message in err,
+ 'Cound not find "%s" in err log:\n%s.' % (message, err))
+ message = (
+ '%s has sent email to the maintainer of %s.' % (
+ self.JOB_CLASS.__name__, proprietary_product.name))
+ self.assertTrue(
+ message in err,
+ 'Cound not find "%s" in err log:\n%s.' % (message, err))
+ IStore(job.job).invalidate()
+ self.assertEqual(JobStatus.COMPLETED, job.job.status)
+ self.assertEqual(JobStatus.COMPLETED, proprietary_job.job.status)
+
class SevenDayCommercialExpirationJobTestCase(CommericialExpirationMixin,
TestCaseWithFactory):
=== modified file 'lib/lp/services/config/schema-lazr.conf'
--- lib/lp/services/config/schema-lazr.conf 2012-06-13 01:05:42 +0000
+++ lib/lp/services/config/schema-lazr.conf 2012-06-14 16:16:22 +0000
@@ -1749,7 +1749,7 @@
# dbuser, the crontab_group, and the module that the job source class
# can be loaded from.
job_sources:
- ICommercialExpiredJob,
+ ICommercialExpiredJobSource,
IMembershipNotificationJobSource,
IPersonMergeJobSource,
IPlainPackageCopyJobSource,
@@ -1759,7 +1759,7 @@
ISevenDayCommercialExpirationJobSource,
IThirtyDayCommercialExpirationJobSource
-[ICommercialExpiredJob]
+[ICommercialExpiredJobSource]
module: lp.registry.interfaces.productjob
dbuser: product-job
crontab_group: MAIN
Follow ups