diff --git a/tests/notification_test.go b/tests/notification_test.go index 450bf4f8..43ccde8d 100644 --- a/tests/notification_test.go +++ b/tests/notification_test.go @@ -145,16 +145,23 @@ var _ = ginkgo.Describe("unsent notification", ginkgo.Ordered, func() { var _ = ginkgo.Describe("basic functionality", func() { - ginkgo.It("should save body for unsent notifications", func() { + ginkgo.It("should update body on duplicate notification", func() { var ( dummyResource = uuid.New() sourceEvent = notification.Events[0] sendStatus = models.NotificationStatusSilenced - body = "Test notification body" + firstBody = "First notification body" + updatedBody = "Updated notification body" ) + // Insert first notification query := "SELECT * FROM insert_unsent_notification_to_history(?, ?, ?, ?, ?, NULL, NULL, NULL, NULL, NULL, NULL, ?)" - err := DefaultContext.DB().Exec(query, notification.ID, sourceEvent, dummyResource, sendStatus, silenceWindow, body).Error + err := DefaultContext.DB().Exec(query, notification.ID, sourceEvent, dummyResource, sendStatus, silenceWindow, firstBody).Error + Expect(err).To(BeNil()) + + // Insert second notification with same parameters but different body + query = "SELECT * FROM insert_unsent_notification_to_history(?, ?, ?, ?, ?, NULL, NULL, NULL, NULL, NULL, NULL, ?)" + err = DefaultContext.DB().Exec(query, notification.ID, sourceEvent, dummyResource, sendStatus, silenceWindow, updatedBody).Error Expect(err).To(BeNil()) var sentHistories []models.NotificationSendHistory @@ -163,32 +170,57 @@ var _ = ginkgo.Describe("unsent notification", ginkgo.Ordered, func() { Where("resource_id = ?", dummyResource). Where("source_event = ?", sourceEvent).Find(&sentHistories).Error Expect(err).To(BeNil()) - Expect(len(sentHistories)).To(Equal(1)) + Expect(len(sentHistories)).To(Equal(1), "Expected only one notification due to deduplication") sentHistory := sentHistories[0] - Expect(sentHistory.ResourceID).To(Equal(dummyResource)) - Expect(sentHistory.Status).To(Equal(sendStatus)) + Expect(sentHistory.Count).To(Equal(2), "Expected count to be 2 after duplicate insert") Expect(sentHistory.Body).ToNot(BeNil()) //nolint:staticcheck - Expect(*sentHistory.Body).To(Equal(body)) //nolint:staticcheck + Expect(*sentHistory.Body).To(Equal(updatedBody), "Body should be updated to the newest value") //nolint:staticcheck }) - ginkgo.It("should update body on duplicate notification", func() { + ginkgo.It("should save body_payload for unsent notifications", func() { var ( dummyResource = uuid.New() sourceEvent = notification.Events[0] sendStatus = models.NotificationStatusSilenced - firstBody = "First notification body" - updatedBody = "Updated notification body" + bodyPayload = `{"schema": "test", "data": {"key": "value"}}` + ) + + query := "SELECT * FROM insert_unsent_notification_to_history(?, ?, ?, ?, ?, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?::jsonb)" + err := DefaultContext.DB().Exec(query, notification.ID, sourceEvent, dummyResource, sendStatus, silenceWindow, bodyPayload).Error + Expect(err).To(BeNil()) + + var sentHistories []models.NotificationSendHistory + err = DefaultContext.DB().Model(&models.NotificationSendHistory{}). + Where("status = ?", sendStatus). + Where("resource_id = ?", dummyResource). + Where("source_event = ?", sourceEvent).Find(&sentHistories).Error + Expect(err).To(BeNil()) + Expect(len(sentHistories)).To(Equal(1)) + + sentHistory := sentHistories[0] + Expect(sentHistory.ResourceID).To(Equal(dummyResource)) + Expect(sentHistory.Status).To(Equal(sendStatus)) + Expect(sentHistory.BodyPayload).ToNot(BeNil()) + Expect(string(sentHistory.BodyPayload)).To(MatchJSON(bodyPayload)) + }) + + ginkgo.It("should update body_payload on duplicate notification", func() { + var ( + dummyResource = uuid.New() + sourceEvent = notification.Events[0] + sendStatus = models.NotificationStatusSilenced + firstBodyPayload = `{"schema": "test", "data": {"version": 1}}` + updatedBodyPayload = `{"schema": "test", "data": {"version": 2}}` ) // Insert first notification - query := "SELECT * FROM insert_unsent_notification_to_history(?, ?, ?, ?, ?, NULL, NULL, NULL, NULL, NULL, NULL, ?)" - err := DefaultContext.DB().Exec(query, notification.ID, sourceEvent, dummyResource, sendStatus, silenceWindow, firstBody).Error + query := "SELECT * FROM insert_unsent_notification_to_history(?, ?, ?, ?, ?, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ?::jsonb)" + err := DefaultContext.DB().Exec(query, notification.ID, sourceEvent, dummyResource, sendStatus, silenceWindow, firstBodyPayload).Error Expect(err).To(BeNil()) - // Insert second notification with same parameters but different body - query = "SELECT * FROM insert_unsent_notification_to_history(?, ?, ?, ?, ?, NULL, NULL, NULL, NULL, NULL, NULL, ?)" - err = DefaultContext.DB().Exec(query, notification.ID, sourceEvent, dummyResource, sendStatus, silenceWindow, updatedBody).Error + // Insert second notification with same parameters but different body_payload + err = DefaultContext.DB().Exec(query, notification.ID, sourceEvent, dummyResource, sendStatus, silenceWindow, updatedBodyPayload).Error Expect(err).To(BeNil()) var sentHistories []models.NotificationSendHistory @@ -201,8 +233,8 @@ var _ = ginkgo.Describe("unsent notification", ginkgo.Ordered, func() { sentHistory := sentHistories[0] Expect(sentHistory.Count).To(Equal(2), "Expected count to be 2 after duplicate insert") - Expect(sentHistory.Body).ToNot(BeNil()) //nolint:staticcheck - Expect(*sentHistory.Body).To(Equal(updatedBody), "Body should be updated to the newest value") //nolint:staticcheck + Expect(sentHistory.BodyPayload).ToNot(BeNil()) + Expect(string(sentHistory.BodyPayload)).To(MatchJSON(updatedBodyPayload), "BodyPayload should be updated to the newest value") }) }) }) diff --git a/views/021_notification.sql b/views/021_notification.sql index e2ebc0ce..72a77ea0 100644 --- a/views/021_notification.sql +++ b/views/021_notification.sql @@ -37,6 +37,7 @@ CREATE OR REPLACE TRIGGER reset_notification_silence_error_before_update_trigger -- Ensure the previous function is cleaned up. DROP FUNCTION IF EXISTS insert_unsent_notification_to_history(uuid, text, uuid, text, interval); +DROP FUNCTION IF EXISTS insert_unsent_notification_to_history(uuid, text, uuid, text, interval, uuid, uuid, uuid, uuid, uuid, uuid, text); --- A function to insert only those notifications that were unsent. --- It deals with the deduplication of inserting the same notification again if it was silenced or blocked by repeatInterval. @@ -52,7 +53,8 @@ CREATE OR REPLACE FUNCTION insert_unsent_notification_to_history ( p_team_id uuid DEFAULT NULL, p_connection_id uuid DEFAULT NULL, p_playbook_run_id uuid DEFAULT NULL, - p_body text DEFAULT NULL + p_body text DEFAULT NULL, + p_body_payload jsonb DEFAULT NULL ) RETURNS VOID AS $$ @@ -84,12 +86,13 @@ BEGIN SET count = count + 1, body = p_body, + body_payload = p_body_payload, created_at = CURRENT_TIMESTAMP WHERE id = v_existing_id; ELSE - INSERT INTO notification_send_history (notification_id, status, source_event, resource_id, parent_id, silenced_by, person_id, team_id, connection_id, playbook_run_id, body) - VALUES (p_notification_id, p_status, p_source_event, p_resource_id, p_parent_id, p_silenced_by, p_person_id, p_team_id, p_connection_id, p_playbook_run_id, p_body); + INSERT INTO notification_send_history (notification_id, status, source_event, resource_id, parent_id, silenced_by, person_id, team_id, connection_id, playbook_run_id, body, body_payload) + VALUES (p_notification_id, p_status, p_source_event, p_resource_id, p_parent_id, p_silenced_by, p_person_id, p_team_id, p_connection_id, p_playbook_run_id, p_body, p_body_payload); END IF; END; $$