Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#174850132] Prevent errors on missing notification #82

Merged
merged 3 commits into from
Sep 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 56 additions & 5 deletions ExtractUserDataActivity/__tests__/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {

import archiver = require("archiver");
import { BlobService } from "azure-storage";
import { fromEither } from "fp-ts/lib/TaskEither";
import { fromEither, taskEither } from "fp-ts/lib/TaskEither";
import { MessageModel } from "io-functions-commons/dist/src/models/message";
import { MessageStatusModel } from "io-functions-commons/dist/src/models/message_status";
import {
Expand All @@ -41,6 +41,7 @@ import {
aRetrievedNotification
} from "../../__mocks__/mocks";
import { AllUserData } from "../../utils/userData";
import { none } from "fp-ts/lib/Option";

const anotherRetrievedNotification: RetrievedNotification = {
...aRetrievedNotification,
Expand Down Expand Up @@ -100,9 +101,12 @@ jest
Promise.resolve([[right(aRetrievedMessageWithoutContent)]])
);

const mockGetContentFromBlob = jest.fn(() =>
taskEither.of(some(aMessageContent))
);
const messageModelMock = ({
findMessages: jest.fn(() => fromEither(right(messageIteratorMock))),
getContentFromBlob: jest.fn(() => fromEither(right(some(aMessageContent))))
getContentFromBlob: mockGetContentFromBlob
} as any) as MessageModel;

const messageStatusModelMock = ({
Expand All @@ -115,10 +119,11 @@ const profileModelMock = ({
findLastVersionByModelId: jest.fn(() => fromEither(right(some(aProfile))))
} as any) as ProfileModel;

const mockFindNotificationForMessage = jest.fn(() =>
taskEither.of(some(aRetrievedNotification))
);
const notificationModelMock = ({
findNotificationForMessage: jest.fn(() =>
fromEither(right(some(aRetrievedNotification)))
),
findNotificationForMessage: mockFindNotificationForMessage,
getQueryIterator: jest.fn(() => notificationIteratorMock)
} as any) as NotificationModel;

Expand Down Expand Up @@ -263,4 +268,50 @@ describe("createExtractUserDataActivityHandler", () => {
expect.any(Object)
);
});

it("should handle export when some messages have no notification", async () => {
const { blobServiceMock } = setupStreamMocks();
mockFindNotificationForMessage.mockImplementationOnce(() =>
taskEither.of(none)
);
const handler = createExtractUserDataActivityHandler({
messageContentBlobService: blobServiceMock,
messageModel: messageModelMock,
messageStatusModel: messageStatusModelMock,
notificationModel: notificationModelMock,
notificationStatusModel: notificationStatusModelMock,
profileModel: profileModelMock,
userDataBlobService: blobServiceMock,
userDataContainerName: aUserDataContainerName
});
const input: ActivityInput = {
fiscalCode: aFiscalCode
};

const result = await handler(contextMock, input);

expect(ActivityResultSuccess.decode(result).isRight()).toBe(true);
});

it("should handle export when some messages have no message content", async () => {
const { blobServiceMock } = setupStreamMocks();
mockGetContentFromBlob.mockImplementationOnce(() => taskEither.of(none));
const handler = createExtractUserDataActivityHandler({
messageContentBlobService: blobServiceMock,
messageModel: messageModelMock,
messageStatusModel: messageStatusModelMock,
notificationModel: notificationModelMock,
notificationStatusModel: notificationStatusModelMock,
profileModel: profileModelMock,
userDataBlobService: blobServiceMock,
userDataContainerName: aUserDataContainerName
});
const input: ActivityInput = {
fiscalCode: aFiscalCode
};

const result = await handler(contextMock, input);

expect(ActivityResultSuccess.decode(result).isRight()).toBe(true);
});
});
44 changes: 18 additions & 26 deletions ExtractUserDataActivity/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as stream from "stream";
import { DeferredPromise } from "italia-ts-commons/lib/promises";

import { sequenceS, sequenceT } from "fp-ts/lib/Apply";
import { array, flatten, rights } from "fp-ts/lib/Array";
import { array, catOptions, flatten, rights } from "fp-ts/lib/Array";
import {
Either,
fromOption,
Expand All @@ -21,6 +21,7 @@ import {
fromEither,
TaskEither,
taskEither,
taskEitherSeq,
taskify,
tryCatch
} from "fp-ts/lib/TaskEither";
Expand Down Expand Up @@ -292,32 +293,23 @@ export const findNotificationsForAllMessages = (
ActivityResultQueryFailure,
ReadonlyArray<RetrievedNotification>
> =>
array.sequence(taskEither)(
messages.map(m =>
notificationModel.findNotificationForMessage(m.id).foldTaskEither(
e =>
fromLeft(
ActivityResultQueryFailure.encode({
kind: "QUERY_FAILURE",
reason: `notificationModel.findNotificationForMessage| ${
e.kind
}, ${getMessageFromCosmosErrors(e)}`
})
),
maybeNotification =>
maybeNotification.foldL(
() =>
fromLeft(
ActivityResultQueryFailure.encode({
kind: "QUERY_FAILURE",
reason: `notificationModel.findNotificationForMessage| No notifications found for messageId ${m.id}`
})
),
notification => fromEither(right(notification))
)
)
array
.sequence(taskEitherSeq)(
messages.map(m => notificationModel.findNotificationForMessage(m.id))
)
);

.bimap(
e =>
ActivityResultQueryFailure.encode({
kind: "QUERY_FAILURE",
reason: `notificationModel.findNotificationForMessage| ${
e.kind
}, ${getMessageFromCosmosErrors(e)}`
}),
// There are cases in which a message has no notification and that's fine
// We just filter "none" elements
catOptions
);

export const findAllNotificationStatuses = (
notificationStatusModel: NotificationStatusModel,
Expand Down