This repository has been archived by the owner on Jan 15, 2025. It is now read-only.
generated from pagopa/io-functions-template
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from pagopa/175761632_add_cgn_activation
[#175761632] Add CGN Activation API
- Loading branch information
Showing
16 changed files
with
1,018 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
/* tslint:disable: no-any */ | ||
import { addYears } from "date-fns"; | ||
import { some } from "fp-ts/lib/Option"; | ||
import { fromLeft, taskEither } from "fp-ts/lib/TaskEither"; | ||
import { toCosmosErrorResponse } from "io-functions-commons/dist/src/utils/cosmosdb_model"; | ||
import { | ||
ResponseErrorInternal, | ||
ResponseSuccessAccepted | ||
} from "italia-ts-commons/lib/responses"; | ||
import { FiscalCode, NonEmptyString } from "italia-ts-commons/lib/strings"; | ||
import { | ||
mockGetStatus, | ||
mockStartNew, | ||
mockStatusRunning | ||
} from "../../__mocks__/durable-functions"; | ||
import { | ||
CgnActivatedStatus, | ||
StatusEnum as ActivatedStatusEnum | ||
} from "../../generated/definitions/CgnActivatedStatus"; | ||
import { | ||
CgnPendingStatus, | ||
StatusEnum | ||
} from "../../generated/definitions/CgnPendingStatus"; | ||
import { | ||
CgnRevokedStatus, | ||
StatusEnum as RevokedStatusEnum | ||
} from "../../generated/definitions/CgnRevokedStatus"; | ||
import { UserCgn } from "../../models/user_cgn"; | ||
import * as orchUtils from "../../utils/orchestrators"; | ||
import { StartCgnActivationHandler } from "../handler"; | ||
|
||
const now = new Date(); | ||
const aFiscalCode = "RODFDS89S10H501T" as FiscalCode; | ||
const anOldFiscalCode = "RODFDS82S10H501T" as FiscalCode; | ||
|
||
const aUserCgnRevokedStatus: CgnRevokedStatus = { | ||
revocation_date: now, | ||
revocation_reason: "revocation_reason" as NonEmptyString, | ||
status: RevokedStatusEnum.REVOKED | ||
}; | ||
|
||
const aUserCgnActivatedStatus: CgnActivatedStatus = { | ||
activation_date: new Date(), | ||
expiration_date: addYears(new Date(), 2), | ||
status: ActivatedStatusEnum.ACTIVATED | ||
}; | ||
|
||
const aUserCgnPendingStatus: CgnPendingStatus = { | ||
status: StatusEnum.PENDING | ||
}; | ||
|
||
const aRevokedUserCgn: UserCgn = { | ||
fiscalCode: aFiscalCode, | ||
id: "A_USER_CGN_ID" as NonEmptyString, | ||
status: aUserCgnRevokedStatus | ||
}; | ||
|
||
const anActivatedUserCgn: UserCgn = { | ||
fiscalCode: aFiscalCode, | ||
id: "A_USER_CGN_ID" as NonEmptyString, | ||
status: aUserCgnActivatedStatus | ||
}; | ||
|
||
const findLastVersionByModelIdMock = jest.fn(); | ||
const upsertModelMock = jest.fn(); | ||
const userCgnModelMock = { | ||
findLastVersionByModelId: findLastVersionByModelIdMock, | ||
upsert: upsertModelMock | ||
}; | ||
|
||
const checkUpdateCgnIsRunningMock = jest.fn(); | ||
jest | ||
.spyOn(orchUtils, "checkUpdateCgnIsRunning") | ||
.mockImplementation(checkUpdateCgnIsRunningMock); | ||
describe("StartCgnActivation", () => { | ||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
it("should return an Internal Error if an error occurs during UserCgn retrieve", async () => { | ||
findLastVersionByModelIdMock.mockImplementationOnce(() => | ||
fromLeft(toCosmosErrorResponse(new Error("query error"))) | ||
); | ||
const startCgnActivationHandler = StartCgnActivationHandler( | ||
userCgnModelMock as any | ||
); | ||
const response = await startCgnActivationHandler({} as any, aFiscalCode); | ||
expect(response.kind).toBe("IResponseErrorInternal"); | ||
}); | ||
|
||
it("should return an Internal Error if it is not possible to check status of an other orchestrator with the same id", async () => { | ||
findLastVersionByModelIdMock.mockImplementationOnce(() => | ||
taskEither.of(some({ ...aRevokedUserCgn, status: aUserCgnPendingStatus })) | ||
); | ||
checkUpdateCgnIsRunningMock.mockImplementationOnce(() => | ||
fromLeft(ResponseErrorInternal("Error")) | ||
); | ||
const startCgnActivationHandler = StartCgnActivationHandler( | ||
userCgnModelMock as any | ||
); | ||
const response = await startCgnActivationHandler({} as any, aFiscalCode); | ||
expect(response.kind).toBe("IResponseErrorInternal"); | ||
}); | ||
|
||
it("should return an Accepted response if there is another orchestrator running with the same id", async () => { | ||
findLastVersionByModelIdMock.mockImplementationOnce(() => | ||
taskEither.of(some({ ...aRevokedUserCgn, status: aUserCgnPendingStatus })) | ||
); | ||
checkUpdateCgnIsRunningMock.mockImplementationOnce(() => | ||
fromLeft(ResponseSuccessAccepted()) | ||
); | ||
const startCgnActivationHandler = StartCgnActivationHandler( | ||
userCgnModelMock as any | ||
); | ||
const response = await startCgnActivationHandler({} as any, aFiscalCode); | ||
expect(response.kind).toBe("IResponseSuccessAccepted"); | ||
}); | ||
|
||
it("should start a new orchestrator if there aren' t conflict on the same id", async () => { | ||
findLastVersionByModelIdMock.mockImplementationOnce(() => | ||
taskEither.of(some({ ...aRevokedUserCgn, status: aUserCgnPendingStatus })) | ||
); | ||
checkUpdateCgnIsRunningMock.mockImplementationOnce(() => | ||
taskEither.of(false) | ||
); | ||
upsertModelMock.mockImplementationOnce(() => taskEither.of({})); | ||
const startCgnActivationHandler = StartCgnActivationHandler( | ||
userCgnModelMock as any | ||
); | ||
await startCgnActivationHandler({} as any, aFiscalCode); | ||
expect(mockStartNew).toBeCalledTimes(1); | ||
}); | ||
|
||
it("should return a Conflict Error if a CGN is already ACTIVATED", async () => { | ||
findLastVersionByModelIdMock.mockImplementationOnce(() => | ||
taskEither.of(some(anActivatedUserCgn)) | ||
); | ||
const startCgnActivationHandler = StartCgnActivationHandler( | ||
userCgnModelMock as any | ||
); | ||
const response = await startCgnActivationHandler({} as any, aFiscalCode); | ||
expect(response.kind).toBe("IResponseErrorConflict"); | ||
}); | ||
|
||
it("should start an Internal Error if there are errors while inserting a new Cgn in pending status", async () => { | ||
findLastVersionByModelIdMock.mockImplementationOnce(() => | ||
taskEither.of(some({ ...aRevokedUserCgn, status: aUserCgnPendingStatus })) | ||
); | ||
checkUpdateCgnIsRunningMock.mockImplementationOnce(() => | ||
taskEither.of(false) | ||
); | ||
upsertModelMock.mockImplementationOnce(() => | ||
fromLeft(new Error("Insert error")) | ||
); | ||
const startCgnActivationHandler = StartCgnActivationHandler( | ||
userCgnModelMock as any | ||
); | ||
const response = await startCgnActivationHandler({} as any, aFiscalCode); | ||
expect(response.kind).toBe("IResponseErrorInternal"); | ||
expect(mockStartNew).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it("should return a Forbidden Error if a fiscal code is not eligible for CGN", async () => { | ||
findLastVersionByModelIdMock.mockImplementationOnce(() => | ||
fromLeft(toCosmosErrorResponse(new Error("query error"))) | ||
); | ||
const startCgnActivationHandler = StartCgnActivationHandler( | ||
userCgnModelMock as any | ||
); | ||
const response = await startCgnActivationHandler( | ||
{} as any, | ||
anOldFiscalCode | ||
); | ||
expect(response.kind).toBe("IResponseErrorForbiddenNotAuthorized"); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"bindings": [ | ||
{ | ||
"authLevel": "function", | ||
"type": "httpTrigger", | ||
"direction": "in", | ||
"name": "req", | ||
"route": "api/v1/cgn/{fiscalcode}/activation", | ||
"methods": [ | ||
"post" | ||
] | ||
}, | ||
{ | ||
"type": "http", | ||
"direction": "out", | ||
"name": "res" | ||
}, | ||
{ | ||
"name": "starter", | ||
"type": "durableClient", | ||
"direction": "in" | ||
} | ||
], | ||
"scriptFile": "../dist/StartCgnActivation/index.js" | ||
} |
Oops, something went wrong.