Merge lp:~wgrant/launchpad/webhook-event-types into lp:launchpad
- webhook-event-types
- Merge into devel
Proposed by
William Grant
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 17687 | ||||
Proposed branch: | lp:~wgrant/launchpad/webhook-event-types | ||||
Merge into: | lp:launchpad | ||||
Diff against target: |
334 lines (+96/-20) 7 files modified
lib/lp/services/webhooks/browser.py (+7/-4) lib/lp/services/webhooks/configure.zcml (+9/-0) lib/lp/services/webhooks/interfaces.py (+18/-3) lib/lp/services/webhooks/model.py (+2/-0) lib/lp/services/webhooks/tests/test_browser.py (+6/-5) lib/lp/services/webhooks/tests/test_model.py (+19/-0) lib/lp/services/webhooks/tests/test_webservice.py (+35/-8) |
||||
To merge this branch: | bzr merge lp:~wgrant/launchpad/webhook-event-types | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Launchpad code reviewers | Pending | ||
Review via email: mp+267470@code.launchpad.net |
Commit message
Improve Webhook.event_types widget and value checking.
Description of the change
Improve Webhook.event_types widget and value checking.
Rather than a weird Zopey text list widget, there's now a set of checkboxes for each known event type. I've eschewed a normal enum due to the non-DB-column and potentially fluid nature of event types; a custom vocabulary is easy and makes migration easier when we change things later.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/lp/services/webhooks/browser.py' | |||
2 | --- lib/lp/services/webhooks/browser.py 2015-08-04 13:18:24 +0000 | |||
3 | +++ lib/lp/services/webhooks/browser.py 2015-08-10 06:17:10 +0000 | |||
4 | @@ -16,9 +16,11 @@ | |||
5 | 16 | 16 | ||
6 | 17 | from lp.app.browser.launchpadform import ( | 17 | from lp.app.browser.launchpadform import ( |
7 | 18 | action, | 18 | action, |
8 | 19 | custom_widget, | ||
9 | 19 | LaunchpadEditFormView, | 20 | LaunchpadEditFormView, |
10 | 20 | LaunchpadFormView, | 21 | LaunchpadFormView, |
11 | 21 | ) | 22 | ) |
12 | 23 | from lp.app.widgets.itemswidgets import LabeledMultiCheckBoxWidget | ||
13 | 22 | from lp.services.propertycache import cachedproperty | 24 | from lp.services.propertycache import cachedproperty |
14 | 23 | from lp.services.webapp import ( | 25 | from lp.services.webapp import ( |
15 | 24 | canonical_url, | 26 | canonical_url, |
16 | @@ -103,8 +105,7 @@ | |||
17 | 103 | 105 | ||
18 | 104 | 106 | ||
19 | 105 | class WebhookEditSchema(Interface): | 107 | class WebhookEditSchema(Interface): |
22 | 106 | # XXX wgrant 2015-08-04: Need custom widgets for secret and | 108 | # XXX wgrant 2015-08-04: Need custom widget for secret. |
21 | 107 | # event_types. | ||
23 | 108 | use_template(IWebhook, include=['delivery_url', 'event_types', 'active']) | 109 | use_template(IWebhook, include=['delivery_url', 'event_types', 'active']) |
24 | 109 | 110 | ||
25 | 110 | 111 | ||
26 | @@ -113,6 +114,7 @@ | |||
27 | 113 | page_title = label = "Add webhook" | 114 | page_title = label = "Add webhook" |
28 | 114 | 115 | ||
29 | 115 | schema = WebhookEditSchema | 116 | schema = WebhookEditSchema |
30 | 117 | custom_widget('event_types', LabeledMultiCheckBoxWidget) | ||
31 | 116 | 118 | ||
32 | 117 | @property | 119 | @property |
33 | 118 | def inside_breadcrumb(self): | 120 | def inside_breadcrumb(self): |
34 | @@ -136,10 +138,11 @@ | |||
35 | 136 | 138 | ||
36 | 137 | class WebhookView(LaunchpadEditFormView): | 139 | class WebhookView(LaunchpadEditFormView): |
37 | 138 | 140 | ||
38 | 139 | schema = WebhookEditSchema | ||
39 | 140 | |||
40 | 141 | label = "Manage webhook" | 141 | label = "Manage webhook" |
41 | 142 | 142 | ||
42 | 143 | schema = WebhookEditSchema | ||
43 | 144 | custom_widget('event_types', LabeledMultiCheckBoxWidget) | ||
44 | 145 | |||
45 | 143 | @property | 146 | @property |
46 | 144 | def next_url(self): | 147 | def next_url(self): |
47 | 145 | # The edit form is the default view, so the URL doesn't need the | 148 | # The edit form is the default view, so the URL doesn't need the |
48 | 146 | 149 | ||
49 | === modified file 'lib/lp/services/webhooks/configure.zcml' | |||
50 | --- lib/lp/services/webhooks/configure.zcml 2015-08-04 11:02:02 +0000 | |||
51 | +++ lib/lp/services/webhooks/configure.zcml 2015-08-10 06:17:10 +0000 | |||
52 | @@ -21,6 +21,15 @@ | |||
53 | 21 | provides="lp.services.webhooks.interfaces.IWebhookSource"> | 21 | provides="lp.services.webhooks.interfaces.IWebhookSource"> |
54 | 22 | <allow interface="lp.services.webhooks.interfaces.IWebhookSource"/> | 22 | <allow interface="lp.services.webhooks.interfaces.IWebhookSource"/> |
55 | 23 | </securedutility> | 23 | </securedutility> |
56 | 24 | <securedutility | ||
57 | 25 | name="WebhookEventType" | ||
58 | 26 | component="lp.services.webhooks.interfaces.WebhookEventTypeVocabulary" | ||
59 | 27 | provides="zope.schema.interfaces.IVocabularyFactory"> | ||
60 | 28 | <allow interface="zope.schema.interfaces.IVocabularyFactory"/> | ||
61 | 29 | </securedutility> | ||
62 | 30 | <class class="lp.services.webhooks.interfaces.WebhookEventTypeVocabulary"> | ||
63 | 31 | <allow interface="zope.schema.interfaces.IVocabularyTokenized"/> | ||
64 | 32 | </class> | ||
65 | 24 | 33 | ||
66 | 25 | <securedutility | 34 | <securedutility |
67 | 26 | component="lp.services.webhooks.model.WebhookJob" | 35 | component="lp.services.webhooks.model.WebhookJob" |
68 | 27 | 36 | ||
69 | === modified file 'lib/lp/services/webhooks/interfaces.py' | |||
70 | --- lib/lp/services/webhooks/interfaces.py 2015-08-04 13:59:25 +0000 | |||
71 | +++ lib/lp/services/webhooks/interfaces.py 2015-08-10 06:17:10 +0000 | |||
72 | @@ -17,6 +17,7 @@ | |||
73 | 17 | 'WebhookDeliveryFailure', | 17 | 'WebhookDeliveryFailure', |
74 | 18 | 'WebhookDeliveryRetry', | 18 | 'WebhookDeliveryRetry', |
75 | 19 | 'WebhookFeatureDisabled', | 19 | 'WebhookFeatureDisabled', |
76 | 20 | 'WebhookEventTypeVocabulary', | ||
77 | 20 | ] | 21 | ] |
78 | 21 | 22 | ||
79 | 22 | import httplib | 23 | import httplib |
80 | @@ -45,12 +46,14 @@ | |||
81 | 45 | ) | 46 | ) |
82 | 46 | from zope.schema import ( | 47 | from zope.schema import ( |
83 | 47 | Bool, | 48 | Bool, |
84 | 49 | Choice, | ||
85 | 48 | Datetime, | 50 | Datetime, |
86 | 49 | Dict, | 51 | Dict, |
87 | 50 | Int, | 52 | Int, |
88 | 51 | List, | 53 | List, |
89 | 52 | TextLine, | 54 | TextLine, |
90 | 53 | ) | 55 | ) |
91 | 56 | from zope.schema.vocabulary import SimpleVocabulary | ||
92 | 54 | 57 | ||
93 | 55 | from lp import _ | 58 | from lp import _ |
94 | 56 | from lp.registry.interfaces.person import IPerson | 59 | from lp.registry.interfaces.person import IPerson |
95 | @@ -67,6 +70,11 @@ | |||
96 | 67 | ) | 70 | ) |
97 | 68 | 71 | ||
98 | 69 | 72 | ||
99 | 73 | WEBHOOK_EVENT_TYPES = { | ||
100 | 74 | "git:push:0.1": "Git push", | ||
101 | 75 | } | ||
102 | 76 | |||
103 | 77 | |||
104 | 70 | @error_status(httplib.UNAUTHORIZED) | 78 | @error_status(httplib.UNAUTHORIZED) |
105 | 71 | class WebhookFeatureDisabled(Exception): | 79 | class WebhookFeatureDisabled(Exception): |
106 | 72 | """Only certain users can create new Git repositories.""" | 80 | """Only certain users can create new Git repositories.""" |
107 | @@ -86,6 +94,15 @@ | |||
108 | 86 | pass | 94 | pass |
109 | 87 | 95 | ||
110 | 88 | 96 | ||
111 | 97 | class WebhookEventTypeVocabulary(SimpleVocabulary): | ||
112 | 98 | |||
113 | 99 | def __init__(self, context): | ||
114 | 100 | terms = [ | ||
115 | 101 | self.createTerm(key, key, value) | ||
116 | 102 | for key, value in WEBHOOK_EVENT_TYPES.iteritems()] | ||
117 | 103 | super(WebhookEventTypeVocabulary, self).__init__(terms) | ||
118 | 104 | |||
119 | 105 | |||
120 | 89 | class IWebhook(Interface): | 106 | class IWebhook(Interface): |
121 | 90 | 107 | ||
122 | 91 | export_as_webservice_entry(as_of='beta') | 108 | export_as_webservice_entry(as_of='beta') |
123 | @@ -97,9 +114,7 @@ | |||
124 | 97 | required=True, readonly=True, | 114 | required=True, readonly=True, |
125 | 98 | description=_("The object for which this webhook receives events."))) | 115 | description=_("The object for which this webhook receives events."))) |
126 | 99 | event_types = exported(List( | 116 | event_types = exported(List( |
130 | 100 | TextLine(), title=_("Event types"), | 117 | Choice(vocabulary='WebhookEventType'), title=_("Event types"), |
128 | 101 | description=_( | ||
129 | 102 | "The event types for which this webhook receives events."), | ||
131 | 103 | required=True, readonly=False)) | 118 | required=True, readonly=False)) |
132 | 104 | registrant = exported(Reference( | 119 | registrant = exported(Reference( |
133 | 105 | title=_("Registrant"), schema=IPerson, required=True, readonly=True, | 120 | title=_("Registrant"), schema=IPerson, required=True, readonly=True, |
134 | 106 | 121 | ||
135 | === modified file 'lib/lp/services/webhooks/model.py' | |||
136 | --- lib/lp/services/webhooks/model.py 2015-08-04 13:59:25 +0000 | |||
137 | +++ lib/lp/services/webhooks/model.py 2015-08-10 06:17:10 +0000 | |||
138 | @@ -140,6 +140,8 @@ | |||
139 | 140 | @event_types.setter | 140 | @event_types.setter |
140 | 141 | def event_types(self, event_types): | 141 | def event_types(self, event_types): |
141 | 142 | updated_data = self.json_data or {} | 142 | updated_data = self.json_data or {} |
142 | 143 | # The correctness of the values is also checked by zope.schema, | ||
143 | 144 | # but best to be safe. | ||
144 | 143 | assert isinstance(event_types, (list, tuple)) | 145 | assert isinstance(event_types, (list, tuple)) |
145 | 144 | assert all(isinstance(v, basestring) for v in event_types) | 146 | assert all(isinstance(v, basestring) for v in event_types) |
146 | 145 | updated_data['event_types'] = event_types | 147 | updated_data['event_types'] = event_types |
147 | 146 | 148 | ||
148 | === modified file 'lib/lp/services/webhooks/tests/test_browser.py' | |||
149 | --- lib/lp/services/webhooks/tests/test_browser.py 2015-08-04 13:18:24 +0000 | |||
150 | +++ lib/lp/services/webhooks/tests/test_browser.py 2015-08-10 06:17:10 +0000 | |||
151 | @@ -149,7 +149,8 @@ | |||
152 | 149 | "+new-webhook", method="POST", | 149 | "+new-webhook", method="POST", |
153 | 150 | form={ | 150 | form={ |
154 | 151 | "field.delivery_url": "http://example.com/test", | 151 | "field.delivery_url": "http://example.com/test", |
156 | 152 | "field.active": "on", "field.event_types.count": "0", | 152 | "field.active": "on", "field.event_types-empty-marker": "1", |
157 | 153 | "field.event_types": "git:push:0.1", | ||
158 | 153 | "field.actions.new": "Add webhook"}) | 154 | "field.actions.new": "Add webhook"}) |
159 | 154 | self.assertEqual([], view.errors) | 155 | self.assertEqual([], view.errors) |
160 | 155 | hook = self.target.webhooks.one() | 156 | hook = self.target.webhooks.one() |
161 | @@ -160,7 +161,7 @@ | |||
162 | 160 | registrant=self.owner, | 161 | registrant=self.owner, |
163 | 161 | delivery_url="http://example.com/test", | 162 | delivery_url="http://example.com/test", |
164 | 162 | active=True, | 163 | active=True, |
166 | 163 | event_types=[])) | 164 | event_types=["git:push:0.1"])) |
167 | 164 | 165 | ||
168 | 165 | def test_rejects_bad_scheme(self): | 166 | def test_rejects_bad_scheme(self): |
169 | 166 | transaction.commit() | 167 | transaction.commit() |
170 | @@ -168,7 +169,7 @@ | |||
171 | 168 | "+new-webhook", method="POST", | 169 | "+new-webhook", method="POST", |
172 | 169 | form={ | 170 | form={ |
173 | 170 | "field.delivery_url": "ftp://example.com/test", | 171 | "field.delivery_url": "ftp://example.com/test", |
175 | 171 | "field.active": "on", "field.event_types.count": "0", | 172 | "field.active": "on", "field.event_types-empty-marker": "1", |
176 | 172 | "field.actions.new": "Add webhook"}) | 173 | "field.actions.new": "Add webhook"}) |
177 | 173 | self.assertEqual( | 174 | self.assertEqual( |
178 | 174 | ['delivery_url'], [error.field_name for error in view.errors]) | 175 | ['delivery_url'], [error.field_name for error in view.errors]) |
179 | @@ -220,7 +221,7 @@ | |||
180 | 220 | "+index", method="POST", | 221 | "+index", method="POST", |
181 | 221 | form={ | 222 | form={ |
182 | 222 | "field.delivery_url": "http://example.com/edited", | 223 | "field.delivery_url": "http://example.com/edited", |
184 | 223 | "field.active": "off", "field.event_types.count": "0", | 224 | "field.active": "off", "field.event_types-empty-marker": "1", |
185 | 224 | "field.actions.save": "Save webhook"}) | 225 | "field.actions.save": "Save webhook"}) |
186 | 225 | self.assertEqual([], view.errors) | 226 | self.assertEqual([], view.errors) |
187 | 226 | self.assertThat( | 227 | self.assertThat( |
188 | @@ -236,7 +237,7 @@ | |||
189 | 236 | "+index", method="POST", | 237 | "+index", method="POST", |
190 | 237 | form={ | 238 | form={ |
191 | 238 | "field.delivery_url": "ftp://example.com/edited", | 239 | "field.delivery_url": "ftp://example.com/edited", |
193 | 239 | "field.active": "off", "field.event_types.count": "0", | 240 | "field.active": "off", "field.event_types-empty-marker": "1", |
194 | 240 | "field.actions.save": "Save webhook"}) | 241 | "field.actions.save": "Save webhook"}) |
195 | 241 | self.assertEqual( | 242 | self.assertEqual( |
196 | 242 | ['delivery_url'], [error.field_name for error in view.errors]) | 243 | ['delivery_url'], [error.field_name for error in view.errors]) |
197 | 243 | 244 | ||
198 | === modified file 'lib/lp/services/webhooks/tests/test_model.py' | |||
199 | --- lib/lp/services/webhooks/tests/test_model.py 2015-08-04 05:46:54 +0000 | |||
200 | +++ lib/lp/services/webhooks/tests/test_model.py 2015-08-10 06:17:10 +0000 | |||
201 | @@ -22,6 +22,7 @@ | |||
202 | 22 | from lp.testing import ( | 22 | from lp.testing import ( |
203 | 23 | admin_logged_in, | 23 | admin_logged_in, |
204 | 24 | anonymous_logged_in, | 24 | anonymous_logged_in, |
205 | 25 | ExpectedException, | ||
206 | 25 | login_person, | 26 | login_person, |
207 | 26 | person_logged_in, | 27 | person_logged_in, |
208 | 27 | StormStatementRecorder, | 28 | StormStatementRecorder, |
209 | @@ -49,6 +50,24 @@ | |||
210 | 49 | webhook.date_last_modified, | 50 | webhook.date_last_modified, |
211 | 50 | GreaterThan(old_mtime)) | 51 | GreaterThan(old_mtime)) |
212 | 51 | 52 | ||
213 | 53 | def test_event_types(self): | ||
214 | 54 | # Webhook.event_types is a list of event type strings. | ||
215 | 55 | webhook = self.factory.makeWebhook() | ||
216 | 56 | with admin_logged_in(): | ||
217 | 57 | self.assertContentEqual([], webhook.event_types) | ||
218 | 58 | webhook.event_types = ['foo', 'bar'] | ||
219 | 59 | self.assertContentEqual(['foo', 'bar'], webhook.event_types) | ||
220 | 60 | |||
221 | 61 | def test_event_types_bad_structure(self): | ||
222 | 62 | # It's not possible to set Webhook.event_types to a list of the | ||
223 | 63 | # wrong type. | ||
224 | 64 | webhook = self.factory.makeWebhook() | ||
225 | 65 | with admin_logged_in(): | ||
226 | 66 | self.assertContentEqual([], webhook.event_types) | ||
227 | 67 | with ExpectedException(AssertionError, '.*'): | ||
228 | 68 | webhook.event_types = ['foo', [1]] | ||
229 | 69 | self.assertContentEqual([], webhook.event_types) | ||
230 | 70 | |||
231 | 52 | 71 | ||
232 | 53 | class TestWebhookPermissions(TestCaseWithFactory): | 72 | class TestWebhookPermissions(TestCaseWithFactory): |
233 | 54 | 73 | ||
234 | 55 | 74 | ||
235 | === modified file 'lib/lp/services/webhooks/tests/test_webservice.py' | |||
236 | --- lib/lp/services/webhooks/tests/test_webservice.py 2015-08-04 05:44:42 +0000 | |||
237 | +++ lib/lp/services/webhooks/tests/test_webservice.py 2015-08-10 06:17:10 +0000 | |||
238 | @@ -16,6 +16,7 @@ | |||
239 | 16 | Is, | 16 | Is, |
240 | 17 | KeysEqual, | 17 | KeysEqual, |
241 | 18 | MatchesAll, | 18 | MatchesAll, |
242 | 19 | MatchesStructure, | ||
243 | 19 | Not, | 20 | Not, |
244 | 20 | ) | 21 | ) |
245 | 21 | from zope.security.proxy import removeSecurityProxy | 22 | from zope.security.proxy import removeSecurityProxy |
246 | @@ -73,7 +74,7 @@ | |||
247 | 73 | old_mtime = representation['date_last_modified'] | 74 | old_mtime = representation['date_last_modified'] |
248 | 74 | patch = json.dumps( | 75 | patch = json.dumps( |
249 | 75 | {'active': False, 'delivery_url': 'http://example.com/ep2', | 76 | {'active': False, 'delivery_url': 'http://example.com/ep2', |
251 | 76 | 'event_types': ['foo', 'bar']}) | 77 | 'event_types': ['git:push:0.1']}) |
252 | 77 | self.webservice.patch( | 78 | self.webservice.patch( |
253 | 78 | self.webhook_url, 'application/json', patch, api_version='devel') | 79 | self.webhook_url, 'application/json', patch, api_version='devel') |
254 | 79 | representation = self.webservice.get( | 80 | representation = self.webservice.get( |
255 | @@ -84,7 +85,33 @@ | |||
256 | 84 | {'active': Equals(False), | 85 | {'active': Equals(False), |
257 | 85 | 'delivery_url': Equals('http://example.com/ep2'), | 86 | 'delivery_url': Equals('http://example.com/ep2'), |
258 | 86 | 'date_last_modified': GreaterThan(old_mtime), | 87 | 'date_last_modified': GreaterThan(old_mtime), |
260 | 87 | 'event_types': Equals(['foo', 'bar'])})) | 88 | 'event_types': Equals(['git:push:0.1'])})) |
261 | 89 | |||
262 | 90 | def test_patch_event_types(self): | ||
263 | 91 | representation = self.webservice.get( | ||
264 | 92 | self.webhook_url, api_version='devel').jsonBody() | ||
265 | 93 | self.assertThat( | ||
266 | 94 | representation, ContainsDict({'event_types': Equals([])})) | ||
267 | 95 | |||
268 | 96 | # Including a valid type in event_types works. | ||
269 | 97 | response = self.webservice.patch( | ||
270 | 98 | self.webhook_url, 'application/json', | ||
271 | 99 | json.dumps({'event_types': ['git:push:0.1']}), api_version='devel') | ||
272 | 100 | self.assertEqual(209, response.status) | ||
273 | 101 | representation = self.webservice.get( | ||
274 | 102 | self.webhook_url, api_version='devel').jsonBody() | ||
275 | 103 | self.assertThat( | ||
276 | 104 | representation, | ||
277 | 105 | ContainsDict({'event_types': Equals(['git:push:0.1'])})) | ||
278 | 106 | |||
279 | 107 | # But an unknown type is rejected. | ||
280 | 108 | response = self.webservice.patch( | ||
281 | 109 | self.webhook_url, 'application/json', | ||
282 | 110 | json.dumps({'event_types': ['hg:push:0.1']}), api_version='devel') | ||
283 | 111 | self.assertThat(response, | ||
284 | 112 | MatchesStructure.byEquality( | ||
285 | 113 | status=400, | ||
286 | 114 | body="event_types: u'hg:push:0.1' isn't a valid token")) | ||
287 | 88 | 115 | ||
288 | 89 | def test_anon_forbidden(self): | 116 | def test_anon_forbidden(self): |
289 | 90 | response = LaunchpadWebServiceCaller().get( | 117 | response = LaunchpadWebServiceCaller().get( |
290 | @@ -279,14 +306,14 @@ | |||
291 | 279 | self.useFixture(FeatureFixture({'webhooks.new.enabled': 'true'})) | 306 | self.useFixture(FeatureFixture({'webhooks.new.enabled': 'true'})) |
292 | 280 | response = self.webservice.named_post( | 307 | response = self.webservice.named_post( |
293 | 281 | self.target_url, 'newWebhook', | 308 | self.target_url, 'newWebhook', |
296 | 282 | delivery_url='http://example.com/ep', event_types=['foo', 'bar'], | 309 | delivery_url='http://example.com/ep', |
297 | 283 | api_version='devel') | 310 | event_types=['git:push:0.1'], api_version='devel') |
298 | 284 | self.assertEqual(201, response.status) | 311 | self.assertEqual(201, response.status) |
299 | 285 | 312 | ||
300 | 286 | representation = self.webservice.get( | 313 | representation = self.webservice.get( |
301 | 287 | self.target_url + '/webhooks', api_version='devel').jsonBody() | 314 | self.target_url + '/webhooks', api_version='devel').jsonBody() |
302 | 288 | self.assertContentEqual( | 315 | self.assertContentEqual( |
304 | 289 | [('http://example.com/ep', ['foo', 'bar'], True)], | 316 | [('http://example.com/ep', ['git:push:0.1'], True)], |
305 | 290 | [(entry['delivery_url'], entry['event_types'], entry['active']) | 317 | [(entry['delivery_url'], entry['event_types'], entry['active']) |
306 | 291 | for entry in representation['entries']]) | 318 | for entry in representation['entries']]) |
307 | 292 | 319 | ||
308 | @@ -294,7 +321,7 @@ | |||
309 | 294 | self.useFixture(FeatureFixture({'webhooks.new.enabled': 'true'})) | 321 | self.useFixture(FeatureFixture({'webhooks.new.enabled': 'true'})) |
310 | 295 | response = self.webservice.named_post( | 322 | response = self.webservice.named_post( |
311 | 296 | self.target_url, 'newWebhook', | 323 | self.target_url, 'newWebhook', |
313 | 297 | delivery_url='http://example.com/ep', event_types=['foo', 'bar'], | 324 | delivery_url='http://example.com/ep', event_types=['git:push:0.1'], |
314 | 298 | secret='sekrit', api_version='devel') | 325 | secret='sekrit', api_version='devel') |
315 | 299 | self.assertEqual(201, response.status) | 326 | self.assertEqual(201, response.status) |
316 | 300 | 327 | ||
317 | @@ -310,7 +337,7 @@ | |||
318 | 310 | webservice = LaunchpadWebServiceCaller() | 337 | webservice = LaunchpadWebServiceCaller() |
319 | 311 | response = webservice.named_post( | 338 | response = webservice.named_post( |
320 | 312 | self.target_url, 'newWebhook', | 339 | self.target_url, 'newWebhook', |
322 | 313 | delivery_url='http://example.com/ep', event_types=['foo', 'bar'], | 340 | delivery_url='http://example.com/ep', event_types=['git:push:0.1'], |
323 | 314 | api_version='devel') | 341 | api_version='devel') |
324 | 315 | self.assertEqual(401, response.status) | 342 | self.assertEqual(401, response.status) |
325 | 316 | self.assertIn('launchpad.Edit', response.body) | 343 | self.assertIn('launchpad.Edit', response.body) |
326 | @@ -318,7 +345,7 @@ | |||
327 | 318 | def test_newWebhook_feature_flag_guard(self): | 345 | def test_newWebhook_feature_flag_guard(self): |
328 | 319 | response = self.webservice.named_post( | 346 | response = self.webservice.named_post( |
329 | 320 | self.target_url, 'newWebhook', | 347 | self.target_url, 'newWebhook', |
331 | 321 | delivery_url='http://example.com/ep', event_types=['foo', 'bar'], | 348 | delivery_url='http://example.com/ep', event_types=['git:push:0.1'], |
332 | 322 | api_version='devel') | 349 | api_version='devel') |
333 | 323 | self.assertEqual(401, response.status) | 350 | self.assertEqual(401, response.status) |
334 | 324 | self.assertEqual( | 351 | self.assertEqual( |