Skip to content

Commit d1bc898

Browse files
authored
[IOCOM-2285] Call sending-func notify endpoint instead of the backend one (#317)
1 parent a21b1db commit d1bc898

File tree

8 files changed

+199
-316
lines changed

8 files changed

+199
-316
lines changed

WebhookNotification/__tests__/handler.test.ts

Lines changed: 26 additions & 208 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
import { CreatedMessageEventSenderMetadata } from "@pagopa/io-functions-commons/dist/src/models/created_message_sender_metadata";
1616
import { Notification } from "@pagopa/io-functions-commons/dist/src/models/notification";
1717
import { isTransientError } from "@pagopa/io-functions-commons/dist/src/utils/errors";
18-
import { PushNotificationsContentTypeEnum } from "@pagopa/io-functions-commons/dist/generated/definitions/PushNotificationsContentType";
1918

2019
import { getWebhookNotificationHandler, sendToWebhook } from "../handler";
2120

@@ -39,16 +38,6 @@ import * as TE from "fp-ts/lib/TaskEither";
3938
import * as O from "fp-ts/lib/Option";
4039
import { StandardServiceCategoryEnum } from "@pagopa/io-functions-admin-sdk/StandardServiceCategory";
4140

42-
import { toInternalError, toNotFoundError } from "../../utils/domain-errors";
43-
import { UserProfileReader } from "../../readers/user-profile";
44-
45-
import { aRetrievedProfile } from "../../__mocks__/mocks";
46-
47-
const mockAppinsights = {
48-
trackDependency: jest.fn(),
49-
trackEvent: jest.fn()
50-
};
51-
5241
const aFiscalCode = "FRLFRC74E04B157I" as FiscalCode;
5342

5443
const aMessageId = "A_MESSAGE_ID" as NonEmptyString;
@@ -132,124 +121,45 @@ const aCommonMessageData = {
132121
senderMetadata: aSenderMetadata
133122
};
134123

135-
const aRetrievedProfileWithFullPushNotificationsContentType = {
136-
...aRetrievedProfile,
137-
pushNotificationsContentType: PushNotificationsContentTypeEnum.FULL
138-
};
139-
140124
const mockRetrieveProcessingMessageData = jest
141125
.fn()
142126
.mockImplementation(() => TE.of(O.some(aCommonMessageData)));
143127

144-
const userProfileReaderMock = jest.fn(
145-
_ => TE.of(aRetrievedProfile) as ReturnType<UserProfileReader>
146-
);
147-
148128
beforeEach(() => {
149129
jest.clearAllMocks();
150130
});
151131

152132
describe("sendToWebhook", () => {
153133
it("should succeded with right parameters, with message content", async () => {
154-
const expectedResponse = { message: "OK" };
155-
const fetchApi = mockFetch(200, expectedResponse);
156-
const notifyApiCall = getNotifyClient(fetchApi as any);
157-
const ret = await sendToWebhook(
158-
notifyApiCall,
159-
"http://localhost/test" as HttpsUrl,
160-
aMessage as any,
161-
aMessageContent,
162-
aSenderMetadata,
163-
aRetrievedProfileWithFullPushNotificationsContentType,
164-
false
165-
)();
166-
167-
expect(fetchApi.mock.calls[0][1]).toHaveProperty("body");
168-
const body = JSON.parse(fetchApi.mock.calls[0][1].body);
169-
expect(body).toHaveProperty("message");
170-
expect(body).toHaveProperty("sender_metadata");
171-
expect(body.message).toHaveProperty("content");
172-
expect(E.isRight(ret)).toBeTruthy();
173-
});
174-
175-
it("should remove message content if the service require secure channel", async () => {
176-
const expectedResponse = { message: "OK" };
177-
const fetchApi = mockFetch(200, expectedResponse);
178-
const notifyApiCall = getNotifyClient(fetchApi as any);
179-
const ret = await sendToWebhook(
180-
notifyApiCall,
181-
"http://localhost/test" as HttpsUrl,
182-
aMessage as any,
183-
aMessageContent,
184-
{
185-
...aSenderMetadata,
186-
requireSecureChannels: true
187-
},
188-
aRetrievedProfileWithFullPushNotificationsContentType,
189-
false
190-
)();
191-
expect(fetchApi.mock.calls[0][1]).toHaveProperty("body");
192-
const body = JSON.parse(fetchApi.mock.calls[0][1].body);
193-
expect(body).toHaveProperty("message");
194-
expect(body).toHaveProperty("sender_metadata");
195-
expect(body.message).not.toHaveProperty("content");
196-
expect(E.isRight(ret)).toBeTruthy();
197-
});
198-
199-
it("should remove message content if webhook message content is disabled", async () => {
200-
const expectedResponse = { message: "OK" };
201-
const fetchApi = mockFetch(200, expectedResponse);
202-
const notifyApiCall = getNotifyClient(fetchApi as any);
134+
const expectedResponse = {};
135+
const fetchApi = mockFetch(204, expectedResponse);
136+
const notifyApiCall = getNotifyClient(fetchApi as any, "aValidApiKey");
203137
const ret = await sendToWebhook(
204138
notifyApiCall,
205139
"http://localhost/test" as HttpsUrl,
206-
aMessage as any,
207-
aMessageContent,
208-
aSenderMetadata,
209-
aRetrievedProfileWithFullPushNotificationsContentType,
210-
true
140+
aMessage as any
211141
)();
212-
expect(fetchApi.mock.calls[0][1]).toHaveProperty("body");
213-
const body = JSON.parse(fetchApi.mock.calls[0][1].body);
214-
expect(body).toHaveProperty("message");
215-
expect(body).toHaveProperty("sender_metadata");
216-
expect(body.message).not.toHaveProperty("content");
217-
expect(E.isRight(ret)).toBeTruthy();
218-
});
219142

220-
it("should remove message content if user did not allow verbose notifications", async () => {
221-
const expectedResponse = { message: "OK" };
222-
const fetchApi = mockFetch(200, expectedResponse);
223-
const notifyApiCall = getNotifyClient(fetchApi as any);
224-
const ret = await sendToWebhook(
225-
notifyApiCall,
226-
"http://localhost/test" as HttpsUrl,
227-
aMessage as any,
228-
aMessageContent,
229-
aSenderMetadata,
230-
aRetrievedProfile,
231-
false
232-
)();
233143
expect(fetchApi.mock.calls[0][1]).toHaveProperty("body");
234144
const body = JSON.parse(fetchApi.mock.calls[0][1].body);
235-
expect(body).toHaveProperty("message");
236-
expect(body).toHaveProperty("sender_metadata");
237-
expect(body.message).not.toHaveProperty("content");
145+
expect(body).toHaveProperty("fiscal_code");
146+
expect(body).toHaveProperty("notification_type");
147+
expect(body).toHaveProperty("message_id");
148+
expect(body).toHaveProperty("webhookEndpoint");
238149
expect(E.isRight(ret)).toBeTruthy();
239150
});
240151

241152
it("should return a transient error in case of timeout", async () => {
242153
const abortableFetch = AbortableFetch(agent.getHttpsFetch(process.env));
243154
const fetchWithTimeout = setFetchTimeout(1 as Millisecond, abortableFetch);
244-
const notifyApiCall = getNotifyClient(toFetch(fetchWithTimeout));
155+
const notifyApiCall = getNotifyClient(
156+
toFetch(fetchWithTimeout),
157+
"aValidApiKey"
158+
);
245159
const ret = await sendToWebhook(
246160
notifyApiCall,
247161
"http://localhost/test" as HttpsUrl,
248-
aMessage as any,
249-
aMessageContent,
250-
aSenderMetadata,
251-
aRetrievedProfile,
252-
false
162+
aMessage as any
253163
)();
254164
expect(E.isLeft(ret)).toBeTruthy();
255165
if (E.isLeft(ret)) {
@@ -259,16 +169,8 @@ describe("sendToWebhook", () => {
259169

260170
it("should return a transient error in case the webhook returns HTTP status 5xx", async () => {
261171
const fetchApi = mockFetch(500, { status: 500 });
262-
const notifyApiCall = getNotifyClient(fetchApi as any);
263-
const ret = await sendToWebhook(
264-
notifyApiCall,
265-
{} as any,
266-
{} as any,
267-
{} as any,
268-
{} as any,
269-
aRetrievedProfile,
270-
false
271-
)();
172+
const notifyApiCall = getNotifyClient(fetchApi as any, "aValidApiKey");
173+
const ret = await sendToWebhook(notifyApiCall, {} as any, {} as any)();
272174
expect(fetchApi).toHaveBeenCalledTimes(1);
273175
expect(E.isLeft(ret)).toBeTruthy();
274176
if (E.isLeft(ret)) {
@@ -278,16 +180,8 @@ describe("sendToWebhook", () => {
278180

279181
it("should return a permanent error in case the webhook returns HTTP status 4xx", async () => {
280182
const fetchApi = mockFetch(401, { status: 401 });
281-
const notifyApiCall = getNotifyClient(fetchApi as any);
282-
const ret = await sendToWebhook(
283-
notifyApiCall,
284-
{} as any,
285-
{} as any,
286-
{} as any,
287-
{} as any,
288-
aRetrievedProfile,
289-
false
290-
)();
183+
const notifyApiCall = getNotifyClient(fetchApi as any, "aValidApiKey");
184+
const ret = await sendToWebhook(notifyApiCall, {} as any, {} as any)();
291185
expect(fetchApi).toHaveBeenCalledTimes(1);
292186
expect(E.isLeft(ret)).toBeTruthy();
293187
if (E.isLeft(ret)) {
@@ -310,8 +204,7 @@ describe("handler", () => {
310204
notificationModelMock as any,
311205
{} as any,
312206
mockRetrieveProcessingMessageData,
313-
userProfileReaderMock,
314-
false
207+
"https://example.com" as HttpsUrl
315208
)(mockContext, JSON.stringify(aNotificationEvent))
316209
).rejects.toThrow();
317210
});
@@ -326,77 +219,7 @@ describe("handler", () => {
326219
notificationModelMock as any,
327220
{} as any,
328221
mockRetrieveProcessingMessageData,
329-
userProfileReaderMock,
330-
false
331-
)(mockContext, JSON.stringify(aNotificationEvent))
332-
).rejects.toThrow();
333-
});
334-
335-
it("should return a transient error when an error occurred retrieving user profile", async () => {
336-
const notificationModelMock = {
337-
find: jest.fn(() => TE.of(O.some(aNotification))),
338-
update: jest.fn(() => TE.of(O.some(aNotification)))
339-
};
340-
341-
const notifyCallApiMock = jest
342-
.fn()
343-
.mockReturnValue(Promise.resolve(E.right({ status: 200 })));
344-
345-
mockRetrieveProcessingMessageData.mockImplementationOnce(() =>
346-
TE.of(O.some({ ...aCommonMessageData, content: aMessageContent }))
347-
);
348-
349-
userProfileReaderMock.mockImplementationOnce(() =>
350-
TE.left(
351-
toInternalError(
352-
"an Error" as NonEmptyString,
353-
"an Error detail" as NonEmptyString
354-
)
355-
)
356-
);
357-
358-
await expect(
359-
getWebhookNotificationHandler(
360-
notificationModelMock as any,
361-
notifyCallApiMock as any,
362-
mockRetrieveProcessingMessageData,
363-
userProfileReaderMock,
364-
false
365-
)(mockContext, JSON.stringify(aNotificationEvent))
366-
).rejects.toThrow();
367-
});
368-
369-
it("should return a transient error when user profile has not been found", async () => {
370-
const notificationModelMock = {
371-
find: jest.fn(() => TE.of(O.some(aNotification))),
372-
update: jest.fn(() => TE.of(O.some(aNotification)))
373-
};
374-
375-
const notifyCallApiMock = jest
376-
.fn()
377-
.mockReturnValue(Promise.resolve(E.right({ status: 200 })));
378-
379-
mockRetrieveProcessingMessageData.mockImplementationOnce(() =>
380-
TE.of(O.some({ ...aCommonMessageData, content: aMessageContent }))
381-
);
382-
383-
userProfileReaderMock.mockImplementationOnce(() =>
384-
TE.left(
385-
toNotFoundError(
386-
"an Error" as NonEmptyString,
387-
"an Error detail" as NonEmptyString,
388-
"profile" as NonEmptyString
389-
)
390-
)
391-
);
392-
393-
await expect(
394-
getWebhookNotificationHandler(
395-
notificationModelMock as any,
396-
notifyCallApiMock as any,
397-
mockRetrieveProcessingMessageData,
398-
userProfileReaderMock,
399-
false
222+
"https://example.com" as HttpsUrl
400223
)(mockContext, JSON.stringify(aNotificationEvent))
401224
).rejects.toThrow();
402225
});
@@ -411,8 +234,7 @@ describe("handler", () => {
411234
notificationModelMock as any,
412235
{} as any,
413236
mockRetrieveProcessingMessageData,
414-
userProfileReaderMock,
415-
false
237+
"https://example.com" as HttpsUrl
416238
)(mockContext, JSON.stringify(aNotificationEvent))
417239
).resolves.toEqual({ kind: "FAILURE", reason: "DECODE_ERROR" });
418240
});
@@ -425,7 +247,7 @@ describe("handler", () => {
425247

426248
const notifyCallApiMock = jest
427249
.fn()
428-
.mockReturnValue(Promise.resolve(E.right({ status: 200 })));
250+
.mockReturnValue(Promise.resolve(E.right({ status: 204 })));
429251

430252
mockRetrieveProcessingMessageData.mockImplementationOnce(() =>
431253
TE.of(O.some({ ...aCommonMessageData, content: aMessageContent }))
@@ -435,8 +257,7 @@ describe("handler", () => {
435257
notificationModelMock as any,
436258
notifyCallApiMock as any,
437259
mockRetrieveProcessingMessageData,
438-
userProfileReaderMock,
439-
false
260+
"https://example.com" as HttpsUrl
440261
)(mockContext, JSON.stringify(aNotificationEvent));
441262

442263
expect(result).toEqual({
@@ -450,7 +271,7 @@ describe("handler", () => {
450271

451272
const notifyCallApiMock = jest
452273
.fn()
453-
.mockReturnValue(Promise.resolve(E.right({ status: 200 })));
274+
.mockReturnValue(Promise.resolve(E.right({ status: 204 })));
454275

455276
const aLongMessageContent = {
456277
markdown: aMessageBodyMarkdown,
@@ -470,8 +291,7 @@ describe("handler", () => {
470291
notificationModelMock as any,
471292
notifyCallApiMock,
472293
mockRetrieveProcessingMessageData,
473-
userProfileReaderMock,
474-
false
294+
"https://example.com" as HttpsUrl
475295
)(mockContext, JSON.stringify(aNotificationEvent));
476296

477297
expect(result).toEqual({
@@ -499,8 +319,7 @@ describe("handler", () => {
499319
notificationModelMock as any,
500320
notifyCallApiMock,
501321
mockRetrieveProcessingMessageData,
502-
userProfileReaderMock,
503-
false
322+
"https://example.com" as HttpsUrl
504323
)(mockContext, JSON.stringify(aNotificationEvent))
505324
).resolves.toEqual({ kind: "FAILURE", reason: "SEND_TO_WEBHOOK_FAILED" });
506325

@@ -528,8 +347,7 @@ describe("handler", () => {
528347
notificationModelMock as any,
529348
{} as any,
530349
mockRetrieveProcessingMessageData,
531-
userProfileReaderMock,
532-
false
350+
"https://example.com" as HttpsUrl
533351
)(mockContext, JSON.stringify(aNotificationEvent));
534352

535353
expect(ret).toEqual({ kind: "SUCCESS", result: "EXPIRED" });

0 commit comments

Comments
 (0)