Skip to content

Commit

Permalink
✅ expand credential sharing tests for User Management (#3931)
Browse files Browse the repository at this point in the history
* 🧪 Expand cred sharing tests

* ⚡ Add recently added flags

* ✅ fix and adjust tests for /credentials

Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com>
  • Loading branch information
ivov and BHesseldieck authored Aug 29, 2022
1 parent 477ad76 commit 1f7ae7e
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 104 deletions.
7 changes: 6 additions & 1 deletion packages/cli/src/credentials/credentials.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
104 changes: 104 additions & 0 deletions packages/cli/test/integration/credentials.ee.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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
// ----------------------------------------
Expand Down Expand Up @@ -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();
}
105 changes: 2 additions & 103 deletions packages/cli/test/integration/credentials.test.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -9,6 +10,7 @@ import * as utils from './shared/utils';

import type { AuthAgent, SaveCredentialFunction } from './shared/types';
import type { Role } from '../../src/databases/entities/Role';
import type { CredentialsEntity } from '../../src/databases/entities/CredentialsEntity';

jest.mock('../../src/telemetry');

Expand Down Expand Up @@ -380,109 +382,6 @@ test('PATCH /credentials/:id should fail with missing encryption key', async ()
mock.mockRestore();
});

test.skip('GET /credentials should retrieve 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 });

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;

expect(typeof ownerCredential.name).toBe('string');
expect(typeof ownerCredential.type).toBe('string');
expect(typeof ownerCredential.nodesAccess[0].nodeType).toBe('string');
expect(ownerCredential.encryptedData).toBeUndefined();

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);

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(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.sharedWith).toBeUndefined();
});

// @TODO: Test for member request

test.skip('GET /credentials should retrieve member creds for member', async () => {
const owner = await testDb.createUser({ globalRole: globalOwnerRole });
const member = await testDb.createUser({ globalRole: globalMemberRole });

await saveCredential(randomCredentialPayload(), { user: owner });

for (let i = 0; i < 3; i++) {
await saveCredential(randomCredentialPayload(), { user: member });
}

const response = await authAgent(member).get('/credentials');

expect(response.statusCode).toBe(200);
expect(response.body.data.length).toBe(3); // member retrieved only member creds

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();

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);

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 });

for (let i = 0; i < 3; i++) {
await saveCredential(randomCredentialPayload(), { user: owner });
}

const response = await authAgent(member).get('/credentials');

expect(response.statusCode).toBe(200);
expect(response.body.data.length).toBe(0); // member did not retrieve owner's creds
});

test('GET /credentials/:id should retrieve owned cred for owner', async () => {
const ownerShell = await testDb.createUserShell(globalOwnerRole);
const authOwnerAgent = authAgent(ownerShell);
Expand Down

0 comments on commit 1f7ae7e

Please sign in to comment.