Merge lp:~wgrant/launchpad/webhook-jobrunner into lp:launchpad

Proposed by William Grant
Status: Merged
Merged at revision: 17634
Proposed branch: lp:~wgrant/launchpad/webhook-jobrunner
Merge into: lp:launchpad
Prerequisite: lp:~wgrant/launchpad/webhook-api
Diff against target: 170 lines (+76/-12)
4 files modified
configs/testrunner/launchpad-lazr.conf (+1/-1)
lib/lp/services/webhooks/configure.zcml (+11/-7)
lib/lp/services/webhooks/model.py (+14/-1)
lib/lp/services/webhooks/tests/test_webhookjob.py (+50/-3)
To merge this branch: bzr merge lp:~wgrant/launchpad/webhook-jobrunner
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+264533@code.launchpad.net

Commit message

Fix and test cron and celery WebhookDeliveryJob running.

Description of the change

Some quick fixes and tests for running WebhookDeliveryJobs from the cronscript and celery.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configs/testrunner/launchpad-lazr.conf'
2--- configs/testrunner/launchpad-lazr.conf 2015-07-13 11:21:00 +0000
3+++ configs/testrunner/launchpad-lazr.conf 2015-07-13 11:21:01 +0000
4@@ -182,4 +182,4 @@
5 root: /var/tmp/testkeyserver.test
6
7 [webhooks]
8-http_proxy: http://example.com:3128/
9+http_proxy: http://webhooks-proxy.invalid:3128/
10
11=== modified file 'lib/lp/services/webhooks/configure.zcml'
12--- lib/lp/services/webhooks/configure.zcml 2015-07-13 11:21:00 +0000
13+++ lib/lp/services/webhooks/configure.zcml 2015-07-13 11:21:01 +0000
14@@ -16,19 +16,23 @@
15 <subscriber
16 for="lp.services.webhooks.interfaces.IWebhook zope.lifecycleevent.interfaces.IObjectModifiedEvent"
17 handler="lp.services.webhooks.model.webhook_modified"/>
18-
19- <class class="lp.services.webhooks.model.WebhookDeliveryJob">
20- <require
21- permission="launchpad.View"
22- interface="lp.services.webhooks.interfaces.IWebhookDeliveryJob"/>
23- </class>
24-
25 <securedutility
26 class="lp.services.webhooks.model.WebhookSource"
27 provides="lp.services.webhooks.interfaces.IWebhookSource">
28 <allow interface="lp.services.webhooks.interfaces.IWebhookSource"/>
29 </securedutility>
30
31+ <securedutility
32+ component="lp.services.webhooks.model.WebhookDeliveryJob"
33+ provides="lp.services.webhooks.interfaces.IWebhookDeliveryJobSource">
34+ <allow interface="lp.services.webhooks.interfaces.IWebhookDeliveryJobSource"/>
35+ </securedutility>
36+ <class class="lp.services.webhooks.model.WebhookDeliveryJob">
37+ <require
38+ permission="launchpad.View"
39+ interface="lp.services.webhooks.interfaces.IWebhookDeliveryJob"/>
40+ </class>
41+
42 <utility
43 provides="lp.services.webhooks.interfaces.IWebhookClient"
44 factory="lp.services.webhooks.client.WebhookClient"
45
46=== modified file 'lib/lp/services/webhooks/model.py'
47--- lib/lp/services/webhooks/model.py 2015-07-13 11:21:00 +0000
48+++ lib/lp/services/webhooks/model.py 2015-07-13 11:21:01 +0000
49@@ -41,7 +41,10 @@
50 from lp.services.database.constants import UTC_NOW
51 from lp.services.database.decoratedresultset import DecoratedResultSet
52 from lp.services.database.enumcol import EnumCol
53-from lp.services.database.interfaces import IStore
54+from lp.services.database.interfaces import (
55+ IMasterStore,
56+ IStore,
57+ )
58 from lp.services.database.stormbase import StormBase
59 from lp.services.features import getFeatureFlag
60 from lp.services.job.model.job import (
61@@ -242,6 +245,16 @@
62 def __init__(self, webhook_job):
63 self.context = webhook_job
64
65+ @classmethod
66+ def iterReady(cls):
67+ """See `IJobSource`."""
68+ jobs = IMasterStore(WebhookJob).find(
69+ WebhookJob,
70+ WebhookJob.job_type == cls.class_job_type,
71+ WebhookJob.job == Job.id,
72+ Job.id.is_in(Job.ready_jobs))
73+ return (cls(job) for job in jobs)
74+
75
76 @provider(IWebhookDeliveryJobSource)
77 @implementer(IWebhookDeliveryJob)
78
79=== modified file 'lib/lp/services/webhooks/tests/test_webhookjob.py'
80--- lib/lp/services/webhooks/tests/test_webhookjob.py 2015-07-13 11:21:00 +0000
81+++ lib/lp/services/webhooks/tests/test_webhookjob.py 2015-07-13 11:21:01 +0000
82@@ -21,9 +21,13 @@
83 MatchesStructure,
84 Not,
85 )
86+import transaction
87
88+from lp.services.features.testing import FeatureFixture
89 from lp.services.job.interfaces.job import JobStatus
90 from lp.services.job.runner import JobRunner
91+from lp.services.job.tests import block_on_job
92+from lp.services.scripts.tests import run_script
93 from lp.services.webhooks.client import WebhookClient
94 from lp.services.webhooks.interfaces import (
95 IWebhookClient,
96@@ -43,8 +47,9 @@
97 ZopeUtilityFixture,
98 )
99 from lp.testing.layers import (
100+ CeleryJobLayer,
101 DatabaseFunctionalLayer,
102- LaunchpadZopelessLayer,
103+ ZopelessDatabaseLayer,
104 )
105
106
107@@ -63,7 +68,7 @@
108 class TestWebhookJobDerived(TestCaseWithFactory):
109 """Tests for `WebhookJobDerived`."""
110
111- layer = LaunchpadZopelessLayer
112+ layer = DatabaseFunctionalLayer
113
114 def test_getOopsMailController(self):
115 """By default, no mail is sent about failed WebhookJobs."""
116@@ -147,7 +152,7 @@
117 class TestWebhookDeliveryJob(TestCaseWithFactory):
118 """Tests for `WebhookDeliveryJob`."""
119
120- layer = LaunchpadZopelessLayer
121+ layer = ZopelessDatabaseLayer
122
123 def makeAndRunJob(self, response_status=200, raises=None, mock=True):
124 hook = self.factory.makeWebhook(delivery_url=u'http://hookep.com/foo')
125@@ -251,3 +256,45 @@
126 self.assertEqual(1, len(oopses.oopses))
127 self.assertEqual(
128 'No webhook proxy configured.', oopses.oopses[0]['value'])
129+
130+
131+class TestViaCronscript(TestCaseWithFactory):
132+
133+ layer = ZopelessDatabaseLayer
134+
135+ def test_run_from_cronscript(self):
136+ hook = self.factory.makeWebhook(delivery_url=u'http://hookep.com/foo')
137+ job = WebhookDeliveryJob.create(hook, payload={'foo': 'bar'})
138+ self.assertEqual(JobStatus.WAITING, job.status)
139+ transaction.commit()
140+
141+ retcode, stdout, stderr = run_script(
142+ 'cronscripts/process-job-source.py', ['IWebhookDeliveryJobSource'],
143+ expect_returncode=0)
144+ self.assertEqual('', stdout)
145+ self.assertIn('INFO Ran 1 WebhookDeliveryJob jobs.\n', stderr)
146+
147+ self.assertEqual(JobStatus.COMPLETED, job.status)
148+ self.assertIn(
149+ 'Cannot connect to proxy',
150+ job.json_data['result']['connection_error'])
151+
152+
153+class TestViaCelery(TestCaseWithFactory):
154+
155+ layer = CeleryJobLayer
156+
157+ def test_WebhookDeliveryJob(self):
158+ """WebhookDeliveryJob runs under Celery."""
159+ hook = self.factory.makeWebhook(delivery_url=u'http://hookep.com/foo')
160+
161+ self.useFixture(FeatureFixture(
162+ {'jobs.celery.enabled_classes': 'WebhookDeliveryJob'}))
163+ with block_on_job():
164+ job = WebhookDeliveryJob.create(hook, payload={'foo': 'bar'})
165+ transaction.commit()
166+
167+ self.assertEqual(JobStatus.COMPLETED, job.status)
168+ self.assertIn(
169+ 'Cannot connect to proxy',
170+ job.json_data['result']['connection_error'])