From 265113c7381ab81131a213e96d0b7cee3d7a87b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Wed, 24 Aug 2022 10:35:46 +0200 Subject: [PATCH 1/3] :test_tube: Expand cred sharing tests --- .../cli/test/integration/credentials.test.ts | 97 ++++++++++--------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/packages/cli/test/integration/credentials.test.ts b/packages/cli/test/integration/credentials.test.ts index b31db19c56ed3..fac316050241a 100644 --- a/packages/cli/test/integration/credentials.test.ts +++ b/packages/cli/test/integration/credentials.test.ts @@ -9,6 +9,7 @@ import * as utils from './shared/utils'; import type { AuthAgent, SaveCredentialFunction } from './shared/types'; import type { Role } from '../../src/databases/entities/Role'; +import { CredentialsEntity } from '../../src/databases/entities/CredentialsEntity'; jest.mock('../../src/telemetry'); @@ -380,7 +381,7 @@ test('PATCH /credentials/:id should fail with missing encryption key', async () mock.mockRestore(); }); -test.skip('GET /credentials should retrieve all creds for owner', async () => { +test('GET /credentials should return all creds for owner', async () => { const owner = await testDb.createUser({ globalRole: globalOwnerRole }); const firstMember = await testDb.createUser({ globalRole: globalMemberRole }); const secondMember = await testDb.createUser({ globalRole: globalMemberRole }); @@ -398,15 +399,18 @@ test.skip('GET /credentials should retrieve all creds for owner', async () => { const [ownerCredential, memberCredential] = response.body.data; - expect(typeof ownerCredential.name).toBe('string'); - expect(typeof ownerCredential.type).toBe('string'); - expect(typeof ownerCredential.nodesAccess[0].nodeType).toBe('string'); - expect(ownerCredential.encryptedData).toBeUndefined(); + validateMainCredentialData(ownerCredential); + validateMainCredentialData(memberCredential); - expect(ownerCredential.ownedBy.id).toBe(owner.id); - expect(ownerCredential.ownedBy.email).toBe(owner.email); - expect(ownerCredential.ownedBy.firstName).toBe(owner.firstName); - expect(ownerCredential.ownedBy.lastName).toBe(owner.lastName); + expect(ownerCredential.ownedBy).toMatchObject({ + id: owner.id, + email: owner.email, + firstName: owner.firstName, + lastName: owner.lastName, + }); + + expect(Array.isArray(ownerCredential.sharedWith)).toBe(true); + expect(ownerCredential.sharedWith.length).toBe(2); const [firstSharee, secondSharee] = ownerCredential.sharedWith; @@ -424,63 +428,53 @@ test.skip('GET /credentials should retrieve all creds for owner', async () => { lastName: secondMember.lastName, }); - expect(typeof memberCredential.name).toBe('string'); - expect(typeof memberCredential.type).toBe('string'); - expect(typeof memberCredential.nodesAccess[0].nodeType).toBe('string'); - expect(memberCredential.encryptedData).toBeUndefined(); - - expect(memberCredential.ownedBy.id).toBe(firstMember.id); - expect(memberCredential.ownedBy.email).toBe(firstMember.email); - expect(memberCredential.ownedBy.firstName).toBe(firstMember.firstName); - expect(memberCredential.ownedBy.lastName).toBe(firstMember.lastName); + expect(memberCredential.ownedBy).toMatchObject({ + id: firstMember.id, + email: firstMember.email, + firstName: firstMember.firstName, + lastName: firstMember.lastName, + }); - expect(memberCredential.sharedWith).toBeUndefined(); + expect(Array.isArray(memberCredential.sharedWith)).toBe(true); + expect(memberCredential.sharedWith.length).toBe(0); }); -// @TODO: Test for member request - -test.skip('GET /credentials should retrieve member creds for member', async () => { +test('GET /credentials should return only relevant creds for member', async () => { const owner = await testDb.createUser({ globalRole: globalOwnerRole }); const member = await testDb.createUser({ globalRole: globalMemberRole }); await saveCredential(randomCredentialPayload(), { user: owner }); + const { id } = await saveCredential(randomCredentialPayload(), { user: member }); - for (let i = 0; i < 3; i++) { - await saveCredential(randomCredentialPayload(), { user: member }); - } + await authAgent(member).post(`/credentials/${id}/share`).send({ shareeId: owner.id }); const response = await authAgent(member).get('/credentials'); expect(response.statusCode).toBe(200); - expect(response.body.data.length).toBe(3); // member retrieved only member creds + expect(response.body.data.length).toBe(1); // member retrieved only member cred - for (const memberCredential of response.body.data) { - expect(typeof memberCredential.name).toBe('string'); - expect(typeof memberCredential.type).toBe('string'); - expect(typeof memberCredential.nodesAccess[0].nodeType).toBe('string'); - expect(memberCredential.encryptedData).toBeUndefined(); + const [memberCredential] = response.body.data; - expect(memberCredential.ownedBy.id).toBe(member.id); - expect(memberCredential.ownedBy.email).toBe(member.email); - expect(memberCredential.ownedBy.firstName).toBe(member.firstName); - expect(memberCredential.ownedBy.lastName).toBe(member.lastName); + validateMainCredentialData(memberCredential); - expect(memberCredential.sharedWith).toBeUndefined(); - } -}); - -test('GET /credentials should not retrieve owner creds for member', async () => { - const owner = await testDb.createUser({ globalRole: globalOwnerRole }); - const member = await testDb.createUser({ globalRole: globalMemberRole }); + expect(memberCredential.ownedBy).toMatchObject({ + id: member.id, + email: member.email, + firstName: member.firstName, + lastName: member.lastName, + }); - for (let i = 0; i < 3; i++) { - await saveCredential(randomCredentialPayload(), { user: owner }); - } + expect(Array.isArray(memberCredential.sharedWith)).toBe(true); + expect(memberCredential.sharedWith.length).toBe(1); - const response = await authAgent(member).get('/credentials'); + const [sharee] = memberCredential.sharedWith; - expect(response.statusCode).toBe(200); - expect(response.body.data.length).toBe(0); // member did not retrieve owner's creds + expect(sharee).toMatchObject({ + id: owner.id, + email: owner.email, + firstName: owner.firstName, + lastName: owner.lastName, + }); }); test('GET /credentials/:id should retrieve owned cred for owner', async () => { @@ -593,3 +587,10 @@ const INVALID_PAYLOADS = [ {}, undefined, ]; + +function validateMainCredentialData(ownerCredential: CredentialsEntity) { + expect(typeof ownerCredential.name).toBe('string'); + expect(typeof ownerCredential.type).toBe('string'); + expect(typeof ownerCredential.nodesAccess[0].nodeType).toBe('string'); + expect(ownerCredential.data).toBeUndefined(); +} From b47b07cb67b145335685b614c896a116c13094c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Wed, 24 Aug 2022 11:38:56 +0200 Subject: [PATCH 2/3] :zap: Add recently added flags --- packages/cli/test/integration/credentials.test.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/cli/test/integration/credentials.test.ts b/packages/cli/test/integration/credentials.test.ts index fac316050241a..174649f541033 100644 --- a/packages/cli/test/integration/credentials.test.ts +++ b/packages/cli/test/integration/credentials.test.ts @@ -1,6 +1,7 @@ import express from 'express'; import { UserSettings } from 'n8n-core'; +import config from '../../config'; import { Db } from '../../src'; import { RESPONSE_ERROR_MESSAGES } from '../../src/constants'; import { randomCredentialPayload, randomName, randomString } from './shared/random'; @@ -9,7 +10,7 @@ import * as utils from './shared/utils'; import type { AuthAgent, SaveCredentialFunction } from './shared/types'; import type { Role } from '../../src/databases/entities/Role'; -import { CredentialsEntity } from '../../src/databases/entities/CredentialsEntity'; +import type { CredentialsEntity } from '../../src/databases/entities/CredentialsEntity'; jest.mock('../../src/telemetry'); @@ -382,6 +383,8 @@ test('PATCH /credentials/:id should fail with missing encryption key', async () }); test('GET /credentials should return all creds for owner', async () => { + config.set('experimental.credentialsSharing', true); + const owner = await testDb.createUser({ globalRole: globalOwnerRole }); const firstMember = await testDb.createUser({ globalRole: globalMemberRole }); const secondMember = await testDb.createUser({ globalRole: globalMemberRole }); @@ -437,9 +440,13 @@ test('GET /credentials should return all creds for owner', async () => { expect(Array.isArray(memberCredential.sharedWith)).toBe(true); expect(memberCredential.sharedWith.length).toBe(0); + + config.set('experimental.credentialsSharing', false); }); test('GET /credentials should return only relevant creds for member', async () => { + config.set('experimental.credentialsSharing', true); + const owner = await testDb.createUser({ globalRole: globalOwnerRole }); const member = await testDb.createUser({ globalRole: globalMemberRole }); @@ -475,6 +482,8 @@ test('GET /credentials should return only relevant creds for member', async () = firstName: owner.firstName, lastName: owner.lastName, }); + + config.set('experimental.credentialsSharing', false); }); test('GET /credentials/:id should retrieve owned cred for owner', async () => { From 04b3cee344041892fb672be01e04deb4b2cf24ea Mon Sep 17 00:00:00 2001 From: Ben Hesseldieck Date: Mon, 29 Aug 2022 11:46:47 +0200 Subject: [PATCH 3/3] =?UTF-8?q?=E2=9C=85=20fix=20and=20adjust=20tests=20fo?= =?UTF-8?q?r=20/credentials?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cli/src/credentials/credentials.types.ts | 7 +- .../test/integration/credentials.ee.test.ts | 104 ++++++++++++++++ .../cli/test/integration/credentials.test.ts | 111 ------------------ 3 files changed, 110 insertions(+), 112 deletions(-) diff --git a/packages/cli/src/credentials/credentials.types.ts b/packages/cli/src/credentials/credentials.types.ts index a5bba341be0ef..3d41fe46da49a 100644 --- a/packages/cli/src/credentials/credentials.types.ts +++ b/packages/cli/src/credentials/credentials.types.ts @@ -5,4 +5,9 @@ export interface CredentialWithSharings extends ICredentialsDb { sharedWith?: UserSharingsDetails[]; } -type UserSharingsDetails = { id: string; email: string; firstName: string; lastName: string }; +export type UserSharingsDetails = { + id: string; + email: string; + firstName: string; + lastName: string; +}; diff --git a/packages/cli/test/integration/credentials.ee.test.ts b/packages/cli/test/integration/credentials.ee.test.ts index 288984168e0fd..feaeb79212811 100644 --- a/packages/cli/test/integration/credentials.ee.test.ts +++ b/packages/cli/test/integration/credentials.ee.test.ts @@ -3,6 +3,8 @@ import { In } from 'typeorm'; import config from '../../config'; import { Db } from '../../src'; +import type { UserSharingsDetails } from '../../src/credentials/credentials.types'; +import type { CredentialsEntity } from '../../src/databases/entities/CredentialsEntity'; import type { Role } from '../../src/databases/entities/Role'; import { randomCredentialPayload } from './shared/random'; import * as testDb from './shared/testDb'; @@ -93,6 +95,101 @@ test('router should switch based on flag', async () => { expect(eeGetStatus).toBe(200); }); +// ---------------------------------------- +// GET /credentials - fetch all credentials +// ---------------------------------------- + +test('GET /credentials should return all creds for owner', async () => { + const owner = await testDb.createUser({ globalRole: globalOwnerRole }); + const [member1, member2, member3] = await testDb.createManyUsers(3, { + globalRole: globalMemberRole, + }); + + const savedCredential = await saveCredential(randomCredentialPayload(), { user: owner }); + await saveCredential(randomCredentialPayload(), { user: member1 }); + + const sharedWith = [member1, member2, member3]; + await testDb.shareCredentialWithUsers(savedCredential, sharedWith); + + const response = await authAgent(owner).get('/credentials'); + + expect(response.statusCode).toBe(200); + expect(response.body.data.length).toBe(2); // owner retrieved owner cred and member cred + + const [ownerCredential, memberCredential] = response.body.data; + + validateMainCredentialData(ownerCredential); + validateMainCredentialData(memberCredential); + + expect(ownerCredential.ownedBy).toMatchObject({ + id: owner.id, + email: owner.email, + firstName: owner.firstName, + lastName: owner.lastName, + }); + + expect(Array.isArray(ownerCredential.sharedWith)).toBe(true); + expect(ownerCredential.sharedWith.length).toBe(3); + + ownerCredential.sharedWith.forEach((sharee: UserSharingsDetails, idx: number) => { + expect(sharee).toMatchObject({ + id: sharedWith[idx].id, + email: sharedWith[idx].email, + firstName: sharedWith[idx].firstName, + lastName: sharedWith[idx].lastName, + }); + }); + + expect(memberCredential.ownedBy).toMatchObject({ + id: member1.id, + email: member1.email, + firstName: member1.firstName, + lastName: member1.lastName, + }); + + expect(Array.isArray(memberCredential.sharedWith)).toBe(true); + expect(memberCredential.sharedWith.length).toBe(0); +}); + +test('GET /credentials should return only relevant creds for member', async () => { + const [member1, member2] = await testDb.createManyUsers(2, { + globalRole: globalMemberRole, + }); + + await saveCredential(randomCredentialPayload(), { user: member2 }); + const savedMemberCredential = await saveCredential(randomCredentialPayload(), { user: member1 }); + + await testDb.shareCredentialWithUsers(savedMemberCredential, [member2]); + + const response = await authAgent(member1).get('/credentials'); + + expect(response.statusCode).toBe(200); + expect(response.body.data.length).toBe(1); // member retrieved only member cred + + const [member1Credential] = response.body.data; + + validateMainCredentialData(member1Credential); + + expect(member1Credential.ownedBy).toMatchObject({ + id: member1.id, + email: member1.email, + firstName: member1.firstName, + lastName: member1.lastName, + }); + + expect(Array.isArray(member1Credential.sharedWith)).toBe(true); + expect(member1Credential.sharedWith.length).toBe(1); + + const [sharee] = member1Credential.sharedWith; + + expect(sharee).toMatchObject({ + id: member2.id, + email: member2.email, + firstName: member2.firstName, + lastName: member2.lastName, + }); +}); + // ---------------------------------------- // indempotent share/unshare // ---------------------------------------- @@ -278,3 +375,10 @@ test('PUT /credentials/:id/share should unshare the credential', async () => { expect(sharedCredentials.length).toBe(1); expect(sharedCredentials[0].userId).toBe(owner.id); }); + +function validateMainCredentialData(ownerCredential: CredentialsEntity) { + expect(typeof ownerCredential.name).toBe('string'); + expect(typeof ownerCredential.type).toBe('string'); + expect(typeof ownerCredential.nodesAccess[0].nodeType).toBe('string'); + expect(ownerCredential.data).toBeUndefined(); +} diff --git a/packages/cli/test/integration/credentials.test.ts b/packages/cli/test/integration/credentials.test.ts index 174649f541033..a642b77e78ca4 100644 --- a/packages/cli/test/integration/credentials.test.ts +++ b/packages/cli/test/integration/credentials.test.ts @@ -382,110 +382,6 @@ test('PATCH /credentials/:id should fail with missing encryption key', async () mock.mockRestore(); }); -test('GET /credentials should return all creds for owner', async () => { - config.set('experimental.credentialsSharing', true); - - const owner = await testDb.createUser({ globalRole: globalOwnerRole }); - const firstMember = await testDb.createUser({ globalRole: globalMemberRole }); - const secondMember = await testDb.createUser({ globalRole: globalMemberRole }); - - const { id } = await saveCredential(randomCredentialPayload(), { user: owner }); - await saveCredential(randomCredentialPayload(), { user: firstMember }); - - await authAgent(owner).post(`/credentials/${id}/share`).send({ shareeId: firstMember.id }); - await authAgent(owner).post(`/credentials/${id}/share`).send({ shareeId: secondMember.id }); - - const response = await authAgent(owner).get('/credentials'); - - expect(response.statusCode).toBe(200); - expect(response.body.data.length).toBe(2); // owner retrieved owner cred and member cred - - const [ownerCredential, memberCredential] = response.body.data; - - validateMainCredentialData(ownerCredential); - validateMainCredentialData(memberCredential); - - expect(ownerCredential.ownedBy).toMatchObject({ - id: owner.id, - email: owner.email, - firstName: owner.firstName, - lastName: owner.lastName, - }); - - expect(Array.isArray(ownerCredential.sharedWith)).toBe(true); - expect(ownerCredential.sharedWith.length).toBe(2); - - const [firstSharee, secondSharee] = ownerCredential.sharedWith; - - expect(firstSharee).toMatchObject({ - id: firstMember.id, - email: firstMember.email, - firstName: firstMember.firstName, - lastName: firstMember.lastName, - }); - - expect(secondSharee).toMatchObject({ - id: secondMember.id, - email: secondMember.email, - firstName: secondMember.firstName, - lastName: secondMember.lastName, - }); - - expect(memberCredential.ownedBy).toMatchObject({ - id: firstMember.id, - email: firstMember.email, - firstName: firstMember.firstName, - lastName: firstMember.lastName, - }); - - expect(Array.isArray(memberCredential.sharedWith)).toBe(true); - expect(memberCredential.sharedWith.length).toBe(0); - - config.set('experimental.credentialsSharing', false); -}); - -test('GET /credentials should return only relevant creds for member', async () => { - config.set('experimental.credentialsSharing', true); - - const owner = await testDb.createUser({ globalRole: globalOwnerRole }); - const member = await testDb.createUser({ globalRole: globalMemberRole }); - - await saveCredential(randomCredentialPayload(), { user: owner }); - const { id } = await saveCredential(randomCredentialPayload(), { user: member }); - - await authAgent(member).post(`/credentials/${id}/share`).send({ shareeId: owner.id }); - - const response = await authAgent(member).get('/credentials'); - - expect(response.statusCode).toBe(200); - expect(response.body.data.length).toBe(1); // member retrieved only member cred - - const [memberCredential] = response.body.data; - - validateMainCredentialData(memberCredential); - - expect(memberCredential.ownedBy).toMatchObject({ - id: member.id, - email: member.email, - firstName: member.firstName, - lastName: member.lastName, - }); - - expect(Array.isArray(memberCredential.sharedWith)).toBe(true); - expect(memberCredential.sharedWith.length).toBe(1); - - const [sharee] = memberCredential.sharedWith; - - expect(sharee).toMatchObject({ - id: owner.id, - email: owner.email, - firstName: owner.firstName, - lastName: owner.lastName, - }); - - config.set('experimental.credentialsSharing', false); -}); - test('GET /credentials/:id should retrieve owned cred for owner', async () => { const ownerShell = await testDb.createUserShell(globalOwnerRole); const authOwnerAgent = authAgent(ownerShell); @@ -596,10 +492,3 @@ const INVALID_PAYLOADS = [ {}, undefined, ]; - -function validateMainCredentialData(ownerCredential: CredentialsEntity) { - expect(typeof ownerCredential.name).toBe('string'); - expect(typeof ownerCredential.type).toBe('string'); - expect(typeof ownerCredential.nodesAccess[0].nodeType).toBe('string'); - expect(ownerCredential.data).toBeUndefined(); -}