Skip to content

Commit

Permalink
[#175497433] Add Profile unsubscription on feed (#86)
Browse files Browse the repository at this point in the history
* [#175497433] Add Profile unsubscription on feed

* [#175497433] Removed useless check

* [#175497433] Add some subscription feed tests

* [#175497433] add date-fns utility methods
  • Loading branch information
AleDore authored Nov 3, 2020
1 parent d96ac0a commit 5206ada
Show file tree
Hide file tree
Showing 2 changed files with 353 additions and 3 deletions.
330 changes: 330 additions & 0 deletions GetSubscriptionsFeed/__tests__/handler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,330 @@
/* tslint:disable:no-any */
/* tslint:disable:no-duplicate-string */
/* tslint:disable:no-big-function */
/* tslint:disable: no-identical-functions */

import { TableService } from "azure-storage";
import * as dateFmt from "date-fns";
import * as endOfTomorrow from "date-fns/end_of_tomorrow";
import * as startOfYesterday from "date-fns/start_of_yesterday";
import { ServiceId } from "io-functions-commons/dist/generated/definitions/ServiceId";
import { FiscalCodeHash } from "../../generated/definitions/FiscalCodeHash";
import { GetSubscriptionsFeedHandler } from "../handler";

const tomorrow = endOfTomorrow();

const yesterday = startOfYesterday();
const aServiceId = "MyServiceId" as ServiceId;

const yesterdayUTC = dateFmt.format(yesterday, "YYYY-MM-DD");

const userAttrs = {
email: "[email protected]",
kind: "IAzureUserAttributes",
service: {
serviceId: aServiceId
}
};

const anHashedFiscalCode = "77408089123C62362C2D70E4C262BB45E268A3D477335D9C4A383521FA772AAE" as FiscalCodeHash;
const anotherHashedFiscalCode = "77408089123C62362C2D70E4C262BB45E268A3D477335D9C4A383521FA772AAA" as FiscalCodeHash;
const anotherThirdHashedFiscalCode = "77408089123C62362C2D70E4C262BB45E268A3D477335D9C4A383521FA772BBB" as FiscalCodeHash;

const queryEntitiesProfileSubscriptionMock = (
entries: ReadonlyArray<any>,
subscriptionSuffix: "S" | "U"
) =>
jest.fn((_, __, ___, cb) => {
return cb(
null,
{
entries:
entries.length > 0
? entries.map(e => ({
RowKey: { _: `P-${yesterdayUTC}-${subscriptionSuffix}-${e}` }
}))
: []
},
{ isSuccessful: true }
);
});

const queryEntitiesServiceSubscriptionMock = (
entries: ReadonlyArray<any>,
subscriptionSuffix: "S" | "U"
) =>
jest.fn((_, __, ___, cb) => {
return cb(
null,
{
entries:
entries.length > 0
? entries.map(e => ({
RowKey: {
_: `S-${yesterdayUTC}-${aServiceId}-${subscriptionSuffix}-${e}`
}
}))
: []
},
{ isSuccessful: true }
);
});

const emptyQueryEntities = queryEntitiesProfileSubscriptionMock([], "S");

describe("GetSubscriptionsFeedHandler", () => {
it("should respond with Not Found if Date.now() is lower than given subscriptionDate", async () => {
const getSubscriptionsFeedHandler = GetSubscriptionsFeedHandler(
{} as any,
"subscriptionFeedByDay"
);
const result = await getSubscriptionsFeedHandler(
{} as any,
{} as any,
userAttrs as any,
dateFmt.format(tomorrow, "YYYY-MM-DD")
);
expect(result.kind).toBe("IResponseErrorNotFound");
});

it("should return an empty feed json if no changes happened for the given subscriptionDate", async () => {
const tableServiceMock = ({
queryEntities: queryEntitiesProfileSubscriptionMock([], "S")
} as any) as TableService;

const getSubscriptionsFeedHandler = GetSubscriptionsFeedHandler(
tableServiceMock,
"subscriptionFeedByDay"
);

const result = await getSubscriptionsFeedHandler(
{} as any,
{} as any,
userAttrs as any,
yesterdayUTC
);
expect(result.kind).toBe("IResponseSuccessJson");
if (result.kind === "IResponseSuccessJson") {
expect(result.value).toEqual({
dateUTC: yesterdayUTC,
subscriptions: [],
unsubscriptions: []
});
}
});

it("should return a correct feed json if there are only profile registrations", async () => {
const queryEntities = jest.fn();
queryEntities.mockImplementationOnce(
queryEntitiesProfileSubscriptionMock(
[anHashedFiscalCode, anotherHashedFiscalCode],
"S"
)
);
queryEntities.mockImplementation(emptyQueryEntities);
const tableServiceMock = ({
queryEntities
} as any) as TableService;

const getSubscriptionsFeedHandler = GetSubscriptionsFeedHandler(
tableServiceMock,
"subscriptionFeedByDay"
);

const result = await getSubscriptionsFeedHandler(
{} as any,
{} as any,
userAttrs as any,
yesterdayUTC
);
expect(result.kind).toBe("IResponseSuccessJson");
if (result.kind === "IResponseSuccessJson") {
expect(result.value).toEqual({
dateUTC: yesterdayUTC,
subscriptions: [anHashedFiscalCode, anotherHashedFiscalCode],
unsubscriptions: []
});
}
});

it("should return a correct feed json if there are profile registrations and another service subscription", async () => {
const queryEntities = jest.fn();
// Profile subscriptions
queryEntities.mockImplementationOnce(
queryEntitiesProfileSubscriptionMock(
[anHashedFiscalCode, anotherHashedFiscalCode],
"S"
)
);
// profile unsubscriptions
queryEntities.mockImplementationOnce(emptyQueryEntities);
// service subscriptions
queryEntities.mockImplementationOnce(
queryEntitiesServiceSubscriptionMock([anotherThirdHashedFiscalCode], "S")
);
queryEntities.mockImplementation(emptyQueryEntities);
const tableServiceMock = ({
queryEntities
} as any) as TableService;

const getSubscriptionsFeedHandler = GetSubscriptionsFeedHandler(
tableServiceMock,
"subscriptionFeedByDay"
);

const result = await getSubscriptionsFeedHandler(
{} as any,
{} as any,
userAttrs as any,
yesterdayUTC
);
expect(result.kind).toBe("IResponseSuccessJson");
if (result.kind === "IResponseSuccessJson") {
expect(result.value).toEqual({
dateUTC: yesterdayUTC,
subscriptions: [
anHashedFiscalCode,
anotherHashedFiscalCode,
anotherThirdHashedFiscalCode
],
unsubscriptions: []
});
}
});

it("should return a correct feed json if there are profile registrations and the same fiscal codes in service subscriptions", async () => {
const queryEntities = jest.fn();
// Profile subscriptions
queryEntities.mockImplementationOnce(
queryEntitiesProfileSubscriptionMock(
[anHashedFiscalCode, anotherHashedFiscalCode],
"S"
)
);
// profile unsubscriptions
queryEntities.mockImplementationOnce(emptyQueryEntities);
// service subscriptions
queryEntities.mockImplementationOnce(
queryEntitiesServiceSubscriptionMock(
[anHashedFiscalCode, anotherHashedFiscalCode],
"S"
)
);
queryEntities.mockImplementation(emptyQueryEntities);
const tableServiceMock = ({
queryEntities
} as any) as TableService;

const getSubscriptionsFeedHandler = GetSubscriptionsFeedHandler(
tableServiceMock,
"subscriptionFeedByDay"
);

const result = await getSubscriptionsFeedHandler(
{} as any,
{} as any,
userAttrs as any,
yesterdayUTC
);
expect(result.kind).toBe("IResponseSuccessJson");
if (result.kind === "IResponseSuccessJson") {
expect(result.value).toEqual({
dateUTC: yesterdayUTC,
subscriptions: [anHashedFiscalCode, anotherHashedFiscalCode],
unsubscriptions: []
});
}
});

it("should return a correct feed json if there are profile delete and the same fiscal codes in service subscriptions", async () => {
const queryEntities = jest.fn();
// Profile subscriptions
queryEntities.mockImplementationOnce(emptyQueryEntities);
// profile unsubscriptions
queryEntities.mockImplementationOnce(
queryEntitiesProfileSubscriptionMock(
[anHashedFiscalCode, anotherHashedFiscalCode],
"U"
)
);
// service subscriptions
queryEntities.mockImplementationOnce(
queryEntitiesServiceSubscriptionMock(
[anHashedFiscalCode, anotherHashedFiscalCode],
"S"
)
);
queryEntities.mockImplementation(emptyQueryEntities);
const tableServiceMock = ({
queryEntities
} as any) as TableService;

const getSubscriptionsFeedHandler = GetSubscriptionsFeedHandler(
tableServiceMock,
"subscriptionFeedByDay"
);

const result = await getSubscriptionsFeedHandler(
{} as any,
{} as any,
userAttrs as any,
yesterdayUTC
);
expect(result.kind).toBe("IResponseSuccessJson");
if (result.kind === "IResponseSuccessJson") {
expect(result.value).toEqual({
dateUTC: yesterdayUTC,
subscriptions: [],
unsubscriptions: [anHashedFiscalCode, anotherHashedFiscalCode]
});
}
});

it("should return a correct feed json if there are profile subscription skipping the same fiscal codes in service unsubscriptions", async () => {
const queryEntities = jest.fn();
// Profile subscriptions
queryEntities.mockImplementationOnce(
queryEntitiesProfileSubscriptionMock(
[
anHashedFiscalCode,
anotherHashedFiscalCode,
anotherThirdHashedFiscalCode
],
"S"
)
);
// profile unsubscriptions
queryEntities.mockImplementationOnce(emptyQueryEntities);
// service subscriptions
queryEntities.mockImplementationOnce(emptyQueryEntities);
queryEntities.mockImplementation(
queryEntitiesServiceSubscriptionMock(
[anHashedFiscalCode, anotherHashedFiscalCode],
"U"
)
);
const tableServiceMock = ({
queryEntities
} as any) as TableService;

const getSubscriptionsFeedHandler = GetSubscriptionsFeedHandler(
tableServiceMock,
"subscriptionFeedByDay"
);

const result = await getSubscriptionsFeedHandler(
{} as any,
{} as any,
userAttrs as any,
yesterdayUTC
);
expect(result.kind).toBe("IResponseSuccessJson");
if (result.kind === "IResponseSuccessJson") {
expect(result.value).toEqual({
dateUTC: yesterdayUTC,
subscriptions: [anotherThirdHashedFiscalCode],
unsubscriptions: []
});
}
});
});
26 changes: 23 additions & 3 deletions GetSubscriptionsFeed/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ export function GetSubscriptionsFeedHandler(
const profileSubscriptionsQuery: PagedQuery = pagedQuery(
queryFilterForKey(`P-${subscriptionsDateUTC}-S`)
);
const profileUnsubscriptionsQuery: PagedQuery = pagedQuery(
queryFilterForKey(`P-${subscriptionsDateUTC}-U`)
);
const serviceSubscriptionsQuery: PagedQuery = pagedQuery(
queryFilterForKey(`S-${subscriptionsDateUTC}-${serviceId}-S`)
);
Expand All @@ -117,6 +120,11 @@ export function GetSubscriptionsFeedHandler(
// users that created their account on date
const profileSubscriptionsSet = await queryUsers(profileSubscriptionsQuery);

// users that deleted their account on date
const profileUnsubscriptionsSet = await queryUsers(
profileUnsubscriptionsQuery
);

// users that subscribed to the client service on date
const serviceSubscriptionsSet = await queryUsers(serviceSubscriptionsQuery);

Expand All @@ -134,7 +142,10 @@ export function GetSubscriptionsFeedHandler(
}
});
serviceSubscriptionsSet.forEach(ss => {
if (!profileSubscriptionsSet.has(ss)) {
if (
!profileSubscriptionsSet.has(ss) &&
!profileUnsubscriptionsSet.has(ss)
) {
// add all users that subscribed to this service, skipping those that
// are new users as they're yet counted in as new subscribers in the
// previous step
Expand All @@ -143,11 +154,20 @@ export function GetSubscriptionsFeedHandler(
});

const unsubscriptions = new Array<FiscalCodeHash>();

profileUnsubscriptionsSet.forEach(pu =>
// add all users that deleted its own account
unsubscriptions.push(pu)
);

serviceUnsubscriptionsSet.forEach(su => {
if (!profileSubscriptionsSet.has(su)) {
if (
!profileSubscriptionsSet.has(su) &&
!profileUnsubscriptionsSet.has(su)
) {
// add all users that unsubscribed from this service, skipping those
// that created the profile on the same day as the service will not
// yet know they exist
// yet know they exist or deleted their account
unsubscriptions.push(su);
}
});
Expand Down

0 comments on commit 5206ada

Please sign in to comment.