diff --git a/src/modules/coreHttpApi/CoreHttpApiModule.ts b/src/modules/coreHttpApi/CoreHttpApiModule.ts index ab594c69..da64fc26 100644 --- a/src/modules/coreHttpApi/CoreHttpApiModule.ts +++ b/src/modules/coreHttpApi/CoreHttpApiModule.ts @@ -30,6 +30,10 @@ export default class CoreHttpApiModule extends ConnectorRuntimeModule { + const result = await this.transportServices.identityDeletionProcesses.initiateIdentityDeletionProcess(); + return this.ok(result); + } + + @GET + @Accept("application/json") + public async getActiveIdentityDeletionProcess(): Promise { + const result = await this.transportServices.identityDeletionProcesses.getActiveIdentityDeletionProcess(); + return this.ok(result); + } + + @DELETE + @Accept("application/json") + public async cancelIdentityDeletionProcess(): Promise { + const result = await this.transportServices.identityDeletionProcesses.cancelIdentityDeletionProcess(); + return this.ok(result); + } +} diff --git a/test/debug/identityDeletionProcess.test.ts b/test/debug/identityDeletionProcess.test.ts new file mode 100644 index 00000000..657569d1 --- /dev/null +++ b/test/debug/identityDeletionProcess.test.ts @@ -0,0 +1,80 @@ +import { ConnectorClient } from "@nmshd/connector-sdk"; +import { AxiosInstance } from "axios"; +import { DateTime } from "luxon"; +import { Launcher } from "../lib/Launcher"; +import { getTimeout } from "../lib/setTimeout"; + +const launcher = new Launcher(); +let client: ConnectorClient; +let axiosInstance: AxiosInstance; + +beforeAll(async () => { + [client] = await launcher.launch(1); + + axiosInstance = (client.account as any).httpClient; +}, getTimeout(30000)); +afterAll(() => launcher.stop()); + +interface IdentityDeletionProcess { + id: string; + status: "WaitingForApproval" | "Rejected" | "Approved" | "Cancelled"; + createdAt?: string; + createdByDevice?: string; + approvalPeriodEndsAt?: string; + rejectedAt?: string; + rejectedByDevice?: string; + approvedAt?: string; + approvedByDevice?: string; + gracePeriodEndsAt?: string; + cancelledAt?: string; + cancelledByDevice?: string; +} + +describe("Identity Deletion Process", () => { + afterEach(async () => await axiosInstance.delete("/api/v2/IdentityDeletionProcess")); + + test("should return 400 when no identity deletion process is active", async () => { + const getResult = await axiosInstance.get("/api/v2/IdentityDeletionProcess"); + expect(getResult.status).toBe(400); + }); + + test("should start an identity deletion and get its status", async () => { + const response = await axiosInstance.post<{ result: IdentityDeletionProcess }>("/api/v2/IdentityDeletionProcess"); + + expect(response.status).toBe(200); + const identityDeletionProcess = response.data.result; + expect(identityDeletionProcess.status).toBe("Approved"); + expect(DateTime.fromISO(identityDeletionProcess.gracePeriodEndsAt!).toMillis()).toBeGreaterThan(DateTime.now().toMillis()); + }); + + test("should get the active identity deletion process", async () => { + const initiateResult = await axiosInstance.post<{ result: IdentityDeletionProcess }>("/api/v2/IdentityDeletionProcess"); + expect(initiateResult.status).toBe(200); + const identityDeletionProcess = initiateResult.data.result; + + const getResult = await axiosInstance.get<{ result: IdentityDeletionProcess }>("/api/v2/IdentityDeletionProcess"); + expect(getResult.status).toBe(200); + expect(getResult.data.result.status).toBe(identityDeletionProcess.status); + expect(getResult.data.result.gracePeriodEndsAt).toBe(identityDeletionProcess.gracePeriodEndsAt); + }); + + test("should return 400 when trying to start a new identity deletion process", async () => { + const initiateResult = await axiosInstance.post<{ result: IdentityDeletionProcess }>("/api/v2/IdentityDeletionProcess"); + expect(initiateResult.status).toBe(200); + + const initiateResult2 = await axiosInstance.post("/api/v2/IdentityDeletionProcess"); + expect(initiateResult2.status).toBe(400); + }); + + test("should cancel an identity deletion", async () => { + const initiateResult = await axiosInstance.post<{ result: IdentityDeletionProcess }>("/api/v2/IdentityDeletionProcess"); + expect(initiateResult.status).toBe(200); + + const cancelResult = await axiosInstance.delete("/api/v2/IdentityDeletionProcess"); + expect(cancelResult.status).toBe(200); + expect(cancelResult.data.result.status).toBe("Cancelled"); + + const getResult = await axiosInstance.get("/api/v2/IdentityDeletionProcess"); + expect(getResult.status).toBe(400); + }); +}); diff --git a/test/lib/Launcher.ts b/test/lib/Launcher.ts index 15fc1bda..dafa80c4 100644 --- a/test/lib/Launcher.ts +++ b/test/lib/Launcher.ts @@ -143,6 +143,6 @@ export class Launcher { public stopClient(connector: ChildProcess, webhookServer: Server | undefined): void { connector.kill(); - webhookServer?.close(); + connector.on("exit", () => webhookServer?.close()); } } diff --git a/test/spec.test.ts b/test/spec.test.ts index 1e680994..32e0f5c5 100644 --- a/test/spec.test.ts +++ b/test/spec.test.ts @@ -11,7 +11,7 @@ describe("test openapi spec against routes", () => { beforeAll(async () => { manualOpenApiSpec = yamljs.load("src/modules/coreHttpApi/openapi.yml"); - const files = "src/modules/**/*.ts"; + const files = "src/modules/coreHttpApi/controllers/**/*.ts"; const metadata = new MetadataGenerator([files], "tsconfig.json").generate(); const defaultOptions = { basePath: "/",