From f228e07373b408aaec20870cd1c14b05786d8107 Mon Sep 17 00:00:00 2001 From: Eric Doughty-Papassideris Date: Mon, 27 May 2024 04:11:25 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=85=E2=99=BB=EF=B8=8F=E2=9A=B0=EF=B8=8F?= =?UTF-8?q?=20back:=20add=20e2e=20test=20for=20trashing=20anonymously=20up?= =?UTF-8?q?loaded=20files,=20deleted=20e2e=5FdeleteDocument=20(#433)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/node/test/e2e/common/user-api.ts | 31 ++++- .../node/test/e2e/documents/documents.spec.ts | 32 +----- .../node/test/e2e/documents/trash.spec.ts | 108 ++++++++++++++++++ .../backend/node/test/e2e/documents/utils.ts | 13 --- 4 files changed, 134 insertions(+), 50 deletions(-) create mode 100644 tdrive/backend/node/test/e2e/documents/trash.spec.ts diff --git a/tdrive/backend/node/test/e2e/common/user-api.ts b/tdrive/backend/node/test/e2e/common/user-api.ts index 88c32c7a..f8d5aeac 100644 --- a/tdrive/backend/node/test/e2e/common/user-api.ts +++ b/tdrive/backend/node/test/e2e/common/user-api.ts @@ -23,6 +23,10 @@ import { UserQuota } from "../../../src/services/user/web/types"; import { Api } from "../utils.api"; import { OidcJwtVerifier } from "../../../src/services/console/clients/remote-jwks-verifier"; +/** The UserApi is an abstraction for E2E tests that + * represents the high level actions a user can take + * in the application. + */ export default class UserApi { private static readonly DOC_URL = "/internal/services/documents/v1"; @@ -54,8 +58,8 @@ export default class UserApi { private async init(newUser: boolean, options?: {}) { this.dbService = await TestDbService.getInstance(this.platform, true); + this.workspace = this.platform.workspace; if (newUser) { - this.workspace = this.platform.workspace; const workspacePK = { id: this.workspace.workspace_id, company_id: this.workspace.company_id, @@ -69,7 +73,6 @@ export default class UserApi { uuidv1()); } else { this.user = this.platform.currentUser; - this.workspace = this.platform.workspace; } this.api = new Api(this.platform, this.user); this.jwt = await this.doLogin(); @@ -227,6 +230,21 @@ export default class UserApi { return directory; } + /** Run the provided callback using the specified bearer JWT token. + * //TODO: Warning: does not override calls using `this.api` have to discuss + */ + async impersonateWithJWT(jwt: string, cb: () => Promise): Promise { + const previous = this.jwt; + this.jwt = jwt; + let result: T | undefined = undefined; + try { + result = await cb(); + } finally { + this.jwt = previous; + } + return result; + } + async createDocument( item: Partial, version: Partial @@ -241,25 +259,26 @@ export default class UserApi { return deserialize(DriveFile, response.body); }; - async createDefaultDocument(): Promise { + async createDefaultDocument(overrides?: Partial): Promise { const scope: "personal" | "shared" = "shared"; const item = { name: "new test file", parent_id: "root", company_id: this.platform.workspace.company_id, scope, + ...overrides, }; return await this.createDocument(item, {}); }; - async shareWithPublicLink(doc: Partial, accessLevel: publicAccessLevel) { + async shareWithPublicLink(doc: Partial & { id: string }, accessLevel: publicAccessLevel) { return await this.updateDocument(doc.id, { ...doc, access_info: { - ...doc.access_info, + ...doc.access_info!, public: { - ...doc.access_info.public!, + ...doc.access_info?.public!, level: accessLevel } } diff --git a/tdrive/backend/node/test/e2e/documents/documents.spec.ts b/tdrive/backend/node/test/e2e/documents/documents.spec.ts index c3aec8ad..9c70a1ed 100644 --- a/tdrive/backend/node/test/e2e/documents/documents.spec.ts +++ b/tdrive/backend/node/test/e2e/documents/documents.spec.ts @@ -7,7 +7,6 @@ import { TestDbService } from "../utils.prepare.db"; import { e2e_createDocumentFile, e2e_createVersion, - e2e_deleteDocument, e2e_updateDocument, } from "./utils"; import UserApi from "../common/user-api"; @@ -68,22 +67,12 @@ describe("the Drive feature", () => { expect(result.item.name).toEqual("Shared Drive"); }); - it("did fetch the trash", async () => { - await TestDbService.getInstance(platform, true); - - const response = await currentUser.getDocument("trash"); - const result = deserialize(DriveItemDetailsMockClass, response.body); - - expect(result.item.id).toEqual("trash"); - expect(result.item.name).toEqual("Trash"); - }); - it("did delete an item", async () => { const createItemResult = await currentUser.createDefaultDocument(); expect(createItemResult.id).toBeDefined(); - const deleteResponse = await e2e_deleteDocument(platform, createItemResult.id); + const deleteResponse = await currentUser.delete(createItemResult.id); expect(deleteResponse.statusCode).toEqual(200); }); @@ -122,25 +111,6 @@ describe("the Drive feature", () => { expect(zipResponse.body.length).toBeGreaterThanOrEqual(100); }); - it("did move an item to trash", async () => { - const createItemResult = await currentUser.createDefaultDocument(); - - expect(createItemResult.id).toBeDefined(); - - const moveToTrashResponse = await e2e_deleteDocument(platform, createItemResult.id); - expect(moveToTrashResponse.statusCode).toEqual(200); - - const listTrashResponse = await currentUser.getDocument("trash"); - const listTrashResult = deserialize( - DriveItemDetailsMockClass, - listTrashResponse.body, - ); - expect(listTrashResult.item.name).toEqual("Trash"); - expect(createItemResult).toBeDefined(); - expect(createItemResult.scope).toEqual("shared"); - expect(listTrashResult.children.some(({ id }) => id === createItemResult.id)).toBeTruthy(); - }); - it("did create a version for a drive item", async () => { const item = await currentUser.createDefaultDocument(); const fileUploadResponse = await e2e_createDocumentFile(platform); diff --git a/tdrive/backend/node/test/e2e/documents/trash.spec.ts b/tdrive/backend/node/test/e2e/documents/trash.spec.ts new file mode 100644 index 00000000..e06ac4a2 --- /dev/null +++ b/tdrive/backend/node/test/e2e/documents/trash.spec.ts @@ -0,0 +1,108 @@ +import { describe, beforeAll, it, expect, afterAll } from "@jest/globals"; +import { deserialize } from "class-transformer"; +import type { DriveFile } from "../../../src/services/documents/entities/drive-file"; +import { init, TestPlatform } from "../setup"; +import { TestDbService } from "../utils.prepare.db"; +import UserApi from "../common/user-api"; +import { + DriveItemDetailsMockClass, +} from "../common/entities/mock_entities"; + +describe("the Drive's documents' trash feature", () => { + let platform: TestPlatform | null; + let currentUser: UserApi; + + beforeAll(async () => { + platform = await init({ + services: [ + "webserver", + "database", + "applications", + "search", + "storage", + "message-queue", + "user", + "search", + "files", + "websocket", + "messages", + "auth", + "realtime", + "channels", + "counter", + "statistics", + "platform-services", + "documents", + ], + }); + currentUser = await UserApi.getInstance(platform); + }); + + afterAll(async () => { + await platform?.tearDown(); + platform = null; + }); + + it("did fetch the trash", async () => { + await TestDbService.getInstance(platform!, true); + + const response = await currentUser.getDocument("trash"); + const result = deserialize(DriveItemDetailsMockClass, response.body); + + expect(result.item.id).toEqual("trash"); + expect(result.item.name).toEqual("Trash"); + }); + + it("did move an item to trash", async () => { + const createItemResult = await currentUser.createDefaultDocument(); + + expect(createItemResult.id).toBeDefined(); + + const moveToTrashResponse = await currentUser.delete(createItemResult.id); + expect(moveToTrashResponse.statusCode).toEqual(200); + + const listTrashResponse = await currentUser.getDocument("trash"); + const listTrashResult = deserialize( + DriveItemDetailsMockClass, + listTrashResponse.body, + ); + expect(listTrashResult.item.name).toEqual("Trash"); + expect(createItemResult).toBeDefined(); + expect(createItemResult.scope).toEqual("shared"); + expect(listTrashResult.children.some(({ id }) => id === createItemResult.id)).toBeTruthy(); + }); + + describe("deleting a file uploaded by an anonymous user should go to the sharers trash", () => { + async function getTrashContentIds() { + const listTrashResponse = await currentUser.getDocument("trash"); + expect(listTrashResponse.statusCode).toBe(200); + const listTrashResult = deserialize( + DriveItemDetailsMockClass, + listTrashResponse.body, + ); + return listTrashResult.children.map(({id}) => id); + } + + async function uploadFileAsAnonymousUser(destinationSharedFolder: DriveFile) { + const publicToken = await currentUser.getPublicLinkAccessToken(destinationSharedFolder); + expect(publicToken?.value?.length ?? "").toBeGreaterThan(0); + return await currentUser.impersonateWithJWT(publicToken.value, () => + currentUser.createDefaultDocument({ + parent_id: destinationSharedFolder.id, + })); + } + + it("finds the owner from the immediate parent folder", async () => { + const publiclyWriteableFolder = await currentUser.createDirectory(); + const setPublicWriteableResponse = await currentUser.shareWithPublicLink(publiclyWriteableFolder, "write"); + expect(setPublicWriteableResponse.statusCode).toBe(200); + + const anonymouslyUploadedDoc = await uploadFileAsAnonymousUser(publiclyWriteableFolder); + + const deletionToTrashResponse = await currentUser.delete(anonymouslyUploadedDoc.id); + expect(deletionToTrashResponse.statusCode).toBe(200); + + expect((await getTrashContentIds()).indexOf(anonymouslyUploadedDoc.id)).toBeGreaterThanOrEqual(0); + }); + }); +}); \ No newline at end of file diff --git a/tdrive/backend/node/test/e2e/documents/utils.ts b/tdrive/backend/node/test/e2e/documents/utils.ts index 884f7dc4..666dc01d 100644 --- a/tdrive/backend/node/test/e2e/documents/utils.ts +++ b/tdrive/backend/node/test/e2e/documents/utils.ts @@ -6,18 +6,6 @@ import * as fs from "fs"; const url = "/internal/services/documents/v1"; -export const e2e_deleteDocument = async (platform: TestPlatform, id: string | "root" | "trash") => { - const token = await platform.auth.getJWTToken(); - - return await platform.app.inject({ - method: "DELETE", - url: `${url}/companies/${platform.workspace.company_id}/item/${id}`, - headers: { - authorization: `Bearer ${token}`, - }, - }); -}; - export const e2e_updateDocument = async ( platform: TestPlatform, id: string | "root" | "trash", @@ -35,7 +23,6 @@ export const e2e_updateDocument = async ( }); }; - export const e2e_createVersion = async ( platform: TestPlatform, id: string,