@@ -157,39 +157,136 @@ def test_disable_v2_versioning(
157157
158158
159159@responses .activate
160- def test_trigger_update_version_webhooks (
161- environment_v2_versioning : Environment , feature : Feature
160+ def test_trigger_update_version_webhooks__with_changes (
161+ environment_v2_versioning : Environment ,
162+ feature : Feature ,
163+ staff_user : FFAdminUser ,
162164) -> None :
163165 # Given
164- version = EnvironmentFeatureVersion .objects .get (
166+ v1 = EnvironmentFeatureVersion .objects .get (
165167 feature = feature , environment = environment_v2_versioning
166168 )
167- feature_state = version .feature_states .first ()
169+ v1_fs = v1 .feature_states .first ()
170+
171+ v2 = EnvironmentFeatureVersion .objects .create (
172+ environment = environment_v2_versioning , feature = feature
173+ )
174+ v2_fs = v2 .feature_states .first ()
175+ v2_fs .enabled = not v1_fs .enabled # Make a change
176+ v2_fs .save ()
177+ v2 .publish (published_by = staff_user )
168178
169- webhook_url = "https://example.com/webhook/"
170- Webhook . objects . create ( environment = environment_v2_versioning , url = webhook_url )
179+ # Setup webhooks
180+ from organisations . models import OrganisationWebhook
171181
172- responses .post (url = webhook_url , status = 200 )
182+ environment_webhook_url = "https://example.com/env-webhook/"
183+ organisation_webhook_url = "https://example.com/org-webhook/"
184+ Webhook .objects .create (
185+ environment = environment_v2_versioning , url = environment_webhook_url , enabled = True
186+ )
187+ OrganisationWebhook .objects .create (
188+ organisation = environment_v2_versioning .project .organisation ,
189+ name = "Test Org Webhook" ,
190+ url = organisation_webhook_url ,
191+ enabled = True ,
192+ )
193+ responses .post (url = environment_webhook_url , status = 200 )
194+ responses .post (url = organisation_webhook_url , status = 200 )
173195
174196 # When
175- trigger_update_version_webhooks (str (version .uuid ))
197+ trigger_update_version_webhooks (str (v2 .uuid ))
176198
177199 # Then
178- assert len (responses .calls ) == 1
179- assert responses .calls [0 ].request .url == webhook_url # type: ignore[union-attr]
180- assert json .loads (responses .calls [0 ].request .body ) == { # type: ignore[union-attr]
200+ # Should trigger 3 webhook calls: 2 environment (FLAG_UPDATED + NEW_VERSION_PUBLISHED)
201+ # and 1 organisation (FLAG_UPDATED only)
202+ assert len (responses .calls ) == 3
203+
204+ # Verify FLAG_UPDATED webhook to environment (first call)
205+ flag_updated_env_body = json .loads (responses .calls [0 ].request .body ) # type: ignore[union-attr]
206+ assert flag_updated_env_body ["event_type" ] == WebhookEventType .FLAG_UPDATED .name
207+ assert flag_updated_env_body ["data" ]["new_state" ]["enabled" ] == v2_fs .enabled
208+ assert flag_updated_env_body ["data" ]["new_state" ]["feature" ]["id" ] == feature .id
209+ assert flag_updated_env_body ["data" ]["new_state" ]["feature" ]["name" ] == feature .name
210+ assert (
211+ flag_updated_env_body ["data" ]["new_state" ]["feature_state_value" ]
212+ == v2_fs .get_feature_state_value ()
213+ )
214+ assert flag_updated_env_body ["data" ]["previous_state" ]["enabled" ] == v1_fs .enabled
215+ assert (
216+ flag_updated_env_body ["data" ]["previous_state" ]["feature_state_value" ]
217+ == v1_fs .get_feature_state_value ()
218+ )
219+ assert flag_updated_env_body ["data" ]["changed_by" ] == staff_user .email
220+ assert "timestamp" in flag_updated_env_body ["data" ]
221+
222+ # Verify FLAG_UPDATED webhook to organisation (second call)
223+ flag_updated_org_body = json .loads (responses .calls [1 ].request .body ) # type: ignore[union-attr]
224+ assert flag_updated_org_body == flag_updated_env_body # Should be identical
225+
226+ # Verify NEW_VERSION_PUBLISHED webhook to environment (third call)
227+ new_version_body = json .loads (responses .calls [2 ].request .body ) # type: ignore[union-attr]
228+ assert new_version_body == {
229+ "event_type" : WebhookEventType .NEW_VERSION_PUBLISHED .name ,
181230 "data" : {
182- "uuid" : str (version .uuid ),
231+ "uuid" : str (v2 .uuid ),
183232 "feature" : {"id" : feature .id , "name" : feature .name },
184- "published_by" : None ,
233+ "published_by" : { "id" : staff_user . id , "email" : staff_user . email } ,
185234 "feature_states" : [
186235 {
187- "enabled" : feature_state .enabled ,
188- "value" : feature_state .get_feature_state_value (),
236+ "enabled" : v2_fs .enabled ,
237+ "value" : v2_fs .get_feature_state_value (),
189238 }
190239 ],
191240 },
241+ }
242+
243+
244+ @responses .activate
245+ def test_trigger_update_version_webhooks__without_changes (
246+ environment_v2_versioning : Environment ,
247+ feature : Feature ,
248+ staff_user : FFAdminUser ,
249+ ) -> None :
250+ # Given
251+ v1 = EnvironmentFeatureVersion .objects .get (
252+ feature = feature , environment = environment_v2_versioning
253+ )
254+ v1 .publish (published_by = staff_user )
255+
256+ v2 = EnvironmentFeatureVersion .objects .create (
257+ environment = environment_v2_versioning , feature = feature
258+ )
259+ v2 .publish (published_by = staff_user )
260+
261+ # Setup webhook
262+ environment_webhook_url = "https://example.com/env-webhook/"
263+ Webhook .objects .create (
264+ environment = environment_v2_versioning , url = environment_webhook_url , enabled = True
265+ )
266+ responses .post (url = environment_webhook_url , status = 200 )
267+
268+ # When
269+ trigger_update_version_webhooks (str (v2 .uuid ))
270+
271+ # Then
272+ # Should trigger only 1 webhook call: NEW_VERSION_PUBLISHED (no FLAG_UPDATED since no changes)
273+ assert len (responses .calls ) == 1
274+
275+ # Verify NEW_VERSION_PUBLISHED webhook data
276+ new_version_body = json .loads (responses .calls [0 ].request .body ) # type: ignore[union-attr]
277+ assert new_version_body == {
192278 "event_type" : WebhookEventType .NEW_VERSION_PUBLISHED .name ,
279+ "data" : {
280+ "uuid" : str (v2 .uuid ),
281+ "feature" : {"id" : feature .id , "name" : feature .name },
282+ "published_by" : {"id" : staff_user .id , "email" : staff_user .email },
283+ "feature_states" : [
284+ {
285+ "enabled" : v2 .feature_states .first ().enabled ,
286+ "value" : v2 .feature_states .first ().get_feature_state_value (),
287+ }
288+ ],
289+ },
193290 }
194291
195292
0 commit comments