mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-09 22:24:05 -08:00
ci(core): Reduce memory usage in tests (part-1) (no-changelog) (#7654)
This commit is contained in:
parent
6a53c2a375
commit
0346b211a7
|
@ -66,23 +66,20 @@ import type {
|
|||
WorkflowRequest,
|
||||
} from '@/requests';
|
||||
import { registerController } from '@/decorators';
|
||||
import {
|
||||
AuthController,
|
||||
LdapController,
|
||||
MeController,
|
||||
MFAController,
|
||||
NodeTypesController,
|
||||
OAuth1CredentialController,
|
||||
OAuth2CredentialController,
|
||||
OwnerController,
|
||||
PasswordResetController,
|
||||
TagsController,
|
||||
TranslationController,
|
||||
UsersController,
|
||||
WorkflowStatisticsController,
|
||||
} from '@/controllers';
|
||||
|
||||
import { BinaryDataController } from './controllers/binaryData.controller';
|
||||
import { AuthController } from '@/controllers/auth.controller';
|
||||
import { BinaryDataController } from '@/controllers/binaryData.controller';
|
||||
import { LdapController } from '@/controllers/ldap.controller';
|
||||
import { MeController } from '@/controllers/me.controller';
|
||||
import { MFAController } from '@/controllers/mfa.controller';
|
||||
import { NodeTypesController } from '@/controllers/nodeTypes.controller';
|
||||
import { OAuth1CredentialController } from '@/controllers/oauth/oAuth1Credential.controller';
|
||||
import { OAuth2CredentialController } from '@/controllers/oauth/oAuth2Credential.controller';
|
||||
import { OwnerController } from '@/controllers/owner.controller';
|
||||
import { PasswordResetController } from '@/controllers/passwordReset.controller';
|
||||
import { TagsController } from '@/controllers/tags.controller';
|
||||
import { TranslationController } from '@/controllers/translation.controller';
|
||||
import { UsersController } from '@/controllers/users.controller';
|
||||
import { WorkflowStatisticsController } from '@/controllers/workflowStatistics.controller';
|
||||
import { ExternalSecretsController } from '@/ExternalSecrets/ExternalSecrets.controller.ee';
|
||||
import { executionsController } from '@/executions/executions.controller';
|
||||
import { isApiEnabled, loadPublicApiVersions } from '@/PublicApi';
|
||||
|
|
|
@ -48,8 +48,6 @@ import { generateFailedExecutionFromError } from '@/WorkflowHelpers';
|
|||
import { initErrorHandling } from '@/ErrorReporting';
|
||||
import { PermissionChecker } from '@/UserManagement/PermissionChecker';
|
||||
import { Push } from '@/push';
|
||||
import { eventBus } from './eventbus';
|
||||
import { recoverExecutionDataFromEventLogMessages } from './eventbus/MessageEventBus/recoverEvents';
|
||||
import { Container } from 'typedi';
|
||||
import { InternalHooks } from './InternalHooks';
|
||||
import { ExecutionRepository } from '@db/repositories';
|
||||
|
@ -131,9 +129,13 @@ export class WorkflowRunner {
|
|||
// does contain those messages.
|
||||
try {
|
||||
// Search for messages for this executionId in event logs
|
||||
const { eventBus } = await import('./eventbus');
|
||||
const eventLogMessages = await eventBus.getEventsByExecutionId(executionId);
|
||||
// Attempt to recover more better runData from these messages (but don't update the execution db entry yet)
|
||||
if (eventLogMessages.length > 0) {
|
||||
const { recoverExecutionDataFromEventLogMessages } = await import(
|
||||
'./eventbus/MessageEventBus/recoverEvents'
|
||||
);
|
||||
const eventLogExecutionData = await recoverExecutionDataFromEventLogMessages(
|
||||
executionId,
|
||||
eventLogMessages,
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
export { AuthController } from './auth.controller';
|
||||
export { LdapController } from './ldap.controller';
|
||||
export { MeController } from './me.controller';
|
||||
export { MFAController } from './mfa.controller';
|
||||
export { NodeTypesController } from './nodeTypes.controller';
|
||||
export { OAuth1CredentialController } from './oauth/oAuth1Credential.controller';
|
||||
export { OAuth2CredentialController } from './oauth/oAuth2Credential.controller';
|
||||
export { OwnerController } from './owner.controller';
|
||||
export { PasswordResetController } from './passwordReset.controller';
|
||||
export { TagsController } from './tags.controller';
|
||||
export { TranslationController } from './translation.controller';
|
||||
export { UsersController } from './users.controller';
|
||||
export { WorkflowStatisticsController } from './workflowStatistics.controller';
|
|
@ -1,7 +1,10 @@
|
|||
import { Service } from 'typedi';
|
||||
import { Authorized, Delete, Get, Post, RestController } from '@/decorators';
|
||||
import { AuthenticatedRequest, MFA } from '@/requests';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import { MfaService } from '@/Mfa/mfa.service';
|
||||
|
||||
@Service()
|
||||
@Authorized()
|
||||
@RestController('/mfa')
|
||||
export class MFAController {
|
||||
|
|
|
@ -22,6 +22,8 @@ import type { WebhookEntity } from '@/databases/entities/WebhookEntity';
|
|||
import { NodeTypes } from '@/NodeTypes';
|
||||
import { chooseRandomly } from './shared/random';
|
||||
import { MultiMainInstancePublisher } from '@/services/orchestration/main/MultiMainInstance.publisher.ee';
|
||||
import { createOwner } from './shared/db/users';
|
||||
import { createWorkflow } from './shared/db/workflows';
|
||||
|
||||
mockInstance(ActiveExecutions);
|
||||
mockInstance(ActiveWorkflows);
|
||||
|
@ -50,7 +52,7 @@ beforeAll(async () => {
|
|||
await testDb.init();
|
||||
|
||||
activeWorkflowRunner = Container.get(ActiveWorkflowRunner);
|
||||
owner = await testDb.createOwner();
|
||||
owner = await createOwner();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
|
@ -88,7 +90,7 @@ describe('init()', () => {
|
|||
});
|
||||
|
||||
test('should start with one active workflow', async () => {
|
||||
await testDb.createWorkflow({ active: true }, owner);
|
||||
await createWorkflow({ active: true }, owner);
|
||||
|
||||
await activeWorkflowRunner.init();
|
||||
|
||||
|
@ -100,8 +102,8 @@ describe('init()', () => {
|
|||
});
|
||||
|
||||
test('should start with multiple active workflows', async () => {
|
||||
await testDb.createWorkflow({ active: true }, owner);
|
||||
await testDb.createWorkflow({ active: true }, owner);
|
||||
await createWorkflow({ active: true }, owner);
|
||||
await createWorkflow({ active: true }, owner);
|
||||
|
||||
await activeWorkflowRunner.init();
|
||||
|
||||
|
@ -113,8 +115,8 @@ describe('init()', () => {
|
|||
});
|
||||
|
||||
test('should pre-check that every workflow can be activated', async () => {
|
||||
await testDb.createWorkflow({ active: true }, owner);
|
||||
await testDb.createWorkflow({ active: true }, owner);
|
||||
await createWorkflow({ active: true }, owner);
|
||||
await createWorkflow({ active: true }, owner);
|
||||
|
||||
const precheckSpy = jest
|
||||
.spyOn(Workflow.prototype, 'checkIfWorkflowCanBeActivated')
|
||||
|
@ -128,8 +130,8 @@ describe('init()', () => {
|
|||
|
||||
describe('removeAll()', () => {
|
||||
test('should remove all active workflows from memory', async () => {
|
||||
await testDb.createWorkflow({ active: true }, owner);
|
||||
await testDb.createWorkflow({ active: true }, owner);
|
||||
await createWorkflow({ active: true }, owner);
|
||||
await createWorkflow({ active: true }, owner);
|
||||
|
||||
await activeWorkflowRunner.init();
|
||||
await activeWorkflowRunner.removeAll();
|
||||
|
@ -141,7 +143,7 @@ describe('removeAll()', () => {
|
|||
|
||||
describe('remove()', () => {
|
||||
test('should call `ActiveWorkflowRunner.clearWebhooks()`', async () => {
|
||||
const workflow = await testDb.createWorkflow({ active: true }, owner);
|
||||
const workflow = await createWorkflow({ active: true }, owner);
|
||||
const clearWebhooksSpy = jest.spyOn(activeWorkflowRunner, 'clearWebhooks');
|
||||
|
||||
await activeWorkflowRunner.init();
|
||||
|
@ -153,7 +155,7 @@ describe('remove()', () => {
|
|||
|
||||
describe('isActive()', () => {
|
||||
test('should return `true` for active workflow in storage', async () => {
|
||||
const workflow = await testDb.createWorkflow({ active: true }, owner);
|
||||
const workflow = await createWorkflow({ active: true }, owner);
|
||||
|
||||
await activeWorkflowRunner.init();
|
||||
|
||||
|
@ -162,7 +164,7 @@ describe('isActive()', () => {
|
|||
});
|
||||
|
||||
test('should return `false` for inactive workflow in storage', async () => {
|
||||
const workflow = await testDb.createWorkflow({ active: false }, owner);
|
||||
const workflow = await createWorkflow({ active: false }, owner);
|
||||
|
||||
await activeWorkflowRunner.init();
|
||||
|
||||
|
@ -173,7 +175,7 @@ describe('isActive()', () => {
|
|||
|
||||
describe('runWorkflow()', () => {
|
||||
test('should call `WorkflowRunner.run()`', async () => {
|
||||
const workflow = await testDb.createWorkflow({ active: true }, owner);
|
||||
const workflow = await createWorkflow({ active: true }, owner);
|
||||
|
||||
await activeWorkflowRunner.init();
|
||||
|
||||
|
@ -193,7 +195,7 @@ describe('runWorkflow()', () => {
|
|||
|
||||
describe('executeErrorWorkflow()', () => {
|
||||
test('should call `WorkflowExecuteAdditionalData.executeErrorWorkflow()`', async () => {
|
||||
const workflow = await testDb.createWorkflow({ active: true }, owner);
|
||||
const workflow = await createWorkflow({ active: true }, owner);
|
||||
const [node] = workflow.nodes;
|
||||
const error = new NodeOperationError(node, 'Fake error message');
|
||||
const executeSpy = jest.spyOn(AdditionalData, 'executeErrorWorkflow');
|
||||
|
@ -205,7 +207,7 @@ describe('executeErrorWorkflow()', () => {
|
|||
});
|
||||
|
||||
test('should be called on failure to activate due to 401', async () => {
|
||||
const storedWorkflow = await testDb.createWorkflow({ active: true }, owner);
|
||||
const storedWorkflow = await createWorkflow({ active: true }, owner);
|
||||
const [node] = storedWorkflow.nodes;
|
||||
const executeSpy = jest.spyOn(activeWorkflowRunner, 'executeErrorWorkflow');
|
||||
|
||||
|
@ -230,7 +232,7 @@ describe('add()', () => {
|
|||
test('leader should add webhooks, triggers and pollers', async () => {
|
||||
const mode = chooseRandomly(NON_LEADERSHIP_CHANGE_MODES);
|
||||
|
||||
const workflow = await testDb.createWorkflow({ active: true }, owner);
|
||||
const workflow = await createWorkflow({ active: true }, owner);
|
||||
|
||||
const addWebhooksSpy = jest.spyOn(activeWorkflowRunner, 'addWebhooks');
|
||||
const addTriggersAndPollersSpy = jest.spyOn(activeWorkflowRunner, 'addTriggersAndPollers');
|
||||
|
@ -256,7 +258,7 @@ describe('add()', () => {
|
|||
|
||||
mockInstance(MultiMainInstancePublisher, { isLeader: true });
|
||||
|
||||
const workflow = await testDb.createWorkflow({ active: true }, owner);
|
||||
const workflow = await createWorkflow({ active: true }, owner);
|
||||
|
||||
const addWebhooksSpy = jest.spyOn(activeWorkflowRunner, 'addWebhooks');
|
||||
const addTriggersAndPollersSpy = jest.spyOn(activeWorkflowRunner, 'addTriggersAndPollers');
|
||||
|
@ -278,7 +280,7 @@ describe('add()', () => {
|
|||
|
||||
mockInstance(MultiMainInstancePublisher, { isLeader: true });
|
||||
|
||||
const workflow = await testDb.createWorkflow({ active: true }, owner);
|
||||
const workflow = await createWorkflow({ active: true }, owner);
|
||||
|
||||
const addWebhooksSpy = jest.spyOn(activeWorkflowRunner, 'addWebhooks');
|
||||
const addTriggersAndPollersSpy = jest.spyOn(activeWorkflowRunner, 'addTriggersAndPollers');
|
||||
|
@ -302,7 +304,7 @@ describe('add()', () => {
|
|||
|
||||
mockInstance(MultiMainInstancePublisher, { isLeader: false });
|
||||
|
||||
const workflow = await testDb.createWorkflow({ active: true }, owner);
|
||||
const workflow = await createWorkflow({ active: true }, owner);
|
||||
|
||||
const addWebhooksSpy = jest.spyOn(activeWorkflowRunner, 'addWebhooks');
|
||||
const addTriggersAndPollersSpy = jest.spyOn(activeWorkflowRunner, 'addTriggersAndPollers');
|
||||
|
@ -330,7 +332,7 @@ describe('addWebhooks()', () => {
|
|||
|
||||
const additionalData = await AdditionalData.getBase('fake-user-id');
|
||||
|
||||
const dbWorkflow = await testDb.createWorkflow({ active: true }, owner);
|
||||
const dbWorkflow = await createWorkflow({ active: true }, owner);
|
||||
|
||||
const workflow = new Workflow({
|
||||
id: dbWorkflow.id,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import type { SuperAgentTest } from 'supertest';
|
||||
import { License } from '@/License';
|
||||
import * as testDb from '../shared/testDb';
|
||||
import * as utils from '../shared/utils/';
|
||||
import type { ExternalSecretsSettings, SecretsProviderState } from '@/Interfaces';
|
||||
import { Cipher } from 'n8n-core';
|
||||
|
@ -18,6 +17,7 @@ import { ExternalSecretsManager } from '@/ExternalSecrets/ExternalSecretsManager
|
|||
import { CREDENTIAL_BLANKING_VALUE } from '@/constants';
|
||||
import { jsonParse, type IDataObject } from 'n8n-workflow';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import { createOwner, createUser } from '../shared/db/users';
|
||||
|
||||
let authOwnerAgent: SuperAgentTest;
|
||||
let authMemberAgent: SuperAgentTest;
|
||||
|
@ -97,9 +97,9 @@ const getDummyProviderData = ({
|
|||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
const owner = await testDb.createOwner();
|
||||
const owner = await createOwner();
|
||||
authOwnerAgent = testServer.authAgentFor(owner);
|
||||
const member = await testDb.createUser();
|
||||
const member = await createUser();
|
||||
authMemberAgent = testServer.authAgentFor(member);
|
||||
config.set('userManagement.isInstanceOwnerSetUp', true);
|
||||
});
|
||||
|
|
|
@ -11,6 +11,8 @@ import { LOGGED_OUT_RESPONSE_BODY } from './shared/constants';
|
|||
import { randomValidPassword } from './shared/random';
|
||||
import * as testDb from './shared/testDb';
|
||||
import * as utils from './shared/utils/';
|
||||
import { getGlobalMemberRole, getGlobalOwnerRole } from './shared/db/roles';
|
||||
import { createUser, createUserShell } from './shared/db/users';
|
||||
|
||||
let globalOwnerRole: Role;
|
||||
let globalMemberRole: Role;
|
||||
|
@ -21,8 +23,8 @@ const ownerPassword = randomValidPassword();
|
|||
const testServer = utils.setupTestServer({ endpointGroups: ['auth'] });
|
||||
|
||||
beforeAll(async () => {
|
||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||
globalMemberRole = await testDb.getGlobalMemberRole();
|
||||
globalOwnerRole = await getGlobalOwnerRole();
|
||||
globalMemberRole = await getGlobalMemberRole();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
|
@ -33,7 +35,7 @@ beforeEach(async () => {
|
|||
|
||||
describe('POST /login', () => {
|
||||
beforeEach(async () => {
|
||||
owner = await testDb.createUser({
|
||||
owner = await createUser({
|
||||
password: ownerPassword,
|
||||
globalRole: globalOwnerRole,
|
||||
});
|
||||
|
@ -69,7 +71,7 @@ describe('POST /login', () => {
|
|||
test('should throw AuthError for non-owner if not within users limit quota', async () => {
|
||||
jest.spyOn(Container.get(License), 'isWithinUsersLimit').mockReturnValueOnce(false);
|
||||
const password = 'testpassword';
|
||||
const member = await testDb.createUser({
|
||||
const member = await createUser({
|
||||
password,
|
||||
});
|
||||
|
||||
|
@ -82,7 +84,7 @@ describe('POST /login', () => {
|
|||
|
||||
test('should not throw AuthError for owner if not within users limit quota', async () => {
|
||||
jest.spyOn(Container.get(License), 'isWithinUsersLimit').mockReturnValueOnce(false);
|
||||
const ownerUser = await testDb.createUser({
|
||||
const ownerUser = await createUser({
|
||||
password: randomValidPassword(),
|
||||
globalRole: globalOwnerRole,
|
||||
isOwner: true,
|
||||
|
@ -104,7 +106,7 @@ describe('GET /login', () => {
|
|||
});
|
||||
|
||||
test('should return cookie if UM is disabled and no cookie is already set', async () => {
|
||||
await testDb.createUserShell(globalOwnerRole);
|
||||
await createUserShell(globalOwnerRole);
|
||||
await utils.setInstanceOwnerSetUp(false);
|
||||
|
||||
const response = await testServer.authlessAgent.get('/login');
|
||||
|
@ -127,7 +129,7 @@ describe('GET /login', () => {
|
|||
});
|
||||
|
||||
test('should return logged-in owner shell', async () => {
|
||||
const ownerShell = await testDb.createUserShell(globalOwnerRole);
|
||||
const ownerShell = await createUserShell(globalOwnerRole);
|
||||
|
||||
const response = await testServer.authAgentFor(ownerShell).get('/login');
|
||||
|
||||
|
@ -153,7 +155,7 @@ describe('GET /login', () => {
|
|||
});
|
||||
|
||||
test('should return logged-in member shell', async () => {
|
||||
const memberShell = await testDb.createUserShell(globalMemberRole);
|
||||
const memberShell = await createUserShell(globalMemberRole);
|
||||
|
||||
const response = await testServer.authAgentFor(memberShell).get('/login');
|
||||
|
||||
|
@ -179,7 +181,7 @@ describe('GET /login', () => {
|
|||
});
|
||||
|
||||
test('should return logged-in owner', async () => {
|
||||
const owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
const owner = await createUser({ globalRole: globalOwnerRole });
|
||||
|
||||
const response = await testServer.authAgentFor(owner).get('/login');
|
||||
|
||||
|
@ -205,7 +207,7 @@ describe('GET /login', () => {
|
|||
});
|
||||
|
||||
test('should return logged-in member', async () => {
|
||||
const member = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
const member = await createUser({ globalRole: globalMemberRole });
|
||||
|
||||
const response = await testServer.authAgentFor(member).get('/login');
|
||||
|
||||
|
@ -233,7 +235,7 @@ describe('GET /login', () => {
|
|||
|
||||
describe('GET /resolve-signup-token', () => {
|
||||
beforeEach(async () => {
|
||||
owner = await testDb.createUser({
|
||||
owner = await createUser({
|
||||
password: ownerPassword,
|
||||
globalRole: globalOwnerRole,
|
||||
});
|
||||
|
@ -241,7 +243,7 @@ describe('GET /resolve-signup-token', () => {
|
|||
});
|
||||
|
||||
test('should validate invite token', async () => {
|
||||
const memberShell = await testDb.createUserShell(globalMemberRole);
|
||||
const memberShell = await createUserShell(globalMemberRole);
|
||||
|
||||
const response = await authOwnerAgent
|
||||
.get('/resolve-signup-token')
|
||||
|
@ -261,7 +263,7 @@ describe('GET /resolve-signup-token', () => {
|
|||
|
||||
test('should return 403 if user quota reached', async () => {
|
||||
jest.spyOn(Container.get(License), 'isWithinUsersLimit').mockReturnValueOnce(false);
|
||||
const memberShell = await testDb.createUserShell(globalMemberRole);
|
||||
const memberShell = await createUserShell(globalMemberRole);
|
||||
|
||||
const response = await authOwnerAgent
|
||||
.get('/resolve-signup-token')
|
||||
|
@ -272,7 +274,7 @@ describe('GET /resolve-signup-token', () => {
|
|||
});
|
||||
|
||||
test('should fail with invalid inputs', async () => {
|
||||
const { id: inviteeId } = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
const { id: inviteeId } = await createUser({ globalRole: globalMemberRole });
|
||||
|
||||
const first = await authOwnerAgent.get('/resolve-signup-token').query({ inviterId: owner.id });
|
||||
|
||||
|
@ -304,7 +306,7 @@ describe('GET /resolve-signup-token', () => {
|
|||
|
||||
describe('POST /logout', () => {
|
||||
test('should log user out', async () => {
|
||||
const owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
const owner = await createUser({ globalRole: globalOwnerRole });
|
||||
|
||||
const response = await testServer.authAgentFor(owner).post('/logout');
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import type { SuperAgentTest } from 'supertest';
|
||||
import * as testDb from './shared/testDb';
|
||||
import * as utils from './shared/utils/';
|
||||
import { getGlobalMemberRole } from './shared/db/roles';
|
||||
import { createUser } from './shared/db/users';
|
||||
|
||||
describe('Auth Middleware', () => {
|
||||
const testServer = utils.setupTestServer({ endpointGroups: ['me', 'auth', 'owner', 'users'] });
|
||||
|
@ -36,8 +37,8 @@ describe('Auth Middleware', () => {
|
|||
describe('Routes requiring Authorization', () => {
|
||||
let authMemberAgent: SuperAgentTest;
|
||||
beforeAll(async () => {
|
||||
const globalMemberRole = await testDb.getGlobalMemberRole();
|
||||
const member = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
const globalMemberRole = await getGlobalMemberRole();
|
||||
const member = await createUser({ globalRole: globalMemberRole });
|
||||
authMemberAgent = testServer.authAgentFor(member);
|
||||
});
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import fsp from 'node:fs/promises';
|
||||
import { Readable } from 'node:stream';
|
||||
import { BinaryDataService, FileNotFoundError } from 'n8n-core';
|
||||
import * as testDb from './shared/testDb';
|
||||
import { mockInstance, setupTestServer } from './shared/utils';
|
||||
import type { SuperAgentTest } from 'supertest';
|
||||
import { createOwner } from './shared/db/users';
|
||||
|
||||
jest.mock('fs/promises');
|
||||
|
||||
|
@ -16,7 +16,7 @@ let testServer = setupTestServer({ endpointGroups: ['binaryData'] });
|
|||
let authOwnerAgent: SuperAgentTest;
|
||||
|
||||
beforeAll(async () => {
|
||||
const owner = await testDb.createOwner();
|
||||
const owner = await createOwner();
|
||||
authOwnerAgent = testServer.authAgentFor(owner);
|
||||
});
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import { ImportCredentialsCommand } from '@/commands/import/credentials';
|
|||
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
|
||||
import * as testDb from '../shared/testDb';
|
||||
import { mockInstance } from '../shared/utils';
|
||||
import { getAllCredentials } from '../shared/db/credentials';
|
||||
|
||||
beforeAll(async () => {
|
||||
mockInstance(InternalHooks);
|
||||
|
@ -22,7 +23,7 @@ afterAll(async () => {
|
|||
|
||||
test('import:credentials should import a credential', async () => {
|
||||
const config: Config.IConfig = new Config.Config({ root: __dirname });
|
||||
const before = await testDb.getAllCredentials();
|
||||
const before = await getAllCredentials();
|
||||
expect(before.length).toBe(0);
|
||||
const importer = new ImportCredentialsCommand(
|
||||
['--input=./test/integration/commands/importCredentials/credentials.json'],
|
||||
|
@ -38,7 +39,7 @@ test('import:credentials should import a credential', async () => {
|
|||
} catch (error) {
|
||||
expect(error.message).toBe('process.exit');
|
||||
}
|
||||
const after = await testDb.getAllCredentials();
|
||||
const after = await getAllCredentials();
|
||||
expect(after.length).toBe(1);
|
||||
expect(after[0].name).toBe('cred-aws-test');
|
||||
expect(after[0].id).toBe('123');
|
||||
|
|
|
@ -5,6 +5,7 @@ import { ImportWorkflowsCommand } from '@/commands/import/workflow';
|
|||
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
|
||||
import * as testDb from '../shared/testDb';
|
||||
import { mockInstance } from '../shared/utils/';
|
||||
import { getAllWorkflows } from '../shared/db/workflows';
|
||||
|
||||
beforeAll(async () => {
|
||||
mockInstance(InternalHooks);
|
||||
|
@ -22,7 +23,7 @@ afterAll(async () => {
|
|||
|
||||
test('import:workflow should import active workflow and deactivate it', async () => {
|
||||
const config: Config.IConfig = new Config.Config({ root: __dirname });
|
||||
const before = await testDb.getAllWorkflows();
|
||||
const before = await getAllWorkflows();
|
||||
expect(before.length).toBe(0);
|
||||
const importer = new ImportWorkflowsCommand(
|
||||
['--separate', '--input=./test/integration/commands/importWorkflows/separate'],
|
||||
|
@ -38,7 +39,7 @@ test('import:workflow should import active workflow and deactivate it', async ()
|
|||
} catch (error) {
|
||||
expect(error.message).toBe('process.exit');
|
||||
}
|
||||
const after = await testDb.getAllWorkflows();
|
||||
const after = await getAllWorkflows();
|
||||
expect(after.length).toBe(2);
|
||||
expect(after[0].name).toBe('active-workflow');
|
||||
expect(after[0].active).toBe(false);
|
||||
|
@ -49,7 +50,7 @@ test('import:workflow should import active workflow and deactivate it', async ()
|
|||
|
||||
test('import:workflow should import active workflow from combined file and deactivate it', async () => {
|
||||
const config: Config.IConfig = new Config.Config({ root: __dirname });
|
||||
const before = await testDb.getAllWorkflows();
|
||||
const before = await getAllWorkflows();
|
||||
expect(before.length).toBe(0);
|
||||
const importer = new ImportWorkflowsCommand(
|
||||
['--input=./test/integration/commands/importWorkflows/combined/combined.json'],
|
||||
|
@ -65,7 +66,7 @@ test('import:workflow should import active workflow from combined file and deact
|
|||
} catch (error) {
|
||||
expect(error.message).toBe('process.exit');
|
||||
}
|
||||
const after = await testDb.getAllWorkflows();
|
||||
const after = await getAllWorkflows();
|
||||
expect(after.length).toBe(2);
|
||||
expect(after[0].name).toBe('active-workflow');
|
||||
expect(after[0].active).toBe(false);
|
||||
|
|
|
@ -6,6 +6,8 @@ import { mockInstance } from '../shared/utils/';
|
|||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
|
||||
import { NodeTypes } from '@/NodeTypes';
|
||||
import { getGlobalOwnerRole } from '../shared/db/roles';
|
||||
import { createUser } from '../shared/db/users';
|
||||
|
||||
let globalOwnerRole: Role;
|
||||
|
||||
|
@ -15,7 +17,7 @@ beforeAll(async () => {
|
|||
mockInstance(NodeTypes);
|
||||
await testDb.init();
|
||||
|
||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||
globalOwnerRole = await getGlobalOwnerRole();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
|
@ -28,7 +30,7 @@ afterAll(async () => {
|
|||
|
||||
// eslint-disable-next-line n8n-local-rules/no-skipped-tests
|
||||
test.skip('user-management:reset should reset DB to default user state', async () => {
|
||||
await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
await createUser({ globalRole: globalOwnerRole });
|
||||
|
||||
await Reset.run();
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import { Push } from '@/push';
|
|||
import { CommunityPackagesService } from '@/services/communityPackages.service';
|
||||
|
||||
import { COMMUNITY_PACKAGE_VERSION } from './shared/constants';
|
||||
import * as testDb from './shared/testDb';
|
||||
import {
|
||||
mockInstance,
|
||||
setupTestServer,
|
||||
|
@ -16,6 +15,7 @@ import {
|
|||
mockNode,
|
||||
mockPackageName,
|
||||
} from './shared/utils';
|
||||
import { createOwner } from './shared/db/users';
|
||||
|
||||
const communityPackagesService = mockInstance(CommunityPackagesService, {
|
||||
hasMissingPackages: false,
|
||||
|
@ -40,7 +40,7 @@ const parsedNpmPackageName = {
|
|||
let authAgent: SuperAgentTest;
|
||||
|
||||
beforeAll(async () => {
|
||||
const ownerShell = await testDb.createOwner();
|
||||
const ownerShell = await createOwner();
|
||||
authAgent = testServer.authAgentFor(ownerShell);
|
||||
});
|
||||
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import * as testDb from './shared/testDb';
|
||||
import * as utils from './shared/utils/';
|
||||
import { randomCredentialPayload as payload } from './shared/random';
|
||||
|
||||
import type { Credentials } from '@/requests';
|
||||
import type { User } from '@db/entities/User';
|
||||
import * as testDb from './shared/testDb';
|
||||
import { setupTestServer } from './shared/utils/';
|
||||
import { randomCredentialPayload as payload } from './shared/random';
|
||||
import { saveCredential } from './shared/db/credentials';
|
||||
import { createMember, createOwner } from './shared/db/users';
|
||||
import { getCredentialOwnerRole } from './shared/db/roles';
|
||||
|
||||
const { any } = expect;
|
||||
|
||||
const testServer = utils.setupTestServer({ endpointGroups: ['credentials'] });
|
||||
const testServer = setupTestServer({ endpointGroups: ['credentials'] });
|
||||
|
||||
let owner: User;
|
||||
let member: User;
|
||||
|
@ -15,8 +17,8 @@ let member: User;
|
|||
beforeEach(async () => {
|
||||
await testDb.truncate(['SharedCredentials', 'Credentials']);
|
||||
|
||||
owner = await testDb.createOwner();
|
||||
member = await testDb.createMember();
|
||||
owner = await createOwner();
|
||||
member = await createMember();
|
||||
});
|
||||
|
||||
type GetAllResponse = { body: { data: Credentials.WithOwnedByAndSharedWith[] } };
|
||||
|
@ -24,10 +26,10 @@ type GetAllResponse = { body: { data: Credentials.WithOwnedByAndSharedWith[] } }
|
|||
describe('GET /credentials', () => {
|
||||
describe('should return', () => {
|
||||
test('all credentials for owner', async () => {
|
||||
const role = await testDb.getCredentialOwnerRole();
|
||||
const role = await getCredentialOwnerRole();
|
||||
|
||||
const { id: id1 } = await testDb.saveCredential(payload(), { user: owner, role });
|
||||
const { id: id2 } = await testDb.saveCredential(payload(), { user: member, role });
|
||||
const { id: id1 } = await saveCredential(payload(), { user: owner, role });
|
||||
const { id: id2 } = await saveCredential(payload(), { user: member, role });
|
||||
|
||||
const response: GetAllResponse = await testServer
|
||||
.authAgentFor(owner)
|
||||
|
@ -45,13 +47,13 @@ describe('GET /credentials', () => {
|
|||
});
|
||||
|
||||
test('only own credentials for member', async () => {
|
||||
const role = await testDb.getCredentialOwnerRole();
|
||||
const role = await getCredentialOwnerRole();
|
||||
|
||||
const firstMember = member;
|
||||
const secondMember = await testDb.createMember();
|
||||
const secondMember = await createMember();
|
||||
|
||||
const c1 = await testDb.saveCredential(payload(), { user: firstMember, role });
|
||||
const c2 = await testDb.saveCredential(payload(), { user: secondMember, role });
|
||||
const c1 = await saveCredential(payload(), { user: firstMember, role });
|
||||
const c2 = await saveCredential(payload(), { user: secondMember, role });
|
||||
|
||||
const response: GetAllResponse = await testServer
|
||||
.authAgentFor(firstMember)
|
||||
|
@ -70,8 +72,8 @@ describe('GET /credentials', () => {
|
|||
|
||||
describe('filter', () => {
|
||||
test('should filter credentials by field: name - full match', async () => {
|
||||
const role = await testDb.getCredentialOwnerRole();
|
||||
const savedCred = await testDb.saveCredential(payload(), { user: owner, role });
|
||||
const role = await getCredentialOwnerRole();
|
||||
const savedCred = await saveCredential(payload(), { user: owner, role });
|
||||
|
||||
const response: GetAllResponse = await testServer
|
||||
.authAgentFor(owner)
|
||||
|
@ -95,8 +97,8 @@ describe('GET /credentials', () => {
|
|||
});
|
||||
|
||||
test('should filter credentials by field: name - partial match', async () => {
|
||||
const role = await testDb.getCredentialOwnerRole();
|
||||
const savedCred = await testDb.saveCredential(payload(), { user: owner, role });
|
||||
const role = await getCredentialOwnerRole();
|
||||
const savedCred = await saveCredential(payload(), { user: owner, role });
|
||||
|
||||
const partialName = savedCred.name.slice(3);
|
||||
|
||||
|
@ -122,9 +124,9 @@ describe('GET /credentials', () => {
|
|||
});
|
||||
|
||||
test('should filter credentials by field: type - full match', async () => {
|
||||
const role = await testDb.getCredentialOwnerRole();
|
||||
const role = await getCredentialOwnerRole();
|
||||
|
||||
const savedCred = await testDb.saveCredential(payload(), { user: owner, role });
|
||||
const savedCred = await saveCredential(payload(), { user: owner, role });
|
||||
|
||||
const response: GetAllResponse = await testServer
|
||||
.authAgentFor(owner)
|
||||
|
@ -148,9 +150,9 @@ describe('GET /credentials', () => {
|
|||
});
|
||||
|
||||
test('should filter credentials by field: type - partial match', async () => {
|
||||
const role = await testDb.getCredentialOwnerRole();
|
||||
const role = await getCredentialOwnerRole();
|
||||
|
||||
const savedCred = await testDb.saveCredential(payload(), { user: owner, role });
|
||||
const savedCred = await saveCredential(payload(), { user: owner, role });
|
||||
|
||||
const partialType = savedCred.type.slice(3);
|
||||
|
||||
|
@ -178,10 +180,10 @@ describe('GET /credentials', () => {
|
|||
|
||||
describe('select', () => {
|
||||
test('should select credential field: id', async () => {
|
||||
const role = await testDb.getCredentialOwnerRole();
|
||||
const role = await getCredentialOwnerRole();
|
||||
|
||||
await testDb.saveCredential(payload(), { user: owner, role });
|
||||
await testDb.saveCredential(payload(), { user: owner, role });
|
||||
await saveCredential(payload(), { user: owner, role });
|
||||
await saveCredential(payload(), { user: owner, role });
|
||||
|
||||
const response: GetAllResponse = await testServer
|
||||
.authAgentFor(owner)
|
||||
|
@ -195,10 +197,10 @@ describe('GET /credentials', () => {
|
|||
});
|
||||
|
||||
test('should select credential field: name', async () => {
|
||||
const role = await testDb.getCredentialOwnerRole();
|
||||
const role = await getCredentialOwnerRole();
|
||||
|
||||
await testDb.saveCredential(payload(), { user: owner, role });
|
||||
await testDb.saveCredential(payload(), { user: owner, role });
|
||||
await saveCredential(payload(), { user: owner, role });
|
||||
await saveCredential(payload(), { user: owner, role });
|
||||
|
||||
const response: GetAllResponse = await testServer
|
||||
.authAgentFor(owner)
|
||||
|
@ -212,10 +214,10 @@ describe('GET /credentials', () => {
|
|||
});
|
||||
|
||||
test('should select credential field: type', async () => {
|
||||
const role = await testDb.getCredentialOwnerRole();
|
||||
const role = await getCredentialOwnerRole();
|
||||
|
||||
await testDb.saveCredential(payload(), { user: owner, role });
|
||||
await testDb.saveCredential(payload(), { user: owner, role });
|
||||
await saveCredential(payload(), { user: owner, role });
|
||||
await saveCredential(payload(), { user: owner, role });
|
||||
|
||||
const response: GetAllResponse = await testServer
|
||||
.authAgentFor(owner)
|
||||
|
@ -231,10 +233,10 @@ describe('GET /credentials', () => {
|
|||
|
||||
describe('take', () => {
|
||||
test('should return n credentials or less, without skip', async () => {
|
||||
const role = await testDb.getCredentialOwnerRole();
|
||||
const role = await getCredentialOwnerRole();
|
||||
|
||||
await testDb.saveCredential(payload(), { user: owner, role });
|
||||
await testDb.saveCredential(payload(), { user: owner, role });
|
||||
await saveCredential(payload(), { user: owner, role });
|
||||
await saveCredential(payload(), { user: owner, role });
|
||||
|
||||
const response = await testServer
|
||||
.authAgentFor(owner)
|
||||
|
@ -258,10 +260,10 @@ describe('GET /credentials', () => {
|
|||
});
|
||||
|
||||
test('should return n credentials or less, with skip', async () => {
|
||||
const role = await testDb.getCredentialOwnerRole();
|
||||
const role = await getCredentialOwnerRole();
|
||||
|
||||
await testDb.saveCredential(payload(), { user: owner, role });
|
||||
await testDb.saveCredential(payload(), { user: owner, role });
|
||||
await saveCredential(payload(), { user: owner, role });
|
||||
await saveCredential(payload(), { user: owner, role });
|
||||
|
||||
const response = await testServer
|
||||
.authAgentFor(owner)
|
||||
|
|
|
@ -7,10 +7,14 @@ import type { Credentials } from '@/requests';
|
|||
import * as UserManagementHelpers from '@/UserManagement/UserManagementHelper';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
import type { User } from '@db/entities/User';
|
||||
|
||||
import { randomCredentialPayload } from './shared/random';
|
||||
import * as testDb from './shared/testDb';
|
||||
import type { SaveCredentialFunction } from './shared/types';
|
||||
import * as utils from './shared/utils/';
|
||||
import { affixRoleToSaveCredential, shareCredentialWithUsers } from './shared/db/credentials';
|
||||
import { getCredentialOwnerRole, getGlobalMemberRole, getGlobalOwnerRole } from './shared/db/roles';
|
||||
import { createManyUsers, createUser, createUserShell } from './shared/db/users';
|
||||
|
||||
const sharingSpy = jest.spyOn(UserManagementHelpers, 'isSharingEnabled').mockReturnValue(true);
|
||||
const testServer = utils.setupTestServer({ endpointGroups: ['credentials'] });
|
||||
|
@ -22,16 +26,16 @@ let authOwnerAgent: SuperAgentTest;
|
|||
let saveCredential: SaveCredentialFunction;
|
||||
|
||||
beforeAll(async () => {
|
||||
const globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||
globalMemberRole = await testDb.getGlobalMemberRole();
|
||||
const credentialOwnerRole = await testDb.getCredentialOwnerRole();
|
||||
const globalOwnerRole = await getGlobalOwnerRole();
|
||||
globalMemberRole = await getGlobalMemberRole();
|
||||
const credentialOwnerRole = await getCredentialOwnerRole();
|
||||
|
||||
owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
member = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
owner = await createUser({ globalRole: globalOwnerRole });
|
||||
member = await createUser({ globalRole: globalMemberRole });
|
||||
|
||||
authOwnerAgent = testServer.authAgentFor(owner);
|
||||
|
||||
saveCredential = testDb.affixRoleToSaveCredential(credentialOwnerRole);
|
||||
saveCredential = affixRoleToSaveCredential(credentialOwnerRole);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
|
@ -75,7 +79,7 @@ describe('router should switch based on flag', () => {
|
|||
// ----------------------------------------
|
||||
describe('GET /credentials', () => {
|
||||
test('should return all creds for owner', async () => {
|
||||
const [member1, member2, member3] = await testDb.createManyUsers(3, {
|
||||
const [member1, member2, member3] = await createManyUsers(3, {
|
||||
globalRole: globalMemberRole,
|
||||
});
|
||||
|
||||
|
@ -83,7 +87,7 @@ describe('GET /credentials', () => {
|
|||
await saveCredential(randomCredentialPayload(), { user: member1 });
|
||||
|
||||
const sharedWith = [member1, member2, member3];
|
||||
await testDb.shareCredentialWithUsers(savedCredential, sharedWith);
|
||||
await shareCredentialWithUsers(savedCredential, sharedWith);
|
||||
|
||||
const response = await authOwnerAgent.get('/credentials');
|
||||
|
||||
|
@ -139,7 +143,7 @@ describe('GET /credentials', () => {
|
|||
});
|
||||
|
||||
test('should return only relevant creds for member', async () => {
|
||||
const [member1, member2] = await testDb.createManyUsers(2, {
|
||||
const [member1, member2] = await createManyUsers(2, {
|
||||
globalRole: globalMemberRole,
|
||||
});
|
||||
|
||||
|
@ -148,7 +152,7 @@ describe('GET /credentials', () => {
|
|||
user: member1,
|
||||
});
|
||||
|
||||
await testDb.shareCredentialWithUsers(savedMemberCredential, [member2]);
|
||||
await shareCredentialWithUsers(savedMemberCredential, [member2]);
|
||||
|
||||
const response = await testServer.authAgentFor(member1).get('/credentials');
|
||||
|
||||
|
@ -215,12 +219,12 @@ describe('GET /credentials/:id', () => {
|
|||
});
|
||||
|
||||
test('should retrieve non-owned cred for owner', async () => {
|
||||
const [member1, member2] = await testDb.createManyUsers(2, {
|
||||
const [member1, member2] = await createManyUsers(2, {
|
||||
globalRole: globalMemberRole,
|
||||
});
|
||||
|
||||
const savedCredential = await saveCredential(randomCredentialPayload(), { user: member1 });
|
||||
await testDb.shareCredentialWithUsers(savedCredential, [member2]);
|
||||
await shareCredentialWithUsers(savedCredential, [member2]);
|
||||
|
||||
const response1 = await authOwnerAgent.get(`/credentials/${savedCredential.id}`);
|
||||
|
||||
|
@ -254,12 +258,12 @@ describe('GET /credentials/:id', () => {
|
|||
});
|
||||
|
||||
test('should retrieve owned cred for member', async () => {
|
||||
const [member1, member2, member3] = await testDb.createManyUsers(3, {
|
||||
const [member1, member2, member3] = await createManyUsers(3, {
|
||||
globalRole: globalMemberRole,
|
||||
});
|
||||
const authMemberAgent = testServer.authAgentFor(member1);
|
||||
const savedCredential = await saveCredential(randomCredentialPayload(), { user: member1 });
|
||||
await testDb.shareCredentialWithUsers(savedCredential, [member2, member3]);
|
||||
await shareCredentialWithUsers(savedCredential, [member2, member3]);
|
||||
|
||||
const firstResponse = await authMemberAgent.get(`/credentials/${savedCredential.id}`);
|
||||
|
||||
|
@ -322,12 +326,12 @@ describe('PUT /credentials/:id/share', () => {
|
|||
test('should share the credential with the provided userIds and unshare it for missing ones', async () => {
|
||||
const savedCredential = await saveCredential(randomCredentialPayload(), { user: owner });
|
||||
|
||||
const [member1, member2, member3, member4, member5] = await testDb.createManyUsers(5, {
|
||||
const [member1, member2, member3, member4, member5] = await createManyUsers(5, {
|
||||
globalRole: globalMemberRole,
|
||||
});
|
||||
const shareWithIds = [member1.id, member2.id, member3.id];
|
||||
|
||||
await testDb.shareCredentialWithUsers(savedCredential, [member4, member5]);
|
||||
await shareCredentialWithUsers(savedCredential, [member4, member5]);
|
||||
|
||||
const response = await authOwnerAgent
|
||||
.put(`/credentials/${savedCredential.id}/share`)
|
||||
|
@ -357,7 +361,7 @@ describe('PUT /credentials/:id/share', () => {
|
|||
});
|
||||
|
||||
test('should share the credential with the provided userIds', async () => {
|
||||
const [member1, member2, member3] = await testDb.createManyUsers(3, {
|
||||
const [member1, member2, member3] = await createManyUsers(3, {
|
||||
globalRole: globalMemberRole,
|
||||
});
|
||||
const memberIds = [member1.id, member2.id, member3.id];
|
||||
|
@ -412,7 +416,7 @@ describe('PUT /credentials/:id/share', () => {
|
|||
});
|
||||
|
||||
test('should ignore pending sharee', async () => {
|
||||
const memberShell = await testDb.createUserShell(globalMemberRole);
|
||||
const memberShell = await createUserShell(globalMemberRole);
|
||||
const savedCredential = await saveCredential(randomCredentialPayload(), { user: owner });
|
||||
|
||||
const response = await authOwnerAgent
|
||||
|
@ -459,11 +463,11 @@ describe('PUT /credentials/:id/share', () => {
|
|||
test('should unshare the credential', async () => {
|
||||
const savedCredential = await saveCredential(randomCredentialPayload(), { user: owner });
|
||||
|
||||
const [member1, member2] = await testDb.createManyUsers(2, {
|
||||
const [member1, member2] = await createManyUsers(2, {
|
||||
globalRole: globalMemberRole,
|
||||
});
|
||||
|
||||
await testDb.shareCredentialWithUsers(savedCredential, [member1, member2]);
|
||||
await shareCredentialWithUsers(savedCredential, [member1, member2]);
|
||||
|
||||
const response = await authOwnerAgent
|
||||
.put(`/credentials/${savedCredential.id}/share`)
|
||||
|
|
|
@ -6,10 +6,14 @@ import * as UserManagementHelpers from '@/UserManagement/UserManagementHelper';
|
|||
import type { Credentials } from '@/requests';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
import type { User } from '@db/entities/User';
|
||||
|
||||
import { randomCredentialPayload, randomName, randomString } from './shared/random';
|
||||
import * as testDb from './shared/testDb';
|
||||
import type { SaveCredentialFunction } from './shared/types';
|
||||
import * as utils from './shared/utils/';
|
||||
import { affixRoleToSaveCredential } from './shared/db/credentials';
|
||||
import { getCredentialOwnerRole, getGlobalMemberRole, getGlobalOwnerRole } from './shared/db/roles';
|
||||
import { createManyUsers, createUser } from './shared/db/users';
|
||||
|
||||
// mock that credentialsSharing is not enabled
|
||||
jest.spyOn(UserManagementHelpers, 'isSharingEnabled').mockReturnValue(false);
|
||||
|
@ -24,14 +28,14 @@ let authMemberAgent: SuperAgentTest;
|
|||
let saveCredential: SaveCredentialFunction;
|
||||
|
||||
beforeAll(async () => {
|
||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||
globalMemberRole = await testDb.getGlobalMemberRole();
|
||||
const credentialOwnerRole = await testDb.getCredentialOwnerRole();
|
||||
globalOwnerRole = await getGlobalOwnerRole();
|
||||
globalMemberRole = await getGlobalMemberRole();
|
||||
const credentialOwnerRole = await getCredentialOwnerRole();
|
||||
|
||||
owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
member = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
owner = await createUser({ globalRole: globalOwnerRole });
|
||||
member = await createUser({ globalRole: globalMemberRole });
|
||||
|
||||
saveCredential = testDb.affixRoleToSaveCredential(credentialOwnerRole);
|
||||
saveCredential = affixRoleToSaveCredential(credentialOwnerRole);
|
||||
|
||||
authOwnerAgent = testServer.authAgentFor(owner);
|
||||
authMemberAgent = testServer.authAgentFor(member);
|
||||
|
@ -65,7 +69,7 @@ describe('GET /credentials', () => {
|
|||
});
|
||||
|
||||
test('should return only own creds for member', async () => {
|
||||
const [member1, member2] = await testDb.createManyUsers(2, {
|
||||
const [member1, member2] = await createManyUsers(2, {
|
||||
globalRole: globalMemberRole,
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import type { SuperAgentTest } from 'supertest';
|
||||
import { SOURCE_CONTROL_API_ROOT } from '@/environments/sourceControl/constants';
|
||||
import * as testDb from '../shared/testDb';
|
||||
import * as utils from '../shared/utils/';
|
||||
import type { User } from '@db/entities/User';
|
||||
import * as UserManagementHelpers from '@/UserManagement/UserManagementHelper';
|
||||
|
@ -10,6 +9,8 @@ import { License } from '@/License';
|
|||
import { SourceControlPreferencesService } from '@/environments/sourceControl/sourceControlPreferences.service.ee';
|
||||
import { SourceControlService } from '@/environments/sourceControl/sourceControl.service.ee';
|
||||
import type { SourceControlledFile } from '@/environments/sourceControl/types/sourceControlledFile';
|
||||
import { getGlobalMemberRole, getGlobalOwnerRole } from '../shared/db/roles';
|
||||
import { createUser } from '../shared/db/users';
|
||||
|
||||
let authOwnerAgent: SuperAgentTest;
|
||||
let authMemberAgent: SuperAgentTest;
|
||||
|
@ -24,10 +25,10 @@ const testServer = utils.setupTestServer({
|
|||
});
|
||||
|
||||
beforeAll(async () => {
|
||||
const globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||
const globalMemberRole = await testDb.getGlobalMemberRole();
|
||||
owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
member = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
const globalOwnerRole = await getGlobalOwnerRole();
|
||||
const globalMemberRole = await getGlobalMemberRole();
|
||||
owner = await createUser({ globalRole: globalOwnerRole });
|
||||
member = await createUser({ globalRole: globalMemberRole });
|
||||
authOwnerAgent = testServer.authAgentFor(owner);
|
||||
authMemberAgent = testServer.authAgentFor(member);
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@ import axios from 'axios';
|
|||
import syslog from 'syslog-client';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import type { SuperAgentTest } from 'supertest';
|
||||
import * as utils from './shared/utils';
|
||||
import * as testDb from './shared/testDb';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type {
|
||||
|
@ -27,6 +25,10 @@ import type { EventNamesTypes } from '@/eventbus/EventMessageClasses';
|
|||
import { EventMessageWorkflow } from '@/eventbus/EventMessageClasses/EventMessageWorkflow';
|
||||
import { EventMessageNode } from '@/eventbus/EventMessageClasses/EventMessageNode';
|
||||
|
||||
import * as utils from './shared/utils';
|
||||
import { getGlobalOwnerRole } from './shared/db/roles';
|
||||
import { createUser } from './shared/db/users';
|
||||
|
||||
jest.unmock('@/eventbus/MessageEventBus/MessageEventBus');
|
||||
jest.mock('axios');
|
||||
const mockedAxios = axios as jest.Mocked<typeof axios>;
|
||||
|
@ -83,8 +85,8 @@ const testServer = utils.setupTestServer({
|
|||
});
|
||||
|
||||
beforeAll(async () => {
|
||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||
owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
globalOwnerRole = await getGlobalOwnerRole();
|
||||
owner = await createUser({ globalRole: globalOwnerRole });
|
||||
authOwnerAgent = testServer.authAgentFor(owner);
|
||||
|
||||
mockedSyslog.createClient.mockImplementation(() => new syslog.Client());
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import type { SuperAgentTest } from 'supertest';
|
||||
import * as utils from './shared/utils/';
|
||||
import * as testDb from './shared/testDb';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { getGlobalOwnerRole } from './shared/db/roles';
|
||||
import { createUser } from './shared/db/users';
|
||||
|
||||
/**
|
||||
* NOTE: due to issues with mocking the MessageEventBus in multiple tests running in parallel,
|
||||
|
@ -20,8 +21,8 @@ const testServer = utils.setupTestServer({
|
|||
});
|
||||
|
||||
beforeAll(async () => {
|
||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||
owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
globalOwnerRole = await getGlobalOwnerRole();
|
||||
owner = await createUser({ globalRole: globalOwnerRole });
|
||||
authOwnerAgent = testServer.authAgentFor(owner);
|
||||
});
|
||||
|
||||
|
|
|
@ -1,19 +1,22 @@
|
|||
import type { User } from '@/databases/entities/User';
|
||||
import { createSuccessfulExecution, getAllExecutions } from './shared/db/executions';
|
||||
import { createOwner } from './shared/db/users';
|
||||
import { createWorkflow } from './shared/db/workflows';
|
||||
import * as testDb from './shared/testDb';
|
||||
import { setupTestServer } from './shared/utils';
|
||||
import type { User } from '@/databases/entities/User';
|
||||
|
||||
let testServer = setupTestServer({ endpointGroups: ['executions'] });
|
||||
|
||||
let owner: User;
|
||||
|
||||
const saveExecution = async ({ belongingTo }: { belongingTo: User }) => {
|
||||
const workflow = await testDb.createWorkflow({}, belongingTo);
|
||||
return testDb.createSuccessfulExecution(workflow);
|
||||
const workflow = await createWorkflow({}, belongingTo);
|
||||
return createSuccessfulExecution(workflow);
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
await testDb.truncate(['Execution', 'Workflow', 'SharedWorkflow']);
|
||||
owner = await testDb.createOwner();
|
||||
owner = await createOwner();
|
||||
});
|
||||
|
||||
describe('POST /executions/delete', () => {
|
||||
|
@ -32,7 +35,7 @@ describe('POST /executions/delete', () => {
|
|||
.send({ ids: [execution.id] })
|
||||
.expect(200);
|
||||
|
||||
const executions = await testDb.getAllExecutions();
|
||||
const executions = await getAllExecutions();
|
||||
|
||||
expect(executions).toHaveLength(0);
|
||||
});
|
||||
|
|
|
@ -19,6 +19,8 @@ import * as testDb from './../shared/testDb';
|
|||
import * as utils from '../shared/utils/';
|
||||
import Container from 'typedi';
|
||||
import { Cipher } from 'n8n-core';
|
||||
import { getGlobalMemberRole, getGlobalOwnerRole } from '../shared/db/roles';
|
||||
import { createLdapUser, createUser, getAllUsers, getLdapIdentities } from '../shared/db/users';
|
||||
|
||||
jest.mock('@/telemetry');
|
||||
|
||||
|
@ -46,11 +48,14 @@ const testServer = utils.setupTestServer({
|
|||
});
|
||||
|
||||
beforeAll(async () => {
|
||||
const [globalOwnerRole, fetchedGlobalMemberRole] = await testDb.getAllRoles();
|
||||
const [globalOwnerRole, fetchedGlobalMemberRole] = await Promise.all([
|
||||
getGlobalOwnerRole(),
|
||||
getGlobalMemberRole(),
|
||||
]);
|
||||
|
||||
globalMemberRole = fetchedGlobalMemberRole;
|
||||
|
||||
owner = await testDb.createUser({ globalRole: globalOwnerRole, password: 'password' });
|
||||
owner = await createUser({ globalRole: globalOwnerRole, password: 'password' });
|
||||
authOwnerAgent = testServer.authAgentFor(owner);
|
||||
|
||||
defaultLdapConfig.bindingAdminPassword = Container.get(Cipher).encrypt(
|
||||
|
@ -90,7 +95,7 @@ const createLdapConfig = async (attributes: Partial<LdapConfig> = {}): Promise<L
|
|||
};
|
||||
|
||||
test('Member role should not be able to access ldap routes', async () => {
|
||||
const member = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
const member = await createUser({ globalRole: globalMemberRole });
|
||||
const authAgent = testServer.authAgentFor(member);
|
||||
await authAgent.get('/ldap/config').expect(403);
|
||||
await authAgent.put('/ldap/config').expect(403);
|
||||
|
@ -162,7 +167,7 @@ describe('PUT /ldap/config', () => {
|
|||
const ldapConfig = await createLdapConfig();
|
||||
LdapManager.updateConfig(ldapConfig);
|
||||
|
||||
const member = await testDb.createLdapUser({ globalRole: globalMemberRole }, uniqueId());
|
||||
const member = await createLdapUser({ globalRole: globalMemberRole }, uniqueId());
|
||||
|
||||
const configuration = ldapConfig;
|
||||
|
||||
|
@ -170,7 +175,7 @@ describe('PUT /ldap/config', () => {
|
|||
await authOwnerAgent.put('/ldap/config').send({ ...configuration, loginEnabled: false });
|
||||
|
||||
const emailUser = await Db.collections.User.findOneByOrFail({ id: member.id });
|
||||
const localLdapIdentities = await testDb.getLdapIdentities();
|
||||
const localLdapIdentities = await getLdapIdentities();
|
||||
|
||||
expect(getCurrentAuthenticationMethod()).toBe('email');
|
||||
expect(emailUser.email).toBe(member.email);
|
||||
|
@ -272,7 +277,7 @@ describe('POST /ldap/sync', () => {
|
|||
const ldapUserEmail = randomEmail();
|
||||
const ldapUserId = uniqueId();
|
||||
|
||||
const member = await testDb.createLdapUser(
|
||||
const member = await createLdapUser(
|
||||
{ globalRole: globalMemberRole, email: ldapUserEmail },
|
||||
ldapUserId,
|
||||
);
|
||||
|
@ -290,7 +295,7 @@ describe('POST /ldap/sync', () => {
|
|||
expect(synchronization.updated).toBe(1);
|
||||
|
||||
// Make sure the changes in the "LDAP server" were not persisted in the database
|
||||
const localLdapIdentities = await testDb.getLdapIdentities();
|
||||
const localLdapIdentities = await getLdapIdentities();
|
||||
const localLdapUsers = localLdapIdentities.map(({ user }) => user);
|
||||
expect(localLdapUsers.length).toBe(1);
|
||||
expect(localLdapUsers[0].id).toBe(member.id);
|
||||
|
@ -301,7 +306,7 @@ describe('POST /ldap/sync', () => {
|
|||
const ldapUserEmail = randomEmail();
|
||||
const ldapUserId = uniqueId();
|
||||
|
||||
const member = await testDb.createLdapUser(
|
||||
const member = await createLdapUser(
|
||||
{ globalRole: globalMemberRole, email: ldapUserEmail },
|
||||
ldapUserId,
|
||||
);
|
||||
|
@ -311,7 +316,7 @@ describe('POST /ldap/sync', () => {
|
|||
expect(synchronization.disabled).toBe(1);
|
||||
|
||||
// Make sure the changes in the "LDAP server" were not persisted in the database
|
||||
const localLdapIdentities = await testDb.getLdapIdentities();
|
||||
const localLdapIdentities = await getLdapIdentities();
|
||||
const localLdapUsers = localLdapIdentities.map(({ user }) => user);
|
||||
expect(localLdapUsers.length).toBe(1);
|
||||
expect(localLdapUsers[0].id).toBe(member.id);
|
||||
|
@ -355,7 +360,7 @@ describe('POST /ldap/sync', () => {
|
|||
expect(synchronization.created).toBe(1);
|
||||
|
||||
// Make sure the changes in the "LDAP server" were persisted in the database
|
||||
const allUsers = await testDb.getAllUsers();
|
||||
const allUsers = await getAllUsers();
|
||||
expect(allUsers.length).toBe(2);
|
||||
|
||||
const ownerUser = allUsers.find((u) => u.email === owner.email)!;
|
||||
|
@ -366,7 +371,7 @@ describe('POST /ldap/sync', () => {
|
|||
expect(memberUser.lastName).toBe(ldapUser.sn);
|
||||
expect(memberUser.firstName).toBe(ldapUser.givenName);
|
||||
|
||||
const authIdentities = await testDb.getLdapIdentities();
|
||||
const authIdentities = await getLdapIdentities();
|
||||
expect(authIdentities.length).toBe(1);
|
||||
expect(authIdentities[0].providerId).toBe(ldapUser.uid);
|
||||
expect(authIdentities[0].providerType).toBe('ldap');
|
||||
|
@ -381,7 +386,7 @@ describe('POST /ldap/sync', () => {
|
|||
uid: uniqueId(),
|
||||
};
|
||||
|
||||
await testDb.createLdapUser(
|
||||
await createLdapUser(
|
||||
{
|
||||
globalRole: globalMemberRole,
|
||||
email: ldapUser.mail,
|
||||
|
@ -395,7 +400,7 @@ describe('POST /ldap/sync', () => {
|
|||
expect(synchronization.updated).toBe(1);
|
||||
|
||||
// Make sure the changes in the "LDAP server" were persisted in the database
|
||||
const localLdapIdentities = await testDb.getLdapIdentities();
|
||||
const localLdapIdentities = await getLdapIdentities();
|
||||
const localLdapUsers = localLdapIdentities.map(({ user }) => user);
|
||||
|
||||
expect(localLdapUsers.length).toBe(1);
|
||||
|
@ -414,7 +419,7 @@ describe('POST /ldap/sync', () => {
|
|||
uid: uniqueId(),
|
||||
};
|
||||
|
||||
await testDb.createLdapUser(
|
||||
await createLdapUser(
|
||||
{
|
||||
globalRole: globalMemberRole,
|
||||
email: ldapUser.mail,
|
||||
|
@ -428,7 +433,7 @@ describe('POST /ldap/sync', () => {
|
|||
expect(synchronization.disabled).toBe(1);
|
||||
|
||||
// Make sure the changes in the "LDAP server" were persisted in the database
|
||||
const allUsers = await testDb.getAllUsers();
|
||||
const allUsers = await getAllUsers();
|
||||
expect(allUsers.length).toBe(2);
|
||||
|
||||
const ownerUser = allUsers.find((u) => u.email === owner.email)!;
|
||||
|
@ -440,12 +445,12 @@ describe('POST /ldap/sync', () => {
|
|||
expect(memberUser.firstName).toBe(ldapUser.givenName);
|
||||
expect(memberUser.disabled).toBe(true);
|
||||
|
||||
const authIdentities = await testDb.getLdapIdentities();
|
||||
const authIdentities = await getLdapIdentities();
|
||||
expect(authIdentities.length).toBe(0);
|
||||
});
|
||||
|
||||
test('should remove user instance access once the user is disabled during synchronization', async () => {
|
||||
const member = await testDb.createLdapUser({ globalRole: globalMemberRole }, uniqueId());
|
||||
const member = await createLdapUser({ globalRole: globalMemberRole }, uniqueId());
|
||||
|
||||
jest.spyOn(LdapService.prototype, 'searchWithAdminBinding').mockResolvedValue([]);
|
||||
|
||||
|
@ -499,7 +504,7 @@ describe('POST /login', () => {
|
|||
expect(response.headers['set-cookie'][0] as string).toContain('n8n-auth=');
|
||||
|
||||
// Make sure the changes in the "LDAP server" were persisted in the database
|
||||
const localLdapIdentities = await testDb.getLdapIdentities();
|
||||
const localLdapIdentities = await getLdapIdentities();
|
||||
const localLdapUsers = localLdapIdentities.map(({ user }) => user);
|
||||
|
||||
expect(localLdapUsers.length).toBe(1);
|
||||
|
@ -530,7 +535,7 @@ describe('POST /login', () => {
|
|||
uid: uniqueId(),
|
||||
};
|
||||
|
||||
await testDb.createLdapUser(
|
||||
await createLdapUser(
|
||||
{
|
||||
globalRole: globalMemberRole,
|
||||
email: ldapUser.mail,
|
||||
|
@ -565,7 +570,7 @@ describe('POST /login', () => {
|
|||
uid: uniqueId(),
|
||||
};
|
||||
|
||||
await testDb.createUser({
|
||||
await createUser({
|
||||
globalRole: globalMemberRole,
|
||||
email: ldapUser.mail,
|
||||
firstName: ldapUser.givenName,
|
||||
|
@ -581,7 +586,7 @@ describe('Instance owner should able to delete LDAP users', () => {
|
|||
const ldapConfig = await createLdapConfig();
|
||||
LdapManager.updateConfig(ldapConfig);
|
||||
|
||||
const member = await testDb.createLdapUser({ globalRole: globalMemberRole }, uniqueId());
|
||||
const member = await createLdapUser({ globalRole: globalMemberRole }, uniqueId());
|
||||
|
||||
await authOwnerAgent.post(`/users/${member.id}`);
|
||||
});
|
||||
|
@ -590,7 +595,7 @@ describe('Instance owner should able to delete LDAP users', () => {
|
|||
const ldapConfig = await createLdapConfig();
|
||||
LdapManager.updateConfig(ldapConfig);
|
||||
|
||||
const member = await testDb.createLdapUser({ globalRole: globalMemberRole }, uniqueId());
|
||||
const member = await createLdapUser({ globalRole: globalMemberRole }, uniqueId());
|
||||
|
||||
// delete the LDAP member and transfer its workflows/credentials to instance owner
|
||||
await authOwnerAgent.post(`/users/${member.id}?transferId=${owner.id}`);
|
||||
|
|
|
@ -5,6 +5,8 @@ import type { ILicensePostResponse, ILicenseReadResponse } from '@/Interfaces';
|
|||
import { License } from '@/License';
|
||||
import * as testDb from './shared/testDb';
|
||||
import * as utils from './shared/utils/';
|
||||
import { getGlobalMemberRole, getGlobalOwnerRole } from './shared/db/roles';
|
||||
import { createUserShell } from './shared/db/users';
|
||||
|
||||
const MOCK_SERVER_URL = 'https://server.com/v1';
|
||||
const MOCK_RENEW_OFFSET = 259200;
|
||||
|
@ -17,10 +19,10 @@ let authMemberAgent: SuperAgentTest;
|
|||
const testServer = utils.setupTestServer({ endpointGroups: ['license'] });
|
||||
|
||||
beforeAll(async () => {
|
||||
const globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||
const globalMemberRole = await testDb.getGlobalMemberRole();
|
||||
owner = await testDb.createUserShell(globalOwnerRole);
|
||||
member = await testDb.createUserShell(globalMemberRole);
|
||||
const globalOwnerRole = await getGlobalOwnerRole();
|
||||
const globalMemberRole = await getGlobalMemberRole();
|
||||
owner = await createUserShell(globalOwnerRole);
|
||||
member = await createUserShell(globalMemberRole);
|
||||
|
||||
authOwnerAgent = testServer.authAgentFor(owner);
|
||||
authMemberAgent = testServer.authAgentFor(member);
|
||||
|
|
|
@ -14,6 +14,8 @@ import {
|
|||
} from './shared/random';
|
||||
import * as testDb from './shared/testDb';
|
||||
import * as utils from './shared/utils/';
|
||||
import { getGlobalMemberRole, getGlobalOwnerRole } from './shared/db/roles';
|
||||
import { addApiKey, createUser, createUserShell } from './shared/db/users';
|
||||
|
||||
const testServer = utils.setupTestServer({ endpointGroups: ['me'] });
|
||||
|
||||
|
@ -21,8 +23,8 @@ let globalOwnerRole: Role;
|
|||
let globalMemberRole: Role;
|
||||
|
||||
beforeAll(async () => {
|
||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||
globalMemberRole = await testDb.getGlobalMemberRole();
|
||||
globalOwnerRole = await getGlobalOwnerRole();
|
||||
globalMemberRole = await getGlobalMemberRole();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
|
@ -34,8 +36,8 @@ describe('Owner shell', () => {
|
|||
let authOwnerShellAgent: SuperAgentTest;
|
||||
|
||||
beforeEach(async () => {
|
||||
ownerShell = await testDb.createUserShell(globalOwnerRole);
|
||||
await testDb.addApiKey(ownerShell);
|
||||
ownerShell = await createUserShell(globalOwnerRole);
|
||||
await addApiKey(ownerShell);
|
||||
authOwnerShellAgent = testServer.authAgentFor(ownerShell);
|
||||
});
|
||||
|
||||
|
@ -172,7 +174,7 @@ describe('Member', () => {
|
|||
let authMemberAgent: SuperAgentTest;
|
||||
|
||||
beforeEach(async () => {
|
||||
member = await testDb.createUser({
|
||||
member = await createUser({
|
||||
password: memberPassword,
|
||||
globalRole: globalMemberRole,
|
||||
apiKey: randomApiKey(),
|
||||
|
@ -314,7 +316,7 @@ describe('Owner', () => {
|
|||
});
|
||||
|
||||
test('PATCH /me should succeed with valid inputs', async () => {
|
||||
const owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
const owner = await createUser({ globalRole: globalOwnerRole });
|
||||
const authOwnerAgent = testServer.authAgentFor(owner);
|
||||
|
||||
for (const validPayload of VALID_PATCH_ME_PAYLOADS) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import { UserService } from '@/services/user.service';
|
|||
import { randomDigit, randomString, randomValidPassword, uniqueId } from '../shared/random';
|
||||
import * as testDb from '../shared/testDb';
|
||||
import * as utils from '../shared/utils';
|
||||
import { createUser, createUserWithMfaEnabled } from '../shared/db/users';
|
||||
|
||||
jest.mock('@/telemetry');
|
||||
|
||||
|
@ -22,7 +23,7 @@ const testServer = utils.setupTestServer({
|
|||
beforeEach(async () => {
|
||||
await testDb.truncate(['User']);
|
||||
|
||||
owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
owner = await createUser({ globalRole: globalOwnerRole });
|
||||
|
||||
config.set('userManagement.disabled', false);
|
||||
});
|
||||
|
@ -174,7 +175,7 @@ describe('Enable MFA setup', () => {
|
|||
|
||||
describe('Disable MFA setup', () => {
|
||||
test('POST /disable should disable login with MFA', async () => {
|
||||
const { user } = await testDb.createUserWithMfaEnabled();
|
||||
const { user } = await createUserWithMfaEnabled();
|
||||
|
||||
const response = await testServer.authAgentFor(user).delete('/mfa/disable');
|
||||
|
||||
|
@ -193,7 +194,7 @@ describe('Disable MFA setup', () => {
|
|||
|
||||
describe('Change password with MFA enabled', () => {
|
||||
test('PATCH /me/password should fail due to missing MFA token', async () => {
|
||||
const { user, rawPassword } = await testDb.createUserWithMfaEnabled();
|
||||
const { user, rawPassword } = await createUserWithMfaEnabled();
|
||||
|
||||
const newPassword = randomPassword();
|
||||
|
||||
|
@ -206,7 +207,7 @@ describe('Change password with MFA enabled', () => {
|
|||
});
|
||||
|
||||
test('POST /change-password should fail due to missing MFA token', async () => {
|
||||
await testDb.createUserWithMfaEnabled();
|
||||
await createUserWithMfaEnabled();
|
||||
|
||||
const newPassword = randomValidPassword();
|
||||
|
||||
|
@ -220,7 +221,7 @@ describe('Change password with MFA enabled', () => {
|
|||
});
|
||||
|
||||
test('POST /change-password should fail due to invalid MFA token', async () => {
|
||||
await testDb.createUserWithMfaEnabled();
|
||||
await createUserWithMfaEnabled();
|
||||
|
||||
const newPassword = randomValidPassword();
|
||||
|
||||
|
@ -236,7 +237,7 @@ describe('Change password with MFA enabled', () => {
|
|||
});
|
||||
|
||||
test('POST /change-password should update password', async () => {
|
||||
const { user, rawSecret } = await testDb.createUserWithMfaEnabled();
|
||||
const { user, rawSecret } = await createUserWithMfaEnabled();
|
||||
|
||||
const newPassword = randomValidPassword();
|
||||
|
||||
|
@ -272,7 +273,7 @@ describe('Login', () => {
|
|||
test('POST /login with email/password should succeed when mfa is disabled', async () => {
|
||||
const password = randomPassword();
|
||||
|
||||
const user = await testDb.createUser({ password });
|
||||
const user = await createUser({ password });
|
||||
|
||||
const response = await testServer.authlessAgent
|
||||
.post('/login')
|
||||
|
@ -303,7 +304,7 @@ describe('Login', () => {
|
|||
});
|
||||
|
||||
test('POST /login with email/password should fail when mfa is enabled', async () => {
|
||||
const { user, rawPassword } = await testDb.createUserWithMfaEnabled();
|
||||
const { user, rawPassword } = await createUserWithMfaEnabled();
|
||||
|
||||
const response = await testServer.authlessAgent
|
||||
.post('/login')
|
||||
|
@ -314,7 +315,7 @@ describe('Login', () => {
|
|||
|
||||
describe('Login with MFA token', () => {
|
||||
test('POST /login should fail due to invalid MFA token', async () => {
|
||||
const { user, rawPassword } = await testDb.createUserWithMfaEnabled();
|
||||
const { user, rawPassword } = await createUserWithMfaEnabled();
|
||||
|
||||
const response = await testServer.authlessAgent
|
||||
.post('/login')
|
||||
|
@ -324,7 +325,7 @@ describe('Login', () => {
|
|||
});
|
||||
|
||||
test('POST /login should fail due two MFA step needed', async () => {
|
||||
const { user, rawPassword } = await testDb.createUserWithMfaEnabled();
|
||||
const { user, rawPassword } = await createUserWithMfaEnabled();
|
||||
|
||||
const response = await testServer.authlessAgent
|
||||
.post('/login')
|
||||
|
@ -335,7 +336,7 @@ describe('Login', () => {
|
|||
});
|
||||
|
||||
test('POST /login should succeed with MFA token', async () => {
|
||||
const { user, rawSecret, rawPassword } = await testDb.createUserWithMfaEnabled();
|
||||
const { user, rawSecret, rawPassword } = await createUserWithMfaEnabled();
|
||||
|
||||
const token = new TOTPService().generateTOTP(rawSecret);
|
||||
|
||||
|
@ -352,7 +353,7 @@ describe('Login', () => {
|
|||
|
||||
describe('Login with recovery code', () => {
|
||||
test('POST /login should fail due to invalid MFA recovery code', async () => {
|
||||
const { user, rawPassword } = await testDb.createUserWithMfaEnabled();
|
||||
const { user, rawPassword } = await createUserWithMfaEnabled();
|
||||
|
||||
const response = await testServer.authlessAgent
|
||||
.post('/login')
|
||||
|
@ -362,7 +363,7 @@ describe('Login', () => {
|
|||
});
|
||||
|
||||
test('POST /login should succeed with MFA recovery code', async () => {
|
||||
const { user, rawPassword, rawRecoveryCodes } = await testDb.createUserWithMfaEnabled();
|
||||
const { user, rawPassword, rawRecoveryCodes } = await createUserWithMfaEnabled();
|
||||
|
||||
const response = await testServer.authlessAgent
|
||||
.post('/login')
|
||||
|
@ -385,7 +386,7 @@ describe('Login', () => {
|
|||
});
|
||||
|
||||
test('POST /login with MFA recovery code should update hasRecoveryCodesLeft property', async () => {
|
||||
const { user, rawPassword, rawRecoveryCodes } = await testDb.createUserWithMfaEnabled({
|
||||
const { user, rawPassword, rawRecoveryCodes } = await createUserWithMfaEnabled({
|
||||
numberOfRecoveryCodes: 1,
|
||||
});
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ import {
|
|||
} from './shared/random';
|
||||
import * as testDb from './shared/testDb';
|
||||
import * as utils from './shared/utils/';
|
||||
import { getGlobalOwnerRole } from './shared/db/roles';
|
||||
import { createUserShell } from './shared/db/users';
|
||||
|
||||
const testServer = utils.setupTestServer({ endpointGroups: ['owner'] });
|
||||
|
||||
|
@ -21,11 +23,11 @@ let ownerShell: User;
|
|||
let authOwnerShellAgent: SuperAgentTest;
|
||||
|
||||
beforeAll(async () => {
|
||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||
globalOwnerRole = await getGlobalOwnerRole();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
ownerShell = await testDb.createUserShell(globalOwnerRole);
|
||||
ownerShell = await createUserShell(globalOwnerRole);
|
||||
authOwnerShellAgent = testServer.authAgentFor(ownerShell);
|
||||
config.set('userManagement.isInstanceOwnerSetUp', false);
|
||||
});
|
||||
|
|
|
@ -23,6 +23,8 @@ import {
|
|||
randomValidPassword,
|
||||
} from './shared/random';
|
||||
import * as testDb from './shared/testDb';
|
||||
import { getGlobalMemberRole, getGlobalOwnerRole } from './shared/db/roles';
|
||||
import { createUser } from './shared/db/users';
|
||||
|
||||
config.set('userManagement.jwtSecret', randomString(5, 10));
|
||||
|
||||
|
@ -38,14 +40,14 @@ const jwtService = Container.get(JwtService);
|
|||
let userService: UserService;
|
||||
|
||||
beforeAll(async () => {
|
||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||
globalMemberRole = await testDb.getGlobalMemberRole();
|
||||
globalOwnerRole = await getGlobalOwnerRole();
|
||||
globalMemberRole = await getGlobalMemberRole();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await testDb.truncate(['User']);
|
||||
owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
member = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
owner = await createUser({ globalRole: globalOwnerRole });
|
||||
member = await createUser({ globalRole: globalMemberRole });
|
||||
externalHooks.run.mockReset();
|
||||
jest.replaceProperty(mailer, 'isEmailSetUp', true);
|
||||
userService = Container.get(UserService);
|
||||
|
@ -53,7 +55,7 @@ beforeEach(async () => {
|
|||
|
||||
describe('POST /forgot-password', () => {
|
||||
test('should send password reset email', async () => {
|
||||
const member = await testDb.createUser({
|
||||
const member = await createUser({
|
||||
email: 'test@test.com',
|
||||
globalRole: globalMemberRole,
|
||||
});
|
||||
|
@ -79,7 +81,7 @@ describe('POST /forgot-password', () => {
|
|||
|
||||
test('should fail if SAML is authentication method', async () => {
|
||||
await setCurrentAuthenticationMethod('saml');
|
||||
const member = await testDb.createUser({
|
||||
const member = await createUser({
|
||||
email: 'test@test.com',
|
||||
globalRole: globalMemberRole,
|
||||
});
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
import config from '@/config';
|
||||
import * as Db from '@/Db';
|
||||
import { BinaryDataService } from 'n8n-core';
|
||||
import type { ExecutionStatus } from 'n8n-workflow';
|
||||
|
||||
import * as testDb from './shared/testDb';
|
||||
import type { ExecutionStatus } from 'n8n-workflow';
|
||||
import type { ExecutionEntity } from '@/databases/entities/ExecutionEntity';
|
||||
import type { ExecutionEntity } from '@db/entities/ExecutionEntity';
|
||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import { TIME } from '@/constants';
|
||||
import { PruningService } from '@/services/pruning.service';
|
||||
import { BinaryDataService } from 'n8n-core';
|
||||
import { Logger } from '@/Logger';
|
||||
import { mockInstance } from './shared/utils';
|
||||
import { createWorkflow } from './shared/db/workflows';
|
||||
import { createExecution, createSuccessfulExecution } from './shared/db/executions';
|
||||
|
||||
describe('softDeleteOnPruningCycle()', () => {
|
||||
let pruningService: PruningService;
|
||||
|
||||
const now = new Date();
|
||||
const yesterday = new Date(Date.now() - TIME.DAY);
|
||||
let workflow: Awaited<ReturnType<typeof testDb.createWorkflow>>;
|
||||
let workflow: WorkflowEntity;
|
||||
|
||||
beforeAll(async () => {
|
||||
await testDb.init();
|
||||
|
@ -26,7 +29,7 @@ describe('softDeleteOnPruningCycle()', () => {
|
|||
mockInstance(BinaryDataService),
|
||||
);
|
||||
|
||||
workflow = await testDb.createWorkflow();
|
||||
workflow = await createWorkflow();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
|
@ -56,9 +59,9 @@ describe('softDeleteOnPruningCycle()', () => {
|
|||
|
||||
test('should mark as deleted based on EXECUTIONS_DATA_PRUNE_MAX_COUNT', async () => {
|
||||
const executions = [
|
||||
await testDb.createSuccessfulExecution(workflow),
|
||||
await testDb.createSuccessfulExecution(workflow),
|
||||
await testDb.createSuccessfulExecution(workflow),
|
||||
await createSuccessfulExecution(workflow),
|
||||
await createSuccessfulExecution(workflow),
|
||||
await createSuccessfulExecution(workflow),
|
||||
];
|
||||
|
||||
await pruningService.softDeleteOnPruningCycle();
|
||||
|
@ -73,11 +76,11 @@ describe('softDeleteOnPruningCycle()', () => {
|
|||
|
||||
test('should not re-mark already marked executions', async () => {
|
||||
const executions = [
|
||||
await testDb.createExecution(
|
||||
await createExecution(
|
||||
{ status: 'success', finished: true, startedAt: now, stoppedAt: now, deletedAt: now },
|
||||
workflow,
|
||||
),
|
||||
await testDb.createSuccessfulExecution(workflow),
|
||||
await createSuccessfulExecution(workflow),
|
||||
];
|
||||
|
||||
await pruningService.softDeleteOnPruningCycle();
|
||||
|
@ -98,8 +101,8 @@ describe('softDeleteOnPruningCycle()', () => {
|
|||
['success', { finished: true, startedAt: now, stoppedAt: now }],
|
||||
])('should prune %s executions', async (status, attributes) => {
|
||||
const executions = [
|
||||
await testDb.createExecution({ status, ...attributes }, workflow),
|
||||
await testDb.createSuccessfulExecution(workflow),
|
||||
await createExecution({ status, ...attributes }, workflow),
|
||||
await createSuccessfulExecution(workflow),
|
||||
];
|
||||
|
||||
await pruningService.softDeleteOnPruningCycle();
|
||||
|
@ -117,8 +120,8 @@ describe('softDeleteOnPruningCycle()', () => {
|
|||
['waiting', { startedAt: now, stoppedAt: now, waitTill: now }],
|
||||
])('should not prune %s executions', async (status, attributes) => {
|
||||
const executions = [
|
||||
await testDb.createExecution({ status, ...attributes }, workflow),
|
||||
await testDb.createSuccessfulExecution(workflow),
|
||||
await createExecution({ status, ...attributes }, workflow),
|
||||
await createSuccessfulExecution(workflow),
|
||||
];
|
||||
|
||||
await pruningService.softDeleteOnPruningCycle();
|
||||
|
@ -139,11 +142,11 @@ describe('softDeleteOnPruningCycle()', () => {
|
|||
|
||||
test('should mark as deleted based on EXECUTIONS_DATA_MAX_AGE', async () => {
|
||||
const executions = [
|
||||
await testDb.createExecution(
|
||||
await createExecution(
|
||||
{ finished: true, startedAt: yesterday, stoppedAt: yesterday, status: 'success' },
|
||||
workflow,
|
||||
),
|
||||
await testDb.createExecution(
|
||||
await createExecution(
|
||||
{ finished: true, startedAt: now, stoppedAt: now, status: 'success' },
|
||||
workflow,
|
||||
),
|
||||
|
@ -160,7 +163,7 @@ describe('softDeleteOnPruningCycle()', () => {
|
|||
|
||||
test('should not re-mark already marked executions', async () => {
|
||||
const executions = [
|
||||
await testDb.createExecution(
|
||||
await createExecution(
|
||||
{
|
||||
status: 'success',
|
||||
finished: true,
|
||||
|
@ -170,7 +173,7 @@ describe('softDeleteOnPruningCycle()', () => {
|
|||
},
|
||||
workflow,
|
||||
),
|
||||
await testDb.createSuccessfulExecution(workflow),
|
||||
await createSuccessfulExecution(workflow),
|
||||
];
|
||||
|
||||
await pruningService.softDeleteOnPruningCycle();
|
||||
|
@ -190,7 +193,7 @@ describe('softDeleteOnPruningCycle()', () => {
|
|||
['failed', { startedAt: yesterday, stoppedAt: yesterday }],
|
||||
['success', { finished: true, startedAt: yesterday, stoppedAt: yesterday }],
|
||||
])('should prune %s executions', async (status, attributes) => {
|
||||
const execution = await testDb.createExecution({ status, ...attributes }, workflow);
|
||||
const execution = await createExecution({ status, ...attributes }, workflow);
|
||||
|
||||
await pruningService.softDeleteOnPruningCycle();
|
||||
|
||||
|
@ -206,8 +209,8 @@ describe('softDeleteOnPruningCycle()', () => {
|
|||
['waiting', { startedAt: yesterday, stoppedAt: yesterday, waitTill: yesterday }],
|
||||
])('should not prune %s executions', async (status, attributes) => {
|
||||
const executions = [
|
||||
await testDb.createExecution({ status, ...attributes }, workflow),
|
||||
await testDb.createSuccessfulExecution(workflow),
|
||||
await createExecution({ status, ...attributes }, workflow),
|
||||
await createSuccessfulExecution(workflow),
|
||||
];
|
||||
|
||||
await pruningService.softDeleteOnPruningCycle();
|
||||
|
|
|
@ -7,6 +7,9 @@ import { randomApiKey, randomName, randomString } from '../shared/random';
|
|||
import * as utils from '../shared/utils/';
|
||||
import type { CredentialPayload, SaveCredentialFunction } from '../shared/types';
|
||||
import * as testDb from '../shared/testDb';
|
||||
import { affixRoleToSaveCredential } from '../shared/db/credentials';
|
||||
import { getAllRoles } from '../shared/db/roles';
|
||||
import { addApiKey, createUser, createUserShell } from '../shared/db/users';
|
||||
|
||||
let globalMemberRole: Role;
|
||||
let credentialOwnerRole: Role;
|
||||
|
@ -21,18 +24,18 @@ const testServer = utils.setupTestServer({ endpointGroups: ['publicApi'] });
|
|||
|
||||
beforeAll(async () => {
|
||||
const [globalOwnerRole, fetchedGlobalMemberRole, _, fetchedCredentialOwnerRole] =
|
||||
await testDb.getAllRoles();
|
||||
await getAllRoles();
|
||||
|
||||
globalMemberRole = fetchedGlobalMemberRole;
|
||||
credentialOwnerRole = fetchedCredentialOwnerRole;
|
||||
|
||||
owner = await testDb.addApiKey(await testDb.createUserShell(globalOwnerRole));
|
||||
member = await testDb.createUser({ globalRole: globalMemberRole, apiKey: randomApiKey() });
|
||||
owner = await addApiKey(await createUserShell(globalOwnerRole));
|
||||
member = await createUser({ globalRole: globalMemberRole, apiKey: randomApiKey() });
|
||||
|
||||
authOwnerAgent = testServer.publicApiAgentFor(owner);
|
||||
authMemberAgent = testServer.publicApiAgentFor(member);
|
||||
|
||||
saveCredential = testDb.affixRoleToSaveCredential(credentialOwnerRole);
|
||||
saveCredential = affixRoleToSaveCredential(credentialOwnerRole);
|
||||
|
||||
await utils.initCredentialsTypes();
|
||||
});
|
||||
|
@ -150,7 +153,7 @@ describe('DELETE /credentials/:id', () => {
|
|||
});
|
||||
|
||||
test('should delete owned cred for member but leave others untouched', async () => {
|
||||
const anotherMember = await testDb.createUser({
|
||||
const anotherMember = await createUser({
|
||||
globalRole: globalMemberRole,
|
||||
apiKey: randomApiKey(),
|
||||
});
|
||||
|
|
|
@ -5,6 +5,19 @@ import type { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
|||
import { randomApiKey } from '../shared/random';
|
||||
import * as utils from '../shared/utils/';
|
||||
import * as testDb from '../shared/testDb';
|
||||
import { getGlobalMemberRole, getGlobalOwnerRole } from '../shared/db/roles';
|
||||
import { createUser } from '../shared/db/users';
|
||||
import {
|
||||
createManyWorkflows,
|
||||
createWorkflow,
|
||||
shareWorkflowWithUsers,
|
||||
} from '../shared/db/workflows';
|
||||
import {
|
||||
createErrorExecution,
|
||||
createManyExecutions,
|
||||
createSuccessfulExecution,
|
||||
createWaitingExecution,
|
||||
} from '../shared/db/executions';
|
||||
|
||||
let owner: User;
|
||||
let user1: User;
|
||||
|
@ -17,11 +30,11 @@ let workflowRunner: ActiveWorkflowRunner;
|
|||
const testServer = utils.setupTestServer({ endpointGroups: ['publicApi'] });
|
||||
|
||||
beforeAll(async () => {
|
||||
const globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||
const globalUserRole = await testDb.getGlobalMemberRole();
|
||||
owner = await testDb.createUser({ globalRole: globalOwnerRole, apiKey: randomApiKey() });
|
||||
user1 = await testDb.createUser({ globalRole: globalUserRole, apiKey: randomApiKey() });
|
||||
user2 = await testDb.createUser({ globalRole: globalUserRole, apiKey: randomApiKey() });
|
||||
const globalOwnerRole = await getGlobalOwnerRole();
|
||||
const globalUserRole = await getGlobalMemberRole();
|
||||
owner = await createUser({ globalRole: globalOwnerRole, apiKey: randomApiKey() });
|
||||
user1 = await createUser({ globalRole: globalUserRole, apiKey: randomApiKey() });
|
||||
user2 = await createUser({ globalRole: globalUserRole, apiKey: randomApiKey() });
|
||||
|
||||
// TODO: mock BinaryDataService instead
|
||||
await utils.initBinaryDataService();
|
||||
|
@ -62,9 +75,9 @@ describe('GET /executions/:id', () => {
|
|||
test('should fail due to invalid API Key', testWithAPIKey('get', '/executions/1', 'abcXYZ'));
|
||||
|
||||
test('owner should be able to get an execution owned by him', async () => {
|
||||
const workflow = await testDb.createWorkflow({}, owner);
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
|
||||
const execution = await testDb.createSuccessfulExecution(workflow);
|
||||
const execution = await createSuccessfulExecution(workflow);
|
||||
|
||||
const response = await authOwnerAgent.get(`/executions/${execution.id}`);
|
||||
|
||||
|
@ -94,8 +107,8 @@ describe('GET /executions/:id', () => {
|
|||
});
|
||||
|
||||
test('owner should be able to read executions of other users', async () => {
|
||||
const workflow = await testDb.createWorkflow({}, user1);
|
||||
const execution = await testDb.createSuccessfulExecution(workflow);
|
||||
const workflow = await createWorkflow({}, user1);
|
||||
const execution = await createSuccessfulExecution(workflow);
|
||||
|
||||
const response = await authOwnerAgent.get(`/executions/${execution.id}`);
|
||||
|
||||
|
@ -103,8 +116,8 @@ describe('GET /executions/:id', () => {
|
|||
});
|
||||
|
||||
test('member should be able to fetch his own executions', async () => {
|
||||
const workflow = await testDb.createWorkflow({}, user1);
|
||||
const execution = await testDb.createSuccessfulExecution(workflow);
|
||||
const workflow = await createWorkflow({}, user1);
|
||||
const execution = await createSuccessfulExecution(workflow);
|
||||
|
||||
const response = await authUser1Agent.get(`/executions/${execution.id}`);
|
||||
|
||||
|
@ -112,9 +125,9 @@ describe('GET /executions/:id', () => {
|
|||
});
|
||||
|
||||
test('member should not get an execution of another user without the workflow being shared', async () => {
|
||||
const workflow = await testDb.createWorkflow({}, owner);
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
|
||||
const execution = await testDb.createSuccessfulExecution(workflow);
|
||||
const execution = await createSuccessfulExecution(workflow);
|
||||
|
||||
const response = await authUser1Agent.get(`/executions/${execution.id}`);
|
||||
|
||||
|
@ -122,11 +135,11 @@ describe('GET /executions/:id', () => {
|
|||
});
|
||||
|
||||
test('member should be able to fetch executions of workflows shared with him', async () => {
|
||||
const workflow = await testDb.createWorkflow({}, user1);
|
||||
const workflow = await createWorkflow({}, user1);
|
||||
|
||||
const execution = await testDb.createSuccessfulExecution(workflow);
|
||||
const execution = await createSuccessfulExecution(workflow);
|
||||
|
||||
await testDb.shareWorkflowWithUsers(workflow, [user2]);
|
||||
await shareWorkflowWithUsers(workflow, [user2]);
|
||||
|
||||
const response = await authUser2Agent.get(`/executions/${execution.id}`);
|
||||
|
||||
|
@ -140,8 +153,8 @@ describe('DELETE /executions/:id', () => {
|
|||
test('should fail due to invalid API Key', testWithAPIKey('delete', '/executions/1', 'abcXYZ'));
|
||||
|
||||
test('should delete an execution', async () => {
|
||||
const workflow = await testDb.createWorkflow({}, owner);
|
||||
const execution = await testDb.createSuccessfulExecution(workflow);
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
const execution = await createSuccessfulExecution(workflow);
|
||||
|
||||
const response = await authOwnerAgent.delete(`/executions/${execution.id}`);
|
||||
|
||||
|
@ -179,11 +192,11 @@ describe('GET /executions', () => {
|
|||
test('should fail due to invalid API Key', testWithAPIKey('get', '/executions', 'abcXYZ'));
|
||||
|
||||
test('should retrieve all successful executions', async () => {
|
||||
const workflow = await testDb.createWorkflow({}, owner);
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
|
||||
const successfulExecution = await testDb.createSuccessfulExecution(workflow);
|
||||
const successfulExecution = await createSuccessfulExecution(workflow);
|
||||
|
||||
await testDb.createErrorExecution(workflow);
|
||||
await createErrorExecution(workflow);
|
||||
|
||||
const response = await authOwnerAgent.get('/executions').query({
|
||||
status: 'success',
|
||||
|
@ -219,13 +232,13 @@ describe('GET /executions', () => {
|
|||
// failing on Postgres and MySQL - ref: https://github.com/n8n-io/n8n/pull/3834
|
||||
// eslint-disable-next-line n8n-local-rules/no-skipped-tests
|
||||
test.skip('should paginate two executions', async () => {
|
||||
const workflow = await testDb.createWorkflow({}, owner);
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
|
||||
const firstSuccessfulExecution = await testDb.createSuccessfulExecution(workflow);
|
||||
const firstSuccessfulExecution = await createSuccessfulExecution(workflow);
|
||||
|
||||
const secondSuccessfulExecution = await testDb.createSuccessfulExecution(workflow);
|
||||
const secondSuccessfulExecution = await createSuccessfulExecution(workflow);
|
||||
|
||||
await testDb.createErrorExecution(workflow);
|
||||
await createErrorExecution(workflow);
|
||||
|
||||
const firstExecutionResponse = await authOwnerAgent.get('/executions').query({
|
||||
status: 'success',
|
||||
|
@ -275,11 +288,11 @@ describe('GET /executions', () => {
|
|||
});
|
||||
|
||||
test('should retrieve all error executions', async () => {
|
||||
const workflow = await testDb.createWorkflow({}, owner);
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
|
||||
await testDb.createSuccessfulExecution(workflow);
|
||||
await createSuccessfulExecution(workflow);
|
||||
|
||||
const errorExecution = await testDb.createErrorExecution(workflow);
|
||||
const errorExecution = await createErrorExecution(workflow);
|
||||
|
||||
const response = await authOwnerAgent.get('/executions').query({
|
||||
status: 'error',
|
||||
|
@ -313,13 +326,13 @@ describe('GET /executions', () => {
|
|||
});
|
||||
|
||||
test('should return all waiting executions', async () => {
|
||||
const workflow = await testDb.createWorkflow({}, owner);
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
|
||||
await testDb.createSuccessfulExecution(workflow);
|
||||
await createSuccessfulExecution(workflow);
|
||||
|
||||
await testDb.createErrorExecution(workflow);
|
||||
await createErrorExecution(workflow);
|
||||
|
||||
const waitingExecution = await testDb.createWaitingExecution(workflow);
|
||||
const waitingExecution = await createWaitingExecution(workflow);
|
||||
|
||||
const response = await authOwnerAgent.get('/executions').query({
|
||||
status: 'waiting',
|
||||
|
@ -353,14 +366,10 @@ describe('GET /executions', () => {
|
|||
});
|
||||
|
||||
test('should retrieve all executions of specific workflow', async () => {
|
||||
const [workflow, workflow2] = await testDb.createManyWorkflows(2, {}, owner);
|
||||
const [workflow, workflow2] = await createManyWorkflows(2, {}, owner);
|
||||
|
||||
const savedExecutions = await testDb.createManyExecutions(
|
||||
2,
|
||||
workflow,
|
||||
testDb.createSuccessfulExecution,
|
||||
);
|
||||
await testDb.createManyExecutions(2, workflow2, testDb.createSuccessfulExecution);
|
||||
const savedExecutions = await createManyExecutions(2, workflow, createSuccessfulExecution);
|
||||
await createManyExecutions(2, workflow2, createSuccessfulExecution);
|
||||
|
||||
const response = await authOwnerAgent.get('/executions').query({
|
||||
workflowId: workflow.id,
|
||||
|
@ -396,21 +405,13 @@ describe('GET /executions', () => {
|
|||
});
|
||||
|
||||
test('owner should retrieve all executions regardless of ownership', async () => {
|
||||
const [firstWorkflowForUser1, secondWorkflowForUser1] = await testDb.createManyWorkflows(
|
||||
2,
|
||||
{},
|
||||
user1,
|
||||
);
|
||||
await testDb.createManyExecutions(2, firstWorkflowForUser1, testDb.createSuccessfulExecution);
|
||||
await testDb.createManyExecutions(2, secondWorkflowForUser1, testDb.createSuccessfulExecution);
|
||||
const [firstWorkflowForUser1, secondWorkflowForUser1] = await createManyWorkflows(2, {}, user1);
|
||||
await createManyExecutions(2, firstWorkflowForUser1, createSuccessfulExecution);
|
||||
await createManyExecutions(2, secondWorkflowForUser1, createSuccessfulExecution);
|
||||
|
||||
const [firstWorkflowForUser2, secondWorkflowForUser2] = await testDb.createManyWorkflows(
|
||||
2,
|
||||
{},
|
||||
user2,
|
||||
);
|
||||
await testDb.createManyExecutions(2, firstWorkflowForUser2, testDb.createSuccessfulExecution);
|
||||
await testDb.createManyExecutions(2, secondWorkflowForUser2, testDb.createSuccessfulExecution);
|
||||
const [firstWorkflowForUser2, secondWorkflowForUser2] = await createManyWorkflows(2, {}, user2);
|
||||
await createManyExecutions(2, firstWorkflowForUser2, createSuccessfulExecution);
|
||||
await createManyExecutions(2, secondWorkflowForUser2, createSuccessfulExecution);
|
||||
|
||||
const response = await authOwnerAgent.get('/executions');
|
||||
|
||||
|
@ -420,21 +421,13 @@ describe('GET /executions', () => {
|
|||
});
|
||||
|
||||
test('member should not see executions of workflows not shared with him', async () => {
|
||||
const [firstWorkflowForUser1, secondWorkflowForUser1] = await testDb.createManyWorkflows(
|
||||
2,
|
||||
{},
|
||||
user1,
|
||||
);
|
||||
await testDb.createManyExecutions(2, firstWorkflowForUser1, testDb.createSuccessfulExecution);
|
||||
await testDb.createManyExecutions(2, secondWorkflowForUser1, testDb.createSuccessfulExecution);
|
||||
const [firstWorkflowForUser1, secondWorkflowForUser1] = await createManyWorkflows(2, {}, user1);
|
||||
await createManyExecutions(2, firstWorkflowForUser1, createSuccessfulExecution);
|
||||
await createManyExecutions(2, secondWorkflowForUser1, createSuccessfulExecution);
|
||||
|
||||
const [firstWorkflowForUser2, secondWorkflowForUser2] = await testDb.createManyWorkflows(
|
||||
2,
|
||||
{},
|
||||
user2,
|
||||
);
|
||||
await testDb.createManyExecutions(2, firstWorkflowForUser2, testDb.createSuccessfulExecution);
|
||||
await testDb.createManyExecutions(2, secondWorkflowForUser2, testDb.createSuccessfulExecution);
|
||||
const [firstWorkflowForUser2, secondWorkflowForUser2] = await createManyWorkflows(2, {}, user2);
|
||||
await createManyExecutions(2, firstWorkflowForUser2, createSuccessfulExecution);
|
||||
await createManyExecutions(2, secondWorkflowForUser2, createSuccessfulExecution);
|
||||
|
||||
const response = await authUser1Agent.get('/executions');
|
||||
|
||||
|
@ -444,23 +437,15 @@ describe('GET /executions', () => {
|
|||
});
|
||||
|
||||
test('member should also see executions of workflows shared with him', async () => {
|
||||
const [firstWorkflowForUser1, secondWorkflowForUser1] = await testDb.createManyWorkflows(
|
||||
2,
|
||||
{},
|
||||
user1,
|
||||
);
|
||||
await testDb.createManyExecutions(2, firstWorkflowForUser1, testDb.createSuccessfulExecution);
|
||||
await testDb.createManyExecutions(2, secondWorkflowForUser1, testDb.createSuccessfulExecution);
|
||||
const [firstWorkflowForUser1, secondWorkflowForUser1] = await createManyWorkflows(2, {}, user1);
|
||||
await createManyExecutions(2, firstWorkflowForUser1, createSuccessfulExecution);
|
||||
await createManyExecutions(2, secondWorkflowForUser1, createSuccessfulExecution);
|
||||
|
||||
const [firstWorkflowForUser2, secondWorkflowForUser2] = await testDb.createManyWorkflows(
|
||||
2,
|
||||
{},
|
||||
user2,
|
||||
);
|
||||
await testDb.createManyExecutions(2, firstWorkflowForUser2, testDb.createSuccessfulExecution);
|
||||
await testDb.createManyExecutions(2, secondWorkflowForUser2, testDb.createSuccessfulExecution);
|
||||
const [firstWorkflowForUser2, secondWorkflowForUser2] = await createManyWorkflows(2, {}, user2);
|
||||
await createManyExecutions(2, firstWorkflowForUser2, createSuccessfulExecution);
|
||||
await createManyExecutions(2, secondWorkflowForUser2, createSuccessfulExecution);
|
||||
|
||||
await testDb.shareWorkflowWithUsers(firstWorkflowForUser2, [user1]);
|
||||
await shareWorkflowWithUsers(firstWorkflowForUser2, [user1]);
|
||||
|
||||
const response = await authUser1Agent.get('/executions');
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ import { License } from '@/License';
|
|||
import { randomApiKey } from '../shared/random';
|
||||
import * as utils from '../shared/utils/';
|
||||
import * as testDb from '../shared/testDb';
|
||||
import { getGlobalMemberRole, getGlobalOwnerRole } from '../shared/db/roles';
|
||||
import { createUser, createUserShell } from '../shared/db/users';
|
||||
|
||||
utils.mockInstance(License, {
|
||||
getUsersLimit: jest.fn().mockReturnValue(-1),
|
||||
|
@ -19,7 +21,10 @@ let globalOwnerRole: Role;
|
|||
let globalMemberRole: Role;
|
||||
|
||||
beforeAll(async () => {
|
||||
[globalOwnerRole, globalMemberRole] = await testDb.getAllRoles();
|
||||
[globalOwnerRole, globalMemberRole] = await Promise.all([
|
||||
getGlobalOwnerRole(),
|
||||
getGlobalMemberRole(),
|
||||
]);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
|
@ -29,13 +34,13 @@ beforeEach(async () => {
|
|||
describe('With license unlimited quota:users', () => {
|
||||
describe('GET /users', () => {
|
||||
test('should fail due to missing API Key', async () => {
|
||||
const owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
const owner = await createUser({ globalRole: globalOwnerRole });
|
||||
const authOwnerAgent = testServer.publicApiAgentFor(owner);
|
||||
await authOwnerAgent.get('/users').expect(401);
|
||||
});
|
||||
|
||||
test('should fail due to invalid API Key', async () => {
|
||||
const owner = await testDb.createUser({
|
||||
const owner = await createUser({
|
||||
globalRole: globalOwnerRole,
|
||||
apiKey: randomApiKey(),
|
||||
});
|
||||
|
@ -45,20 +50,20 @@ describe('With license unlimited quota:users', () => {
|
|||
});
|
||||
|
||||
test('should fail due to member trying to access owner only endpoint', async () => {
|
||||
const member = await testDb.createUser({ apiKey: randomApiKey() });
|
||||
const member = await createUser({ apiKey: randomApiKey() });
|
||||
const authMemberAgent = testServer.publicApiAgentFor(member);
|
||||
await authMemberAgent.get('/users').expect(403);
|
||||
});
|
||||
|
||||
test('should return all users', async () => {
|
||||
const owner = await testDb.createUser({
|
||||
const owner = await createUser({
|
||||
globalRole: globalOwnerRole,
|
||||
apiKey: randomApiKey(),
|
||||
});
|
||||
|
||||
const authOwnerAgent = testServer.publicApiAgentFor(owner);
|
||||
|
||||
await testDb.createUser();
|
||||
await createUser();
|
||||
|
||||
const response = await authOwnerAgent.get('/users').expect(200);
|
||||
expect(response.body.data.length).toBe(2);
|
||||
|
@ -94,13 +99,13 @@ describe('With license unlimited quota:users', () => {
|
|||
|
||||
describe('GET /users/:id', () => {
|
||||
test('should fail due to missing API Key', async () => {
|
||||
const owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
const owner = await createUser({ globalRole: globalOwnerRole });
|
||||
const authOwnerAgent = testServer.publicApiAgentFor(owner);
|
||||
await authOwnerAgent.get(`/users/${owner.id}`).expect(401);
|
||||
});
|
||||
|
||||
test('should fail due to invalid API Key', async () => {
|
||||
const owner = await testDb.createUser({
|
||||
const owner = await createUser({
|
||||
globalRole: globalOwnerRole,
|
||||
apiKey: randomApiKey(),
|
||||
});
|
||||
|
@ -110,12 +115,12 @@ describe('With license unlimited quota:users', () => {
|
|||
});
|
||||
|
||||
test('should fail due to member trying to access owner only endpoint', async () => {
|
||||
const member = await testDb.createUser({ apiKey: randomApiKey() });
|
||||
const member = await createUser({ apiKey: randomApiKey() });
|
||||
const authMemberAgent = testServer.publicApiAgentFor(member);
|
||||
await authMemberAgent.get(`/users/${member.id}`).expect(403);
|
||||
});
|
||||
test('should return 404 for non-existing id ', async () => {
|
||||
const owner = await testDb.createUser({
|
||||
const owner = await createUser({
|
||||
globalRole: globalOwnerRole,
|
||||
apiKey: randomApiKey(),
|
||||
});
|
||||
|
@ -124,12 +129,12 @@ describe('With license unlimited quota:users', () => {
|
|||
});
|
||||
|
||||
test('should return a pending user', async () => {
|
||||
const owner = await testDb.createUser({
|
||||
const owner = await createUser({
|
||||
globalRole: globalOwnerRole,
|
||||
apiKey: randomApiKey(),
|
||||
});
|
||||
|
||||
const { id: memberId } = await testDb.createUserShell(globalMemberRole);
|
||||
const { id: memberId } = await createUserShell(globalMemberRole);
|
||||
|
||||
const authOwnerAgent = testServer.publicApiAgentFor(owner);
|
||||
const response = await authOwnerAgent.get(`/users/${memberId}`).expect(200);
|
||||
|
@ -163,7 +168,7 @@ describe('With license unlimited quota:users', () => {
|
|||
|
||||
describe('GET /users/:email', () => {
|
||||
test('with non-existing email should return 404', async () => {
|
||||
const owner = await testDb.createUser({
|
||||
const owner = await createUser({
|
||||
globalRole: globalOwnerRole,
|
||||
apiKey: randomApiKey(),
|
||||
});
|
||||
|
@ -172,7 +177,7 @@ describe('With license unlimited quota:users', () => {
|
|||
});
|
||||
|
||||
test('should return a user', async () => {
|
||||
const owner = await testDb.createUser({
|
||||
const owner = await createUser({
|
||||
globalRole: globalOwnerRole,
|
||||
apiKey: randomApiKey(),
|
||||
});
|
||||
|
@ -213,7 +218,7 @@ describe('With license without quota:users', () => {
|
|||
beforeEach(async () => {
|
||||
utils.mockInstance(License, { getUsersLimit: jest.fn().mockReturnValue(null) });
|
||||
|
||||
const owner = await testDb.createUser({
|
||||
const owner = await createUser({
|
||||
globalRole: globalOwnerRole,
|
||||
apiKey: randomApiKey(),
|
||||
});
|
||||
|
|
|
@ -13,6 +13,10 @@ import { STARTING_NODES } from '@/constants';
|
|||
import { License } from '@/License';
|
||||
import { WorkflowHistoryRepository } from '@/databases/repositories';
|
||||
import Container from 'typedi';
|
||||
import { getAllRoles } from '../shared/db/roles';
|
||||
import { createUser } from '../shared/db/users';
|
||||
import { createWorkflow, createWorkflowWithTrigger } from '../shared/db/workflows';
|
||||
import { createTag } from '../shared/db/tags';
|
||||
|
||||
let workflowOwnerRole: Role;
|
||||
let owner: User;
|
||||
|
@ -29,16 +33,16 @@ const licenseLike = utils.mockInstance(License, {
|
|||
});
|
||||
|
||||
beforeAll(async () => {
|
||||
const [globalOwnerRole, globalMemberRole, fetchedWorkflowOwnerRole] = await testDb.getAllRoles();
|
||||
const [globalOwnerRole, globalMemberRole, fetchedWorkflowOwnerRole] = await getAllRoles();
|
||||
|
||||
workflowOwnerRole = fetchedWorkflowOwnerRole;
|
||||
|
||||
owner = await testDb.createUser({
|
||||
owner = await createUser({
|
||||
globalRole: globalOwnerRole,
|
||||
apiKey: randomApiKey(),
|
||||
});
|
||||
|
||||
member = await testDb.createUser({
|
||||
member = await createUser({
|
||||
globalRole: globalMemberRole,
|
||||
apiKey: randomApiKey(),
|
||||
});
|
||||
|
@ -80,9 +84,9 @@ describe('GET /workflows', () => {
|
|||
|
||||
test('should return all owned workflows', async () => {
|
||||
await Promise.all([
|
||||
testDb.createWorkflow({}, member),
|
||||
testDb.createWorkflow({}, member),
|
||||
testDb.createWorkflow({}, member),
|
||||
createWorkflow({}, member),
|
||||
createWorkflow({}, member),
|
||||
createWorkflow({}, member),
|
||||
]);
|
||||
|
||||
const response = await authMemberAgent.get('/workflows');
|
||||
|
@ -120,9 +124,9 @@ describe('GET /workflows', () => {
|
|||
|
||||
test('should return all owned workflows with pagination', async () => {
|
||||
await Promise.all([
|
||||
testDb.createWorkflow({}, member),
|
||||
testDb.createWorkflow({}, member),
|
||||
testDb.createWorkflow({}, member),
|
||||
createWorkflow({}, member),
|
||||
createWorkflow({}, member),
|
||||
createWorkflow({}, member),
|
||||
]);
|
||||
|
||||
const response = await authMemberAgent.get('/workflows?limit=1');
|
||||
|
@ -173,11 +177,11 @@ describe('GET /workflows', () => {
|
|||
});
|
||||
|
||||
test('should return all owned workflows filtered by tag', async () => {
|
||||
const tag = await testDb.createTag({});
|
||||
const tag = await createTag({});
|
||||
|
||||
const [workflow] = await Promise.all([
|
||||
testDb.createWorkflow({ tags: [tag] }, member),
|
||||
testDb.createWorkflow({}, member),
|
||||
createWorkflow({ tags: [tag] }, member),
|
||||
createWorkflow({}, member),
|
||||
]);
|
||||
|
||||
const response = await authMemberAgent.get(`/workflows?tags=${tag.name}`);
|
||||
|
@ -213,15 +217,15 @@ describe('GET /workflows', () => {
|
|||
});
|
||||
|
||||
test('should return all owned workflows filtered by tags', async () => {
|
||||
const tags = await Promise.all([await testDb.createTag({}), await testDb.createTag({})]);
|
||||
const tags = await Promise.all([await createTag({}), await createTag({})]);
|
||||
const tagNames = tags.map((tag) => tag.name).join(',');
|
||||
|
||||
const [workflow1, workflow2] = await Promise.all([
|
||||
testDb.createWorkflow({ tags }, member),
|
||||
testDb.createWorkflow({ tags }, member),
|
||||
testDb.createWorkflow({}, member),
|
||||
testDb.createWorkflow({ tags: [tags[0]] }, member),
|
||||
testDb.createWorkflow({ tags: [tags[1]] }, member),
|
||||
createWorkflow({ tags }, member),
|
||||
createWorkflow({ tags }, member),
|
||||
createWorkflow({}, member),
|
||||
createWorkflow({ tags: [tags[0]] }, member),
|
||||
createWorkflow({ tags: [tags[1]] }, member),
|
||||
]);
|
||||
|
||||
const response = await authMemberAgent.get(`/workflows?tags=${tagNames}`);
|
||||
|
@ -254,11 +258,11 @@ describe('GET /workflows', () => {
|
|||
|
||||
test('should return all workflows for owner', async () => {
|
||||
await Promise.all([
|
||||
testDb.createWorkflow({}, owner),
|
||||
testDb.createWorkflow({}, member),
|
||||
testDb.createWorkflow({}, owner),
|
||||
testDb.createWorkflow({}, member),
|
||||
testDb.createWorkflow({}, owner),
|
||||
createWorkflow({}, owner),
|
||||
createWorkflow({}, member),
|
||||
createWorkflow({}, owner),
|
||||
createWorkflow({}, member),
|
||||
createWorkflow({}, owner),
|
||||
]);
|
||||
|
||||
const response = await authOwnerAgent.get('/workflows');
|
||||
|
@ -307,7 +311,7 @@ describe('GET /workflows/:id', () => {
|
|||
|
||||
test('should retrieve workflow', async () => {
|
||||
// create and assign workflow to owner
|
||||
const workflow = await testDb.createWorkflow({}, member);
|
||||
const workflow = await createWorkflow({}, member);
|
||||
|
||||
const response = await authMemberAgent.get(`/workflows/${workflow.id}`);
|
||||
|
||||
|
@ -340,7 +344,7 @@ describe('GET /workflows/:id', () => {
|
|||
|
||||
test('should retrieve non-owned workflow for owner', async () => {
|
||||
// create and assign workflow to owner
|
||||
const workflow = await testDb.createWorkflow({}, member);
|
||||
const workflow = await createWorkflow({}, member);
|
||||
|
||||
const response = await authOwnerAgent.get(`/workflows/${workflow.id}`);
|
||||
|
||||
|
@ -373,7 +377,7 @@ describe('DELETE /workflows/:id', () => {
|
|||
|
||||
test('should delete the workflow', async () => {
|
||||
// create and assign workflow to owner
|
||||
const workflow = await testDb.createWorkflow({}, member);
|
||||
const workflow = await createWorkflow({}, member);
|
||||
|
||||
const response = await authMemberAgent.delete(`/workflows/${workflow.id}`);
|
||||
|
||||
|
@ -402,7 +406,7 @@ describe('DELETE /workflows/:id', () => {
|
|||
|
||||
test('should delete non-owned workflow when owner', async () => {
|
||||
// create and assign workflow to owner
|
||||
const workflow = await testDb.createWorkflow({}, member);
|
||||
const workflow = await createWorkflow({}, member);
|
||||
|
||||
const response = await authMemberAgent.delete(`/workflows/${workflow.id}`);
|
||||
|
||||
|
@ -444,13 +448,13 @@ describe('POST /workflows/:id/activate', () => {
|
|||
});
|
||||
|
||||
test('should fail due to trying to activate a workflow without a trigger', async () => {
|
||||
const workflow = await testDb.createWorkflow({}, owner);
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
const response = await authOwnerAgent.post(`/workflows/${workflow.id}/activate`);
|
||||
expect(response.statusCode).toBe(400);
|
||||
});
|
||||
|
||||
test('should set workflow as active', async () => {
|
||||
const workflow = await testDb.createWorkflowWithTrigger({}, member);
|
||||
const workflow = await createWorkflowWithTrigger({}, member);
|
||||
|
||||
const response = await authMemberAgent.post(`/workflows/${workflow.id}/activate`);
|
||||
|
||||
|
@ -485,7 +489,7 @@ describe('POST /workflows/:id/activate', () => {
|
|||
});
|
||||
|
||||
test('should set non-owned workflow as active when owner', async () => {
|
||||
const workflow = await testDb.createWorkflowWithTrigger({}, member);
|
||||
const workflow = await createWorkflowWithTrigger({}, member);
|
||||
|
||||
const response = await authMemberAgent.post(`/workflows/${workflow.id}/activate`);
|
||||
|
||||
|
@ -546,7 +550,7 @@ describe('POST /workflows/:id/deactivate', () => {
|
|||
});
|
||||
|
||||
test('should deactivate workflow', async () => {
|
||||
const workflow = await testDb.createWorkflowWithTrigger({}, member);
|
||||
const workflow = await createWorkflowWithTrigger({}, member);
|
||||
|
||||
await authMemberAgent.post(`/workflows/${workflow.id}/activate`);
|
||||
|
||||
|
@ -583,7 +587,7 @@ describe('POST /workflows/:id/deactivate', () => {
|
|||
});
|
||||
|
||||
test('should deactivate non-owned workflow when owner', async () => {
|
||||
const workflow = await testDb.createWorkflowWithTrigger({}, member);
|
||||
const workflow = await createWorkflowWithTrigger({}, member);
|
||||
|
||||
await authMemberAgent.post(`/workflows/${workflow.id}/activate`);
|
||||
|
||||
|
@ -869,7 +873,7 @@ describe('PUT /workflows/:id', () => {
|
|||
});
|
||||
|
||||
test('should update workflow', async () => {
|
||||
const workflow = await testDb.createWorkflow({}, member);
|
||||
const workflow = await createWorkflow({}, member);
|
||||
const payload = {
|
||||
name: 'name updated',
|
||||
nodes: [
|
||||
|
@ -936,7 +940,7 @@ describe('PUT /workflows/:id', () => {
|
|||
|
||||
test('should create workflow history version when licensed', async () => {
|
||||
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(true);
|
||||
const workflow = await testDb.createWorkflow({}, member);
|
||||
const workflow = await createWorkflow({}, member);
|
||||
const payload = {
|
||||
name: 'name updated',
|
||||
nodes: [
|
||||
|
@ -991,7 +995,7 @@ describe('PUT /workflows/:id', () => {
|
|||
|
||||
test('should not create workflow history when not licensed', async () => {
|
||||
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
|
||||
const workflow = await testDb.createWorkflow({}, member);
|
||||
const workflow = await createWorkflow({}, member);
|
||||
const payload = {
|
||||
name: 'name updated',
|
||||
nodes: [
|
||||
|
@ -1037,7 +1041,7 @@ describe('PUT /workflows/:id', () => {
|
|||
});
|
||||
|
||||
test('should update non-owned workflow if owner', async () => {
|
||||
const workflow = await testDb.createWorkflow({}, member);
|
||||
const workflow = await createWorkflow({}, member);
|
||||
|
||||
const payload = {
|
||||
name: 'name owner updated',
|
||||
|
|
|
@ -10,9 +10,9 @@ import { SamlService } from '@/sso/saml/saml.service.ee';
|
|||
import type { SamlUserAttributes } from '@/sso/saml/types/samlUserAttributes';
|
||||
|
||||
import { randomEmail, randomName, randomValidPassword } from '../shared/random';
|
||||
import * as testDb from '../shared/testDb';
|
||||
import * as utils from '../shared/utils/';
|
||||
import { sampleConfig } from './sampleMetadata';
|
||||
import { createOwner, createUser } from '../shared/db/users';
|
||||
|
||||
let someUser: User;
|
||||
let owner: User;
|
||||
|
@ -29,8 +29,8 @@ const testServer = utils.setupTestServer({
|
|||
});
|
||||
|
||||
beforeAll(async () => {
|
||||
owner = await testDb.createOwner();
|
||||
someUser = await testDb.createUser();
|
||||
owner = await createOwner();
|
||||
someUser = await createUser();
|
||||
authOwnerAgent = testServer.authAgentFor(owner);
|
||||
authMemberAgent = testServer.authAgentFor(someUser);
|
||||
});
|
||||
|
|
67
packages/cli/test/integration/shared/db/credentials.ts
Normal file
67
packages/cli/test/integration/shared/db/credentials.ts
Normal file
|
@ -0,0 +1,67 @@
|
|||
import { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
import type { ICredentialsDb } from '@/Interfaces';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import type { CredentialPayload } from '../types';
|
||||
import Container from 'typedi';
|
||||
import { CredentialsRepository, SharedCredentialsRepository } from '@/databases/repositories';
|
||||
|
||||
async function encryptCredentialData(credential: CredentialsEntity) {
|
||||
const { createCredentialsFromCredentialsEntity } = await import('@/CredentialsHelper');
|
||||
const coreCredential = createCredentialsFromCredentialsEntity(credential, true);
|
||||
|
||||
// @ts-ignore
|
||||
coreCredential.setData(credential.data);
|
||||
|
||||
return coreCredential.getDataToSave() as ICredentialsDb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a credential to the test DB, sharing it with a user.
|
||||
*/
|
||||
export async function saveCredential(
|
||||
credentialPayload: CredentialPayload,
|
||||
{ user, role }: { user: User; role: Role },
|
||||
) {
|
||||
const newCredential = new CredentialsEntity();
|
||||
|
||||
Object.assign(newCredential, credentialPayload);
|
||||
|
||||
const encryptedData = await encryptCredentialData(newCredential);
|
||||
|
||||
Object.assign(newCredential, encryptedData);
|
||||
|
||||
const savedCredential = await Container.get(CredentialsRepository).save(newCredential);
|
||||
|
||||
savedCredential.data = newCredential.data;
|
||||
|
||||
await Container.get(SharedCredentialsRepository).save({
|
||||
user,
|
||||
credentials: savedCredential,
|
||||
role,
|
||||
});
|
||||
|
||||
return savedCredential;
|
||||
}
|
||||
|
||||
export async function shareCredentialWithUsers(credential: CredentialsEntity, users: User[]) {
|
||||
const role = await Container.get(RoleService).findCredentialUserRole();
|
||||
const newSharedCredentials = users.map((user) =>
|
||||
Container.get(SharedCredentialsRepository).create({
|
||||
userId: user.id,
|
||||
credentialsId: credential.id,
|
||||
roleId: role?.id,
|
||||
}),
|
||||
);
|
||||
return Container.get(SharedCredentialsRepository).save(newSharedCredentials);
|
||||
}
|
||||
|
||||
export function affixRoleToSaveCredential(role: Role) {
|
||||
return async (credentialPayload: CredentialPayload, { user }: { user: User }) =>
|
||||
saveCredential(credentialPayload, { user, role });
|
||||
}
|
||||
|
||||
export async function getAllCredentials() {
|
||||
return Container.get(CredentialsRepository).find();
|
||||
}
|
68
packages/cli/test/integration/shared/db/executions.ts
Normal file
68
packages/cli/test/integration/shared/db/executions.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
import Container from 'typedi';
|
||||
import type { ExecutionData } from '@db/entities/ExecutionData';
|
||||
import type { ExecutionEntity } from '@db/entities/ExecutionEntity';
|
||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import { ExecutionDataRepository, ExecutionRepository } from '@db/repositories';
|
||||
|
||||
export async function createManyExecutions(
|
||||
amount: number,
|
||||
workflow: WorkflowEntity,
|
||||
callback: (workflow: WorkflowEntity) => Promise<ExecutionEntity>,
|
||||
) {
|
||||
const executionsRequests = [...Array(amount)].map(async (_) => callback(workflow));
|
||||
return Promise.all(executionsRequests);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a execution in the DB and assign it to a workflow.
|
||||
*/
|
||||
export async function createExecution(
|
||||
attributes: Partial<ExecutionEntity & ExecutionData>,
|
||||
workflow: WorkflowEntity,
|
||||
) {
|
||||
const { data, finished, mode, startedAt, stoppedAt, waitTill, status, deletedAt } = attributes;
|
||||
|
||||
const execution = await Container.get(ExecutionRepository).save({
|
||||
finished: finished ?? true,
|
||||
mode: mode ?? 'manual',
|
||||
startedAt: startedAt ?? new Date(),
|
||||
...(workflow !== undefined && { workflowId: workflow.id }),
|
||||
stoppedAt: stoppedAt ?? new Date(),
|
||||
waitTill: waitTill ?? null,
|
||||
status,
|
||||
deletedAt,
|
||||
});
|
||||
|
||||
await Container.get(ExecutionDataRepository).save({
|
||||
data: data ?? '[]',
|
||||
workflowData: workflow ?? {},
|
||||
executionId: execution.id,
|
||||
});
|
||||
|
||||
return execution;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a successful execution in the DB and assign it to a workflow.
|
||||
*/
|
||||
export async function createSuccessfulExecution(workflow: WorkflowEntity) {
|
||||
return createExecution({ finished: true, status: 'success' }, workflow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store an error execution in the DB and assign it to a workflow.
|
||||
*/
|
||||
export async function createErrorExecution(workflow: WorkflowEntity) {
|
||||
return createExecution({ finished: false, stoppedAt: new Date(), status: 'failed' }, workflow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a waiting execution in the DB and assign it to a workflow.
|
||||
*/
|
||||
export async function createWaitingExecution(workflow: WorkflowEntity) {
|
||||
return createExecution({ finished: false, waitTill: new Date(), status: 'waiting' }, workflow);
|
||||
}
|
||||
|
||||
export async function getAllExecutions() {
|
||||
return Container.get(ExecutionRepository).find();
|
||||
}
|
31
packages/cli/test/integration/shared/db/roles.ts
Normal file
31
packages/cli/test/integration/shared/db/roles.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import Container from 'typedi';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
export async function getGlobalOwnerRole() {
|
||||
return Container.get(RoleService).findGlobalOwnerRole();
|
||||
}
|
||||
|
||||
export async function getGlobalMemberRole() {
|
||||
return Container.get(RoleService).findGlobalMemberRole();
|
||||
}
|
||||
|
||||
export async function getWorkflowOwnerRole() {
|
||||
return Container.get(RoleService).findWorkflowOwnerRole();
|
||||
}
|
||||
|
||||
export async function getWorkflowEditorRole() {
|
||||
return Container.get(RoleService).findWorkflowEditorRole();
|
||||
}
|
||||
|
||||
export async function getCredentialOwnerRole() {
|
||||
return Container.get(RoleService).findCredentialOwnerRole();
|
||||
}
|
||||
|
||||
export async function getAllRoles() {
|
||||
return Promise.all([
|
||||
getGlobalOwnerRole(),
|
||||
getGlobalMemberRole(),
|
||||
getWorkflowOwnerRole(),
|
||||
getCredentialOwnerRole(),
|
||||
]);
|
||||
}
|
25
packages/cli/test/integration/shared/db/tags.ts
Normal file
25
packages/cli/test/integration/shared/db/tags.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import Container from 'typedi';
|
||||
import type { TagEntity } from '@db/entities/TagEntity';
|
||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import { TagRepository, WorkflowTagMappingRepository } from '@db/repositories';
|
||||
import { generateNanoId } from '@db/utils/generators';
|
||||
|
||||
import { randomName } from '../random';
|
||||
|
||||
export async function createTag(attributes: Partial<TagEntity> = {}, workflow?: WorkflowEntity) {
|
||||
const { name } = attributes;
|
||||
|
||||
const tag = await Container.get(TagRepository).save({
|
||||
id: generateNanoId(),
|
||||
name: name ?? randomName(),
|
||||
...attributes,
|
||||
});
|
||||
|
||||
if (workflow) {
|
||||
const mappingRepository = Container.get(WorkflowTagMappingRepository);
|
||||
const mapping = mappingRepository.create({ tagId: tag.id, workflowId: workflow.id });
|
||||
await mappingRepository.save(mapping);
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
134
packages/cli/test/integration/shared/db/users.ts
Normal file
134
packages/cli/test/integration/shared/db/users.ts
Normal file
|
@ -0,0 +1,134 @@
|
|||
import Container from 'typedi';
|
||||
import { hash } from 'bcryptjs';
|
||||
import { AuthIdentity } from '@db/entities/AuthIdentity';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { AuthIdentityRepository, UserRepository } from '@db/repositories';
|
||||
import { TOTPService } from '@/Mfa/totp.service';
|
||||
import { MfaService } from '@/Mfa/mfa.service';
|
||||
|
||||
import { randomApiKey, randomEmail, randomName, randomValidPassword } from '../random';
|
||||
import { getGlobalMemberRole, getGlobalOwnerRole } from './roles';
|
||||
|
||||
/**
|
||||
* Store a user in the DB, defaulting to a `member`.
|
||||
*/
|
||||
export async function createUser(attributes: Partial<User> = {}): Promise<User> {
|
||||
const { email, password, firstName, lastName, globalRole, ...rest } = attributes;
|
||||
const user: Partial<User> = {
|
||||
email: email ?? randomEmail(),
|
||||
password: await hash(password ?? randomValidPassword(), 10),
|
||||
firstName: firstName ?? randomName(),
|
||||
lastName: lastName ?? randomName(),
|
||||
globalRoleId: (globalRole ?? (await getGlobalMemberRole())).id,
|
||||
globalRole,
|
||||
...rest,
|
||||
};
|
||||
|
||||
return Container.get(UserRepository).save(user);
|
||||
}
|
||||
|
||||
export async function createLdapUser(attributes: Partial<User>, ldapId: string): Promise<User> {
|
||||
const user = await createUser(attributes);
|
||||
await Container.get(AuthIdentityRepository).save(AuthIdentity.create(user, ldapId, 'ldap'));
|
||||
return user;
|
||||
}
|
||||
|
||||
export async function createUserWithMfaEnabled(
|
||||
data: { numberOfRecoveryCodes: number } = { numberOfRecoveryCodes: 10 },
|
||||
) {
|
||||
const email = randomEmail();
|
||||
const password = randomValidPassword();
|
||||
|
||||
const toptService = new TOTPService();
|
||||
|
||||
const secret = toptService.generateSecret();
|
||||
|
||||
const mfaService = Container.get(MfaService);
|
||||
|
||||
const recoveryCodes = mfaService.generateRecoveryCodes(data.numberOfRecoveryCodes);
|
||||
|
||||
const { encryptedSecret, encryptedRecoveryCodes } = mfaService.encryptSecretAndRecoveryCodes(
|
||||
secret,
|
||||
recoveryCodes,
|
||||
);
|
||||
|
||||
return {
|
||||
user: await createUser({
|
||||
mfaEnabled: true,
|
||||
password,
|
||||
email,
|
||||
mfaSecret: encryptedSecret,
|
||||
mfaRecoveryCodes: encryptedRecoveryCodes,
|
||||
}),
|
||||
rawPassword: password,
|
||||
rawSecret: secret,
|
||||
rawRecoveryCodes: recoveryCodes,
|
||||
};
|
||||
}
|
||||
|
||||
export async function createOwner() {
|
||||
return createUser({ globalRole: await getGlobalOwnerRole() });
|
||||
}
|
||||
|
||||
export async function createMember() {
|
||||
return createUser({ globalRole: await getGlobalMemberRole() });
|
||||
}
|
||||
|
||||
export async function createUserShell(globalRole: Role): Promise<User> {
|
||||
if (globalRole.scope !== 'global') {
|
||||
throw new Error(`Invalid role received: ${JSON.stringify(globalRole)}`);
|
||||
}
|
||||
|
||||
const shell: Partial<User> = { globalRoleId: globalRole.id };
|
||||
|
||||
if (globalRole.name !== 'owner') {
|
||||
shell.email = randomEmail();
|
||||
}
|
||||
|
||||
return Container.get(UserRepository).save(shell);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create many users in the DB, defaulting to a `member`.
|
||||
*/
|
||||
export async function createManyUsers(
|
||||
amount: number,
|
||||
attributes: Partial<User> = {},
|
||||
): Promise<User[]> {
|
||||
let { email, password, firstName, lastName, globalRole, ...rest } = attributes;
|
||||
if (!globalRole) {
|
||||
globalRole = await getGlobalMemberRole();
|
||||
}
|
||||
|
||||
const users = await Promise.all(
|
||||
[...Array(amount)].map(async () =>
|
||||
Container.get(UserRepository).create({
|
||||
email: email ?? randomEmail(),
|
||||
password: await hash(password ?? randomValidPassword(), 10),
|
||||
firstName: firstName ?? randomName(),
|
||||
lastName: lastName ?? randomName(),
|
||||
globalRole,
|
||||
...rest,
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
return Container.get(UserRepository).save(users);
|
||||
}
|
||||
|
||||
export async function addApiKey(user: User): Promise<User> {
|
||||
user.apiKey = randomApiKey();
|
||||
return Container.get(UserRepository).save(user);
|
||||
}
|
||||
|
||||
export const getAllUsers = async () =>
|
||||
Container.get(UserRepository).find({
|
||||
relations: ['globalRole', 'authIdentities'],
|
||||
});
|
||||
|
||||
export const getLdapIdentities = async () =>
|
||||
Container.get(AuthIdentityRepository).find({
|
||||
where: { providerType: 'ldap' },
|
||||
relations: ['user'],
|
||||
});
|
43
packages/cli/test/integration/shared/db/workflowHistory.ts
Normal file
43
packages/cli/test/integration/shared/db/workflowHistory.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
import Container from 'typedi';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import type { WorkflowHistory } from '@db/entities/WorkflowHistory';
|
||||
import { WorkflowHistoryRepository } from '@db/repositories';
|
||||
|
||||
export async function createWorkflowHistoryItem(
|
||||
workflowId: string,
|
||||
data?: Partial<WorkflowHistory>,
|
||||
) {
|
||||
return Container.get(WorkflowHistoryRepository).save({
|
||||
authors: 'John Smith',
|
||||
connections: {},
|
||||
nodes: [
|
||||
{
|
||||
id: 'uuid-1234',
|
||||
name: 'Start',
|
||||
parameters: {},
|
||||
position: [-20, 260],
|
||||
type: 'n8n-nodes-base.start',
|
||||
typeVersion: 1,
|
||||
},
|
||||
],
|
||||
versionId: uuid(),
|
||||
...(data ?? {}),
|
||||
workflowId,
|
||||
});
|
||||
}
|
||||
|
||||
export async function createManyWorkflowHistoryItems(
|
||||
workflowId: string,
|
||||
count: number,
|
||||
time?: Date,
|
||||
) {
|
||||
const baseTime = (time ?? new Date()).valueOf();
|
||||
return Promise.all(
|
||||
[...Array(count)].map(async (_, i) =>
|
||||
createWorkflowHistoryItem(workflowId, {
|
||||
createdAt: new Date(baseTime + i),
|
||||
updatedAt: new Date(baseTime + i),
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
118
packages/cli/test/integration/shared/db/workflows.ts
Normal file
118
packages/cli/test/integration/shared/db/workflows.ts
Normal file
|
@ -0,0 +1,118 @@
|
|||
import Container from 'typedi';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import { SharedWorkflowRepository, WorkflowRepository } from '@db/repositories';
|
||||
import { getWorkflowEditorRole, getWorkflowOwnerRole } from './roles';
|
||||
|
||||
export async function createManyWorkflows(
|
||||
amount: number,
|
||||
attributes: Partial<WorkflowEntity> = {},
|
||||
user?: User,
|
||||
) {
|
||||
const workflowRequests = [...Array(amount)].map(async (_) => createWorkflow(attributes, user));
|
||||
return Promise.all(workflowRequests);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a workflow in the DB (without a trigger) and optionally assign it to a user.
|
||||
* @param attributes workflow attributes
|
||||
* @param user user to assign the workflow to
|
||||
*/
|
||||
export async function createWorkflow(attributes: Partial<WorkflowEntity> = {}, user?: User) {
|
||||
const { active, name, nodes, connections, versionId } = attributes;
|
||||
|
||||
const workflowEntity = Container.get(WorkflowRepository).create({
|
||||
active: active ?? false,
|
||||
name: name ?? 'test workflow',
|
||||
nodes: nodes ?? [
|
||||
{
|
||||
id: 'uuid-1234',
|
||||
name: 'Schedule Trigger',
|
||||
parameters: {},
|
||||
position: [-20, 260],
|
||||
type: 'n8n-nodes-base.scheduleTrigger',
|
||||
typeVersion: 1,
|
||||
},
|
||||
],
|
||||
connections: connections ?? {},
|
||||
versionId: versionId ?? uuid(),
|
||||
...attributes,
|
||||
});
|
||||
|
||||
const workflow = await Container.get(WorkflowRepository).save(workflowEntity);
|
||||
|
||||
if (user) {
|
||||
await Container.get(SharedWorkflowRepository).save({
|
||||
user,
|
||||
workflow,
|
||||
role: await getWorkflowOwnerRole(),
|
||||
});
|
||||
}
|
||||
return workflow;
|
||||
}
|
||||
|
||||
export async function shareWorkflowWithUsers(workflow: WorkflowEntity, users: User[]) {
|
||||
const role = await getWorkflowEditorRole();
|
||||
const sharedWorkflows = users.map((user) => ({
|
||||
user,
|
||||
workflow,
|
||||
role,
|
||||
}));
|
||||
return Container.get(SharedWorkflowRepository).save(sharedWorkflows);
|
||||
}
|
||||
|
||||
export async function getWorkflowSharing(workflow: WorkflowEntity) {
|
||||
return Container.get(SharedWorkflowRepository).findBy({
|
||||
workflowId: workflow.id,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a workflow in the DB (with a trigger) and optionally assign it to a user.
|
||||
* @param user user to assign the workflow to
|
||||
*/
|
||||
export async function createWorkflowWithTrigger(
|
||||
attributes: Partial<WorkflowEntity> = {},
|
||||
user?: User,
|
||||
) {
|
||||
const workflow = await createWorkflow(
|
||||
{
|
||||
nodes: [
|
||||
{
|
||||
id: 'uuid-1',
|
||||
parameters: {},
|
||||
name: 'Start',
|
||||
type: 'n8n-nodes-base.start',
|
||||
typeVersion: 1,
|
||||
position: [240, 300],
|
||||
},
|
||||
{
|
||||
id: 'uuid-2',
|
||||
parameters: { triggerTimes: { item: [{ mode: 'everyMinute' }] } },
|
||||
name: 'Cron',
|
||||
type: 'n8n-nodes-base.cron',
|
||||
typeVersion: 1,
|
||||
position: [500, 300],
|
||||
},
|
||||
{
|
||||
id: 'uuid-3',
|
||||
parameters: { options: {} },
|
||||
name: 'Set',
|
||||
type: 'n8n-nodes-base.set',
|
||||
typeVersion: 1,
|
||||
position: [780, 300],
|
||||
},
|
||||
],
|
||||
connections: { Cron: { main: [[{ node: 'Set', type: 'main', index: 0 }]] } },
|
||||
...attributes,
|
||||
},
|
||||
user,
|
||||
);
|
||||
|
||||
return workflow;
|
||||
}
|
||||
|
||||
export async function getAllWorkflows() {
|
||||
return Container.get(WorkflowRepository).find();
|
||||
}
|
|
@ -1,42 +1,19 @@
|
|||
import type { DataSourceOptions as ConnectionOptions, Repository } from 'typeorm';
|
||||
import { DataSource as Connection } from 'typeorm';
|
||||
import { Container } from 'typedi';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import config from '@/config';
|
||||
import * as Db from '@/Db';
|
||||
import { createCredentialsFromCredentialsEntity } from '@/CredentialsHelper';
|
||||
import { entities } from '@db/entities';
|
||||
import { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||
import { mysqlMigrations } from '@db/migrations/mysqldb';
|
||||
import { postgresMigrations } from '@db/migrations/postgresdb';
|
||||
import { sqliteMigrations } from '@db/migrations/sqlite';
|
||||
import { hashPassword } from '@/UserManagement/UserManagementHelper';
|
||||
import { AuthIdentity } from '@db/entities/AuthIdentity';
|
||||
import type { ExecutionEntity } from '@db/entities/ExecutionEntity';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
import type { TagEntity } from '@db/entities/TagEntity';
|
||||
import type { User } from '@db/entities/User';
|
||||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import type { ICredentialsDb } from '@/Interfaces';
|
||||
import { DB_INITIALIZATION_TIMEOUT } from './constants';
|
||||
import { randomApiKey, randomEmail, randomName, randomString, randomValidPassword } from './random';
|
||||
import type { CollectionName, CredentialPayload, PostgresSchemaSection } from './types';
|
||||
import type { ExecutionData } from '@db/entities/ExecutionData';
|
||||
import { generateNanoId } from '@db/utils/generators';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { VariablesService } from '@/environments/variables/variables.service';
|
||||
import {
|
||||
TagRepository,
|
||||
WorkflowHistoryRepository,
|
||||
WorkflowTagMappingRepository,
|
||||
} from '@/databases/repositories';
|
||||
import { separate } from '@/utils';
|
||||
import { TagRepository, WorkflowTagMappingRepository } from '@/databases/repositories';
|
||||
|
||||
import { randomPassword } from '@/Ldap/helpers';
|
||||
import { TOTPService } from '@/Mfa/totp.service';
|
||||
import { MfaService } from '@/Mfa/mfa.service';
|
||||
import type { WorkflowHistory } from '@/databases/entities/WorkflowHistory';
|
||||
import { DB_INITIALIZATION_TIMEOUT } from './constants';
|
||||
import { randomString } from './random';
|
||||
import type { CollectionName, PostgresSchemaSection } from './types';
|
||||
import { separate } from '@/utils';
|
||||
|
||||
export type TestDBType = 'postgres' | 'mysql';
|
||||
|
||||
|
@ -132,503 +109,6 @@ export async function truncate(collections: CollectionName[]) {
|
|||
}
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// credential creation
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* Save a credential to the test DB, sharing it with a user.
|
||||
*/
|
||||
export async function saveCredential(
|
||||
credentialPayload: CredentialPayload,
|
||||
{ user, role }: { user: User; role: Role },
|
||||
) {
|
||||
const newCredential = new CredentialsEntity();
|
||||
|
||||
Object.assign(newCredential, credentialPayload);
|
||||
|
||||
const encryptedData = await encryptCredentialData(newCredential);
|
||||
|
||||
Object.assign(newCredential, encryptedData);
|
||||
|
||||
const savedCredential = await Db.collections.Credentials.save(newCredential);
|
||||
|
||||
savedCredential.data = newCredential.data;
|
||||
|
||||
await Db.collections.SharedCredentials.save({
|
||||
user,
|
||||
credentials: savedCredential,
|
||||
role,
|
||||
});
|
||||
|
||||
return savedCredential;
|
||||
}
|
||||
|
||||
export async function shareCredentialWithUsers(credential: CredentialsEntity, users: User[]) {
|
||||
const role = await Container.get(RoleService).findCredentialUserRole();
|
||||
const newSharedCredentials = users.map((user) =>
|
||||
Db.collections.SharedCredentials.create({
|
||||
userId: user.id,
|
||||
credentialsId: credential.id,
|
||||
roleId: role?.id,
|
||||
}),
|
||||
);
|
||||
return Db.collections.SharedCredentials.save(newSharedCredentials);
|
||||
}
|
||||
|
||||
export function affixRoleToSaveCredential(role: Role) {
|
||||
return async (credentialPayload: CredentialPayload, { user }: { user: User }) =>
|
||||
saveCredential(credentialPayload, { user, role });
|
||||
}
|
||||
|
||||
export async function getAllCredentials() {
|
||||
return Db.collections.Credentials.find();
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// user creation
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* Store a user in the DB, defaulting to a `member`.
|
||||
*/
|
||||
export async function createUser(attributes: Partial<User> = {}): Promise<User> {
|
||||
const { email, password, firstName, lastName, globalRole, ...rest } = attributes;
|
||||
const user: Partial<User> = {
|
||||
email: email ?? randomEmail(),
|
||||
password: await hashPassword(password ?? randomValidPassword()),
|
||||
firstName: firstName ?? randomName(),
|
||||
lastName: lastName ?? randomName(),
|
||||
globalRoleId: (globalRole ?? (await getGlobalMemberRole())).id,
|
||||
globalRole,
|
||||
...rest,
|
||||
};
|
||||
|
||||
return Db.collections.User.save(user);
|
||||
}
|
||||
|
||||
export async function createLdapUser(attributes: Partial<User>, ldapId: string): Promise<User> {
|
||||
const user = await createUser(attributes);
|
||||
await Db.collections.AuthIdentity.save(AuthIdentity.create(user, ldapId, 'ldap'));
|
||||
return user;
|
||||
}
|
||||
|
||||
export async function createUserWithMfaEnabled(
|
||||
data: { numberOfRecoveryCodes: number } = { numberOfRecoveryCodes: 10 },
|
||||
) {
|
||||
const email = randomEmail();
|
||||
const password = randomPassword();
|
||||
|
||||
const toptService = new TOTPService();
|
||||
|
||||
const secret = toptService.generateSecret();
|
||||
|
||||
const mfaService = Container.get(MfaService);
|
||||
|
||||
const recoveryCodes = mfaService.generateRecoveryCodes(data.numberOfRecoveryCodes);
|
||||
|
||||
const { encryptedSecret, encryptedRecoveryCodes } = mfaService.encryptSecretAndRecoveryCodes(
|
||||
secret,
|
||||
recoveryCodes,
|
||||
);
|
||||
|
||||
return {
|
||||
user: await createUser({
|
||||
mfaEnabled: true,
|
||||
password,
|
||||
email,
|
||||
mfaSecret: encryptedSecret,
|
||||
mfaRecoveryCodes: encryptedRecoveryCodes,
|
||||
}),
|
||||
rawPassword: password,
|
||||
rawSecret: secret,
|
||||
rawRecoveryCodes: recoveryCodes,
|
||||
};
|
||||
}
|
||||
|
||||
export async function createOwner() {
|
||||
return createUser({ globalRole: await getGlobalOwnerRole() });
|
||||
}
|
||||
|
||||
export async function createMember() {
|
||||
return createUser({ globalRole: await getGlobalMemberRole() });
|
||||
}
|
||||
|
||||
export async function createUserShell(globalRole: Role): Promise<User> {
|
||||
if (globalRole.scope !== 'global') {
|
||||
throw new Error(`Invalid role received: ${JSON.stringify(globalRole)}`);
|
||||
}
|
||||
|
||||
const shell: Partial<User> = { globalRoleId: globalRole.id };
|
||||
|
||||
if (globalRole.name !== 'owner') {
|
||||
shell.email = randomEmail();
|
||||
}
|
||||
|
||||
return Db.collections.User.save(shell);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create many users in the DB, defaulting to a `member`.
|
||||
*/
|
||||
export async function createManyUsers(
|
||||
amount: number,
|
||||
attributes: Partial<User> = {},
|
||||
): Promise<User[]> {
|
||||
let { email, password, firstName, lastName, globalRole, ...rest } = attributes;
|
||||
if (!globalRole) {
|
||||
globalRole = await getGlobalMemberRole();
|
||||
}
|
||||
|
||||
const users = await Promise.all(
|
||||
[...Array(amount)].map(async () =>
|
||||
Db.collections.User.create({
|
||||
email: email ?? randomEmail(),
|
||||
password: await hashPassword(password ?? randomValidPassword()),
|
||||
firstName: firstName ?? randomName(),
|
||||
lastName: lastName ?? randomName(),
|
||||
globalRole,
|
||||
...rest,
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
return Db.collections.User.save(users);
|
||||
}
|
||||
|
||||
export async function addApiKey(user: User): Promise<User> {
|
||||
user.apiKey = randomApiKey();
|
||||
return Db.collections.User.save(user);
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// role fetchers
|
||||
// ----------------------------------
|
||||
|
||||
export async function getGlobalOwnerRole() {
|
||||
return Container.get(RoleService).findGlobalOwnerRole();
|
||||
}
|
||||
|
||||
export async function getGlobalMemberRole() {
|
||||
return Container.get(RoleService).findGlobalMemberRole();
|
||||
}
|
||||
|
||||
export async function getWorkflowOwnerRole() {
|
||||
return Container.get(RoleService).findWorkflowOwnerRole();
|
||||
}
|
||||
|
||||
export async function getWorkflowEditorRole() {
|
||||
return Container.get(RoleService).findWorkflowEditorRole();
|
||||
}
|
||||
|
||||
export async function getCredentialOwnerRole() {
|
||||
return Container.get(RoleService).findCredentialOwnerRole();
|
||||
}
|
||||
|
||||
export async function getAllRoles() {
|
||||
return Promise.all([
|
||||
getGlobalOwnerRole(),
|
||||
getGlobalMemberRole(),
|
||||
getWorkflowOwnerRole(),
|
||||
getCredentialOwnerRole(),
|
||||
]);
|
||||
}
|
||||
|
||||
export const getAllUsers = async () =>
|
||||
Db.collections.User.find({
|
||||
relations: ['globalRole', 'authIdentities'],
|
||||
});
|
||||
|
||||
export const getLdapIdentities = async () =>
|
||||
Db.collections.AuthIdentity.find({
|
||||
where: { providerType: 'ldap' },
|
||||
relations: ['user'],
|
||||
});
|
||||
|
||||
// ----------------------------------
|
||||
// Execution helpers
|
||||
// ----------------------------------
|
||||
|
||||
export async function createManyExecutions(
|
||||
amount: number,
|
||||
workflow: WorkflowEntity,
|
||||
callback: (workflow: WorkflowEntity) => Promise<ExecutionEntity>,
|
||||
) {
|
||||
const executionsRequests = [...Array(amount)].map(async (_) => callback(workflow));
|
||||
return Promise.all(executionsRequests);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a execution in the DB and assign it to a workflow.
|
||||
*/
|
||||
export async function createExecution(
|
||||
attributes: Partial<ExecutionEntity & ExecutionData>,
|
||||
workflow: WorkflowEntity,
|
||||
) {
|
||||
const { data, finished, mode, startedAt, stoppedAt, waitTill, status, deletedAt } = attributes;
|
||||
|
||||
const execution = await Db.collections.Execution.save({
|
||||
finished: finished ?? true,
|
||||
mode: mode ?? 'manual',
|
||||
startedAt: startedAt ?? new Date(),
|
||||
...(workflow !== undefined && { workflowId: workflow.id }),
|
||||
stoppedAt: stoppedAt ?? new Date(),
|
||||
waitTill: waitTill ?? null,
|
||||
status,
|
||||
deletedAt,
|
||||
});
|
||||
|
||||
await Db.collections.ExecutionData.save({
|
||||
data: data ?? '[]',
|
||||
workflowData: workflow ?? {},
|
||||
executionId: execution.id,
|
||||
});
|
||||
|
||||
return execution;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a successful execution in the DB and assign it to a workflow.
|
||||
*/
|
||||
export async function createSuccessfulExecution(workflow: WorkflowEntity) {
|
||||
return createExecution({ finished: true, status: 'success' }, workflow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store an error execution in the DB and assign it to a workflow.
|
||||
*/
|
||||
export async function createErrorExecution(workflow: WorkflowEntity) {
|
||||
return createExecution({ finished: false, stoppedAt: new Date(), status: 'failed' }, workflow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a waiting execution in the DB and assign it to a workflow.
|
||||
*/
|
||||
export async function createWaitingExecution(workflow: WorkflowEntity) {
|
||||
return createExecution({ finished: false, waitTill: new Date(), status: 'waiting' }, workflow);
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// Tags
|
||||
// ----------------------------------
|
||||
|
||||
export async function createTag(attributes: Partial<TagEntity> = {}, workflow?: WorkflowEntity) {
|
||||
const { name } = attributes;
|
||||
|
||||
const tag = await Container.get(TagRepository).save({
|
||||
id: generateNanoId(),
|
||||
name: name ?? randomName(),
|
||||
...attributes,
|
||||
});
|
||||
|
||||
if (workflow) {
|
||||
const mappingRepository = Container.get(WorkflowTagMappingRepository);
|
||||
|
||||
const mapping = mappingRepository.create({ tagId: tag.id, workflowId: workflow.id });
|
||||
|
||||
await mappingRepository.save(mapping);
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// Workflow helpers
|
||||
// ----------------------------------
|
||||
|
||||
export async function createManyWorkflows(
|
||||
amount: number,
|
||||
attributes: Partial<WorkflowEntity> = {},
|
||||
user?: User,
|
||||
) {
|
||||
const workflowRequests = [...Array(amount)].map(async (_) => createWorkflow(attributes, user));
|
||||
return Promise.all(workflowRequests);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a workflow in the DB (without a trigger) and optionally assign it to a user.
|
||||
* @param attributes workflow attributes
|
||||
* @param user user to assign the workflow to
|
||||
*/
|
||||
export async function createWorkflow(attributes: Partial<WorkflowEntity> = {}, user?: User) {
|
||||
const { active, name, nodes, connections, versionId } = attributes;
|
||||
|
||||
const workflowEntity = Db.collections.Workflow.create({
|
||||
active: active ?? false,
|
||||
name: name ?? 'test workflow',
|
||||
nodes: nodes ?? [
|
||||
{
|
||||
id: 'uuid-1234',
|
||||
name: 'Schedule Trigger',
|
||||
parameters: {},
|
||||
position: [-20, 260],
|
||||
type: 'n8n-nodes-base.scheduleTrigger',
|
||||
typeVersion: 1,
|
||||
},
|
||||
],
|
||||
connections: connections ?? {},
|
||||
versionId: versionId ?? uuid(),
|
||||
...attributes,
|
||||
});
|
||||
|
||||
const workflow = await Db.collections.Workflow.save(workflowEntity);
|
||||
|
||||
if (user) {
|
||||
await Db.collections.SharedWorkflow.save({
|
||||
user,
|
||||
workflow,
|
||||
role: await getWorkflowOwnerRole(),
|
||||
});
|
||||
}
|
||||
return workflow;
|
||||
}
|
||||
|
||||
export async function shareWorkflowWithUsers(workflow: WorkflowEntity, users: User[]) {
|
||||
const role = await getWorkflowEditorRole();
|
||||
const sharedWorkflows = users.map((user) => ({
|
||||
user,
|
||||
workflow,
|
||||
role,
|
||||
}));
|
||||
return Db.collections.SharedWorkflow.save(sharedWorkflows);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a workflow in the DB (with a trigger) and optionally assign it to a user.
|
||||
* @param user user to assign the workflow to
|
||||
*/
|
||||
export async function createWorkflowWithTrigger(
|
||||
attributes: Partial<WorkflowEntity> = {},
|
||||
user?: User,
|
||||
) {
|
||||
const workflow = await createWorkflow(
|
||||
{
|
||||
nodes: [
|
||||
{
|
||||
id: 'uuid-1',
|
||||
parameters: {},
|
||||
name: 'Start',
|
||||
type: 'n8n-nodes-base.start',
|
||||
typeVersion: 1,
|
||||
position: [240, 300],
|
||||
},
|
||||
{
|
||||
id: 'uuid-2',
|
||||
parameters: { triggerTimes: { item: [{ mode: 'everyMinute' }] } },
|
||||
name: 'Cron',
|
||||
type: 'n8n-nodes-base.cron',
|
||||
typeVersion: 1,
|
||||
position: [500, 300],
|
||||
},
|
||||
{
|
||||
id: 'uuid-3',
|
||||
parameters: { options: {} },
|
||||
name: 'Set',
|
||||
type: 'n8n-nodes-base.set',
|
||||
typeVersion: 1,
|
||||
position: [780, 300],
|
||||
},
|
||||
],
|
||||
connections: { Cron: { main: [[{ node: 'Set', type: 'main', index: 0 }]] } },
|
||||
...attributes,
|
||||
},
|
||||
user,
|
||||
);
|
||||
|
||||
return workflow;
|
||||
}
|
||||
|
||||
export async function getAllWorkflows() {
|
||||
return Db.collections.Workflow.find();
|
||||
}
|
||||
|
||||
export async function getAllExecutions() {
|
||||
return Db.collections.Execution.find();
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// workflow sharing
|
||||
// ----------------------------------
|
||||
|
||||
export async function getWorkflowSharing(workflow: WorkflowEntity) {
|
||||
return Db.collections.SharedWorkflow.findBy({
|
||||
workflowId: workflow.id,
|
||||
});
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// variables
|
||||
// ----------------------------------
|
||||
|
||||
export async function createVariable(key: string, value: string) {
|
||||
const result = await Db.collections.Variables.save({
|
||||
id: generateNanoId(),
|
||||
key,
|
||||
value,
|
||||
});
|
||||
await Container.get(VariablesService).updateCache();
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function getVariableByKey(key: string) {
|
||||
return Db.collections.Variables.findOne({
|
||||
where: {
|
||||
key,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function getVariableById(id: string) {
|
||||
return Db.collections.Variables.findOne({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// workflow history
|
||||
// ----------------------------------
|
||||
|
||||
export async function createWorkflowHistoryItem(
|
||||
workflowId: string,
|
||||
data?: Partial<WorkflowHistory>,
|
||||
) {
|
||||
return Container.get(WorkflowHistoryRepository).save({
|
||||
authors: 'John Smith',
|
||||
connections: {},
|
||||
nodes: [
|
||||
{
|
||||
id: 'uuid-1234',
|
||||
name: 'Start',
|
||||
parameters: {},
|
||||
position: [-20, 260],
|
||||
type: 'n8n-nodes-base.start',
|
||||
typeVersion: 1,
|
||||
},
|
||||
],
|
||||
versionId: uuid(),
|
||||
...(data ?? {}),
|
||||
workflowId,
|
||||
});
|
||||
}
|
||||
|
||||
export async function createManyWorkflowHistoryItems(
|
||||
workflowId: string,
|
||||
count: number,
|
||||
time?: Date,
|
||||
) {
|
||||
const baseTime = (time ?? new Date()).valueOf();
|
||||
return Promise.all(
|
||||
[...Array(count)].map(async (_, i) =>
|
||||
createWorkflowHistoryItem(workflowId, {
|
||||
createdAt: new Date(baseTime + i),
|
||||
updatedAt: new Date(baseTime + i),
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// connection options
|
||||
// ----------------------------------
|
||||
|
@ -683,16 +163,3 @@ const getDBOptions = (type: TestDBType, name: string) => ({
|
|||
synchronize: false,
|
||||
logging: false,
|
||||
});
|
||||
|
||||
// ----------------------------------
|
||||
// encryption
|
||||
// ----------------------------------
|
||||
|
||||
async function encryptCredentialData(credential: CredentialsEntity) {
|
||||
const coreCredential = createCredentialsFromCredentialsEntity(credential, true);
|
||||
|
||||
// @ts-ignore
|
||||
coreCredential.setData(credential.data);
|
||||
|
||||
return coreCredential.getDataToSave() as ICredentialsDb;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ export type CollectionName =
|
|||
| keyof IDatabaseCollections
|
||||
| { new (dataSource: DataSource): Repository<any> };
|
||||
|
||||
export type EndpointGroup =
|
||||
type EndpointGroup =
|
||||
| 'me'
|
||||
| 'users'
|
||||
| 'auth'
|
||||
|
|
|
@ -12,7 +12,6 @@ import { v4 as uuid } from 'uuid';
|
|||
import config from '@/config';
|
||||
import * as Db from '@/Db';
|
||||
import { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||
import { AUTH_COOKIE_NAME } from '@/constants';
|
||||
|
||||
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
|
||||
|
@ -29,7 +28,8 @@ export { setupTestServer } from './testServer';
|
|||
/**
|
||||
* Initialize node types.
|
||||
*/
|
||||
export async function initActiveWorkflowRunner(): Promise<ActiveWorkflowRunner> {
|
||||
export async function initActiveWorkflowRunner() {
|
||||
const { ActiveWorkflowRunner } = await import('@/ActiveWorkflowRunner');
|
||||
const workflowRunner = Container.get(ActiveWorkflowRunner);
|
||||
await workflowRunner.init();
|
||||
return workflowRunner;
|
||||
|
|
|
@ -6,61 +6,27 @@ import request from 'supertest';
|
|||
import { URL } from 'url';
|
||||
|
||||
import config from '@/config';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||
import { workflowsController } from '@/workflows/workflows.controller';
|
||||
import { AUTH_COOKIE_NAME } from '@/constants';
|
||||
import { credentialsController } from '@/credentials/credentials.controller';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { loadPublicApiVersions } from '@/PublicApi/';
|
||||
import { issueJWT } from '@/auth/jwt';
|
||||
import { UserManagementMailer } from '@/UserManagement/email/UserManagementMailer';
|
||||
import { licenseController } from '@/license/license.controller';
|
||||
import { registerController } from '@/decorators';
|
||||
import {
|
||||
AuthController,
|
||||
LdapController,
|
||||
MFAController,
|
||||
MeController,
|
||||
OwnerController,
|
||||
PasswordResetController,
|
||||
TagsController,
|
||||
UsersController,
|
||||
} from '@/controllers';
|
||||
import { rawBodyReader, bodyParser, setupAuthMiddlewares } from '@/middlewares';
|
||||
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { variablesController } from '@/environments/variables/variables.controller';
|
||||
import { LdapManager } from '@/Ldap/LdapManager.ee';
|
||||
import { handleLdapInit } from '@/Ldap/helpers';
|
||||
import { setSamlLoginEnabled } from '@/sso/saml/samlHelpers';
|
||||
import { SamlController } from '@/sso/saml/routes/saml.controller.ee';
|
||||
import { EventBusController } from '@/eventbus/eventBus.controller';
|
||||
import { EventBusControllerEE } from '@/eventbus/eventBus.controller.ee';
|
||||
import { License } from '@/License';
|
||||
import { SourceControlController } from '@/environments/sourceControl/sourceControl.controller.ee';
|
||||
|
||||
import * as testDb from '../../shared/testDb';
|
||||
import { AUTHLESS_ENDPOINTS, PUBLIC_API_REST_PATH_SEGMENT, REST_PATH_SEGMENT } from '../constants';
|
||||
import type { EndpointGroup, SetupProps, TestServer } from '../types';
|
||||
import { mockInstance } from './mocking';
|
||||
import { ExternalSecretsController } from '@/ExternalSecrets/ExternalSecrets.controller.ee';
|
||||
import { MfaService } from '@/Mfa/mfa.service';
|
||||
import { MetricsService } from '@/services/metrics.service';
|
||||
import {
|
||||
SettingsRepository,
|
||||
SharedCredentialsRepository,
|
||||
SharedWorkflowRepository,
|
||||
} from '@/databases/repositories';
|
||||
import { JwtService } from '@/services/jwt.service';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { UserService } from '@/services/user.service';
|
||||
import { executionsController } from '@/executions/executions.controller';
|
||||
import { WorkflowHistoryController } from '@/workflows/workflowHistory/workflowHistory.controller.ee';
|
||||
import { BinaryDataController } from '@/controllers/binaryData.controller';
|
||||
import { Logger } from '@/Logger';
|
||||
|
||||
import * as testDb from '../../shared/testDb';
|
||||
import { AUTHLESS_ENDPOINTS, PUBLIC_API_REST_PATH_SEGMENT, REST_PATH_SEGMENT } from '../constants';
|
||||
import type { SetupProps, TestServer } from '../types';
|
||||
import { mockInstance } from './mocking';
|
||||
|
||||
/**
|
||||
* Plugin to prefix a path segment into a request URL pathname.
|
||||
*
|
||||
|
@ -81,30 +47,6 @@ function prefix(pathSegment: string) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Classify endpoint groups into `routerEndpoints` (newest, using `express.Router`),
|
||||
* and `functionEndpoints` (legacy, namespaced inside a function).
|
||||
*/
|
||||
const classifyEndpointGroups = (endpointGroups: EndpointGroup[]) => {
|
||||
const routerEndpoints: EndpointGroup[] = [];
|
||||
const functionEndpoints: EndpointGroup[] = [];
|
||||
|
||||
const ROUTER_GROUP = [
|
||||
'credentials',
|
||||
'workflows',
|
||||
'publicApi',
|
||||
'license',
|
||||
'variables',
|
||||
'executions',
|
||||
];
|
||||
|
||||
endpointGroups.forEach((group) =>
|
||||
(ROUTER_GROUP.includes(group) ? routerEndpoints : functionEndpoints).push(group),
|
||||
);
|
||||
|
||||
return [routerEndpoints, functionEndpoints];
|
||||
};
|
||||
|
||||
function createAgent(app: express.Application, options?: { auth: boolean; user: User }) {
|
||||
const agent = request.agent(app);
|
||||
void agent.use(prefix(REST_PATH_SEGMENT));
|
||||
|
@ -168,118 +110,177 @@ export const setupTestServer = ({
|
|||
|
||||
app.use(bodyParser);
|
||||
|
||||
const [routerEndpoints, functionEndpoints] = classifyEndpointGroups(endpointGroups);
|
||||
|
||||
if (routerEndpoints.length) {
|
||||
const map: Record<string, express.Router | express.Router[] | any> = {
|
||||
credentials: { controller: credentialsController, path: 'credentials' },
|
||||
workflows: { controller: workflowsController, path: 'workflows' },
|
||||
license: { controller: licenseController, path: 'license' },
|
||||
variables: { controller: variablesController, path: 'variables' },
|
||||
executions: { controller: executionsController, path: 'executions' },
|
||||
};
|
||||
|
||||
if (enablePublicAPI) {
|
||||
const { apiRouters } = await loadPublicApiVersions(PUBLIC_API_REST_PATH_SEGMENT);
|
||||
map.publicApi = apiRouters;
|
||||
}
|
||||
|
||||
for (const group of routerEndpoints) {
|
||||
if (group === 'publicApi') {
|
||||
app.use(...(map[group] as express.Router[]));
|
||||
} else {
|
||||
app.use(`/${REST_PATH_SEGMENT}/${map[group].path}`, map[group].controller);
|
||||
}
|
||||
}
|
||||
if (enablePublicAPI) {
|
||||
const { loadPublicApiVersions } = await import('@/PublicApi');
|
||||
const { apiRouters } = await loadPublicApiVersions(PUBLIC_API_REST_PATH_SEGMENT);
|
||||
app.use(...apiRouters);
|
||||
}
|
||||
|
||||
if (functionEndpoints.length) {
|
||||
const externalHooks = Container.get(ExternalHooks);
|
||||
const internalHooks = Container.get(InternalHooks);
|
||||
const mailer = Container.get(UserManagementMailer);
|
||||
const mfaService = Container.get(MfaService);
|
||||
const userService = Container.get(UserService);
|
||||
|
||||
for (const group of functionEndpoints) {
|
||||
if (endpointGroups.length) {
|
||||
for (const group of endpointGroups) {
|
||||
switch (group) {
|
||||
case 'credentials':
|
||||
const { credentialsController } = await import('@/credentials/credentials.controller');
|
||||
app.use(`/${REST_PATH_SEGMENT}/credentials`, credentialsController);
|
||||
break;
|
||||
|
||||
case 'workflows':
|
||||
const { workflowsController } = await import('@/workflows/workflows.controller');
|
||||
app.use(`/${REST_PATH_SEGMENT}/workflows`, workflowsController);
|
||||
break;
|
||||
|
||||
case 'executions':
|
||||
const { executionsController } = await import('@/executions/executions.controller');
|
||||
app.use(`/${REST_PATH_SEGMENT}/executions`, executionsController);
|
||||
break;
|
||||
|
||||
case 'variables':
|
||||
const { variablesController } = await import(
|
||||
'@/environments/variables/variables.controller'
|
||||
);
|
||||
app.use(`/${REST_PATH_SEGMENT}/variables`, variablesController);
|
||||
break;
|
||||
|
||||
case 'license':
|
||||
const { licenseController } = await import('@/license/license.controller');
|
||||
app.use(`/${REST_PATH_SEGMENT}/license`, licenseController);
|
||||
break;
|
||||
|
||||
case 'metrics':
|
||||
const { MetricsService } = await import('@/services/metrics.service');
|
||||
await Container.get(MetricsService).configureMetrics(app);
|
||||
break;
|
||||
|
||||
case 'eventBus':
|
||||
const { EventBusController } = await import('@/eventbus/eventBus.controller');
|
||||
const { EventBusControllerEE } = await import('@/eventbus/eventBus.controller.ee');
|
||||
registerController(app, config, new EventBusController());
|
||||
registerController(app, config, new EventBusControllerEE());
|
||||
break;
|
||||
|
||||
case 'auth':
|
||||
const { AuthController } = await import('@/controllers/auth.controller');
|
||||
registerController(app, config, Container.get(AuthController));
|
||||
break;
|
||||
|
||||
case 'mfa':
|
||||
registerController(app, config, new MFAController(mfaService));
|
||||
const { MFAController } = await import('@/controllers/mfa.controller');
|
||||
registerController(app, config, Container.get(MFAController));
|
||||
break;
|
||||
|
||||
case 'ldap':
|
||||
const { LdapManager } = await import('@/Ldap/LdapManager.ee');
|
||||
const { handleLdapInit } = await import('@/Ldap/helpers');
|
||||
const { LdapController } = await import('@/controllers/ldap.controller');
|
||||
Container.get(License).isLdapEnabled = () => true;
|
||||
await handleLdapInit();
|
||||
const { service, sync } = LdapManager.getInstance();
|
||||
registerController(app, config, new LdapController(service, sync, internalHooks));
|
||||
registerController(
|
||||
app,
|
||||
config,
|
||||
new LdapController(service, sync, Container.get(InternalHooks)),
|
||||
);
|
||||
break;
|
||||
|
||||
case 'saml':
|
||||
const { setSamlLoginEnabled } = await import('@/sso/saml/samlHelpers');
|
||||
const { SamlController } = await import('@/sso/saml/routes/saml.controller.ee');
|
||||
await setSamlLoginEnabled(true);
|
||||
registerController(app, config, Container.get(SamlController));
|
||||
break;
|
||||
|
||||
case 'sourceControl':
|
||||
const { SourceControlController } = await import(
|
||||
'@/environments/sourceControl/sourceControl.controller.ee'
|
||||
);
|
||||
registerController(app, config, Container.get(SourceControlController));
|
||||
break;
|
||||
|
||||
case 'community-packages':
|
||||
const { CommunityPackagesController } = await import(
|
||||
'@/controllers/communityPackages.controller'
|
||||
);
|
||||
registerController(app, config, Container.get(CommunityPackagesController));
|
||||
break;
|
||||
|
||||
case 'me':
|
||||
const { MeController } = await import('@/controllers/me.controller');
|
||||
registerController(app, config, Container.get(MeController));
|
||||
break;
|
||||
|
||||
case 'passwordReset':
|
||||
const { PasswordResetController } = await import(
|
||||
'@/controllers/passwordReset.controller'
|
||||
);
|
||||
registerController(app, config, Container.get(PasswordResetController));
|
||||
break;
|
||||
|
||||
case 'owner':
|
||||
const { UserService } = await import('@/services/user.service');
|
||||
const { OwnerController } = await import('@/controllers/owner.controller');
|
||||
registerController(
|
||||
app,
|
||||
config,
|
||||
new OwnerController(
|
||||
config,
|
||||
logger,
|
||||
internalHooks,
|
||||
Container.get(InternalHooks),
|
||||
Container.get(SettingsRepository),
|
||||
userService,
|
||||
Container.get(UserService),
|
||||
),
|
||||
);
|
||||
break;
|
||||
|
||||
case 'users':
|
||||
const { ActiveWorkflowRunner } = await import('@/ActiveWorkflowRunner');
|
||||
const { ExternalHooks } = await import('@/ExternalHooks');
|
||||
const { JwtService } = await import('@/services/jwt.service');
|
||||
const { RoleService } = await import('@/services/role.service');
|
||||
const { UserService: US } = await import('@/services/user.service');
|
||||
const { UserManagementMailer } = await import(
|
||||
'@/UserManagement/email/UserManagementMailer'
|
||||
);
|
||||
const { UsersController } = await import('@/controllers/users.controller');
|
||||
registerController(
|
||||
app,
|
||||
config,
|
||||
new UsersController(
|
||||
config,
|
||||
logger,
|
||||
externalHooks,
|
||||
internalHooks,
|
||||
Container.get(ExternalHooks),
|
||||
Container.get(InternalHooks),
|
||||
Container.get(SharedCredentialsRepository),
|
||||
Container.get(SharedWorkflowRepository),
|
||||
Container.get(ActiveWorkflowRunner),
|
||||
mailer,
|
||||
Container.get(UserManagementMailer),
|
||||
Container.get(JwtService),
|
||||
Container.get(RoleService),
|
||||
userService,
|
||||
Container.get(US),
|
||||
),
|
||||
);
|
||||
break;
|
||||
|
||||
case 'tags':
|
||||
const { TagsController } = await import('@/controllers/tags.controller');
|
||||
registerController(app, config, Container.get(TagsController));
|
||||
break;
|
||||
|
||||
case 'externalSecrets':
|
||||
const { ExternalSecretsController } = await import(
|
||||
'@/ExternalSecrets/ExternalSecrets.controller.ee'
|
||||
);
|
||||
registerController(app, config, Container.get(ExternalSecretsController));
|
||||
break;
|
||||
|
||||
case 'workflowHistory':
|
||||
const { WorkflowHistoryController } = await import(
|
||||
'@/workflows/workflowHistory/workflowHistory.controller.ee'
|
||||
);
|
||||
registerController(app, config, Container.get(WorkflowHistoryController));
|
||||
break;
|
||||
|
||||
case 'binaryData':
|
||||
const { BinaryDataController } = await import('@/controllers/binaryData.controller');
|
||||
registerController(app, config, Container.get(BinaryDataController));
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -3,13 +3,15 @@ import * as testDb from './shared/testDb';
|
|||
import type { SuperAgentTest } from 'supertest';
|
||||
import { TagRepository } from '@/databases/repositories';
|
||||
import Container from 'typedi';
|
||||
import { getGlobalOwnerRole } from './shared/db/roles';
|
||||
import { createUserShell } from './shared/db/users';
|
||||
|
||||
let authOwnerAgent: SuperAgentTest;
|
||||
const testServer = utils.setupTestServer({ endpointGroups: ['tags'] });
|
||||
|
||||
beforeAll(async () => {
|
||||
const globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||
const ownerShell = await testDb.createUserShell(globalOwnerRole);
|
||||
const globalOwnerRole = await getGlobalOwnerRole();
|
||||
const ownerShell = await createUserShell(globalOwnerRole);
|
||||
authOwnerAgent = testServer.authAgentFor(ownerShell);
|
||||
});
|
||||
|
||||
|
|
|
@ -20,6 +20,10 @@ import {
|
|||
} from './shared/random';
|
||||
import * as testDb from './shared/testDb';
|
||||
import * as utils from './shared/utils/';
|
||||
import { saveCredential } from './shared/db/credentials';
|
||||
import { getAllRoles } from './shared/db/roles';
|
||||
import { createUser, createUserShell } from './shared/db/users';
|
||||
import { createWorkflow } from './shared/db/workflows';
|
||||
|
||||
let globalMemberRole: Role;
|
||||
let workflowOwnerRole: Role;
|
||||
|
@ -37,13 +41,13 @@ beforeAll(async () => {
|
|||
fetchedGlobalMemberRole,
|
||||
fetchedWorkflowOwnerRole,
|
||||
fetchedCredentialOwnerRole,
|
||||
] = await testDb.getAllRoles();
|
||||
] = await getAllRoles();
|
||||
|
||||
globalMemberRole = fetchedGlobalMemberRole;
|
||||
workflowOwnerRole = fetchedWorkflowOwnerRole;
|
||||
credentialOwnerRole = fetchedCredentialOwnerRole;
|
||||
|
||||
owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
owner = await createUser({ globalRole: globalOwnerRole });
|
||||
|
||||
authOwnerAgent = testServer.authAgentFor(owner);
|
||||
});
|
||||
|
@ -57,7 +61,7 @@ beforeEach(async () => {
|
|||
|
||||
describe('DELETE /users/:id', () => {
|
||||
test('should delete the user', async () => {
|
||||
const userToDelete = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
const userToDelete = await createUser({ globalRole: globalMemberRole });
|
||||
|
||||
const newWorkflow = new WorkflowEntity();
|
||||
|
||||
|
@ -132,7 +136,7 @@ describe('DELETE /users/:id', () => {
|
|||
});
|
||||
|
||||
test('should fail if user to delete is transferee', async () => {
|
||||
const { id: idToDelete } = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
const { id: idToDelete } = await createUser({ globalRole: globalMemberRole });
|
||||
|
||||
const response = await authOwnerAgent.delete(`/users/${idToDelete}`).query({
|
||||
transferId: idToDelete,
|
||||
|
@ -145,11 +149,11 @@ describe('DELETE /users/:id', () => {
|
|||
});
|
||||
|
||||
test('with transferId should perform transfer', async () => {
|
||||
const userToDelete = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
const userToDelete = await createUser({ globalRole: globalMemberRole });
|
||||
|
||||
const savedWorkflow = await testDb.createWorkflow(undefined, userToDelete);
|
||||
const savedWorkflow = await createWorkflow(undefined, userToDelete);
|
||||
|
||||
const savedCredential = await testDb.saveCredential(randomCredentialPayload(), {
|
||||
const savedCredential = await saveCredential(randomCredentialPayload(), {
|
||||
user: userToDelete,
|
||||
role: credentialOwnerRole,
|
||||
});
|
||||
|
@ -184,7 +188,7 @@ describe('DELETE /users/:id', () => {
|
|||
|
||||
describe('POST /users/:id', () => {
|
||||
test('should fill out a user shell', async () => {
|
||||
const memberShell = await testDb.createUserShell(globalMemberRole);
|
||||
const memberShell = await createUserShell(globalMemberRole);
|
||||
|
||||
const memberData = {
|
||||
inviterId: owner.id,
|
||||
|
@ -282,7 +286,7 @@ describe('POST /users/:id', () => {
|
|||
});
|
||||
|
||||
test('should fail with already accepted invite', async () => {
|
||||
const member = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
const member = await createUser({ globalRole: globalMemberRole });
|
||||
|
||||
const newMemberData = {
|
||||
inviterId: owner.id,
|
||||
|
@ -317,8 +321,8 @@ describe('POST /users', () => {
|
|||
});
|
||||
|
||||
test('should email invites and create user shells but ignore existing', async () => {
|
||||
const member = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
const memberShell = await testDb.createUserShell(globalMemberRole);
|
||||
const member = await createUser({ globalRole: globalMemberRole });
|
||||
const memberShell = await createUserShell(globalMemberRole);
|
||||
|
||||
const testEmails = [
|
||||
randomEmail(),
|
||||
|
@ -407,7 +411,7 @@ describe('POST /users/:id/reinvite', () => {
|
|||
|
||||
expect(reinviteResponse.statusCode).toBe(200);
|
||||
|
||||
const member = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
const member = await createUser({ globalRole: globalMemberRole });
|
||||
const reinviteMemberResponse = await authOwnerAgent.post(`/users/${member.id}/reinvite`);
|
||||
|
||||
expect(reinviteMemberResponse.statusCode).toBe(400);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { createMember, createOwner } from './shared/db/users';
|
||||
import * as testDb from './shared/testDb';
|
||||
import { setupTestServer } from './shared/utils/';
|
||||
import type { User } from '@/databases/entities/User';
|
||||
|
@ -12,8 +13,8 @@ let member: User;
|
|||
|
||||
beforeEach(async () => {
|
||||
await testDb.truncate(['User']);
|
||||
owner = await testDb.createOwner();
|
||||
member = await testDb.createMember();
|
||||
owner = await createOwner();
|
||||
member = await createMember();
|
||||
});
|
||||
|
||||
const validatePublicUser = (user: PublicUser) => {
|
||||
|
@ -47,7 +48,7 @@ describe('GET /users', () => {
|
|||
|
||||
describe('filter', () => {
|
||||
test('should filter users by field: email', async () => {
|
||||
const secondMember = await testDb.createMember();
|
||||
const secondMember = await createMember();
|
||||
|
||||
const response = await testServer
|
||||
.authAgentFor(owner)
|
||||
|
@ -71,7 +72,7 @@ describe('GET /users', () => {
|
|||
});
|
||||
|
||||
test('should filter users by field: firstName', async () => {
|
||||
const secondMember = await testDb.createMember();
|
||||
const secondMember = await createMember();
|
||||
|
||||
const response = await testServer
|
||||
.authAgentFor(owner)
|
||||
|
@ -95,7 +96,7 @@ describe('GET /users', () => {
|
|||
});
|
||||
|
||||
test('should filter users by field: lastName', async () => {
|
||||
const secondMember = await testDb.createMember();
|
||||
const secondMember = await createMember();
|
||||
|
||||
const response = await testServer
|
||||
.authAgentFor(owner)
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import Container from 'typedi';
|
||||
import type { SuperAgentTest } from 'supertest';
|
||||
import type { Variables } from '@db/entities/Variables';
|
||||
import { VariablesRepository } from '@db/repositories';
|
||||
import { generateNanoId } from '@db/utils/generators';
|
||||
import { License } from '@/License';
|
||||
import { VariablesService } from '@/environments/variables/variables.service';
|
||||
import * as testDb from './shared/testDb';
|
||||
import * as utils from './shared/utils/';
|
||||
import { createOwner, createUser } from './shared/db/users';
|
||||
|
||||
let authOwnerAgent: SuperAgentTest;
|
||||
let authMemberAgent: SuperAgentTest;
|
||||
|
@ -15,12 +20,38 @@ const licenseLike = {
|
|||
|
||||
const testServer = utils.setupTestServer({ endpointGroups: ['variables'] });
|
||||
|
||||
async function createVariable(key: string, value: string) {
|
||||
const result = await Container.get(VariablesRepository).save({
|
||||
id: generateNanoId(),
|
||||
key,
|
||||
value,
|
||||
});
|
||||
await Container.get(VariablesService).updateCache();
|
||||
return result;
|
||||
}
|
||||
|
||||
async function getVariableByKey(key: string) {
|
||||
return Container.get(VariablesRepository).findOne({
|
||||
where: {
|
||||
key,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function getVariableById(id: string) {
|
||||
return Container.get(VariablesRepository).findOne({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
utils.mockInstance(License, licenseLike);
|
||||
|
||||
const owner = await testDb.createOwner();
|
||||
const owner = await createOwner();
|
||||
authOwnerAgent = testServer.authAgentFor(owner);
|
||||
const member = await testDb.createUser();
|
||||
const member = await createUser();
|
||||
authMemberAgent = testServer.authAgentFor(member);
|
||||
});
|
||||
|
||||
|
@ -35,10 +66,7 @@ beforeEach(async () => {
|
|||
// ----------------------------------------
|
||||
describe('GET /variables', () => {
|
||||
beforeEach(async () => {
|
||||
await Promise.all([
|
||||
testDb.createVariable('test1', 'value1'),
|
||||
testDb.createVariable('test2', 'value2'),
|
||||
]);
|
||||
await Promise.all([createVariable('test1', 'value1'), createVariable('test2', 'value2')]);
|
||||
});
|
||||
|
||||
test('should return all variables for an owner', async () => {
|
||||
|
@ -61,8 +89,8 @@ describe('GET /variables/:id', () => {
|
|||
let var1: Variables, var2: Variables;
|
||||
beforeEach(async () => {
|
||||
[var1, var2] = await Promise.all([
|
||||
testDb.createVariable('test1', 'value1'),
|
||||
testDb.createVariable('test2', 'value2'),
|
||||
createVariable('test1', 'value1'),
|
||||
createVariable('test2', 'value2'),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -104,8 +132,8 @@ describe('POST /variables', () => {
|
|||
expect(response.body.data.value).toBe(toCreate.value);
|
||||
|
||||
const [byId, byKey] = await Promise.all([
|
||||
testDb.getVariableById(response.body.data.id),
|
||||
testDb.getVariableByKey(toCreate.key),
|
||||
getVariableById(response.body.data.id),
|
||||
getVariableByKey(toCreate.key),
|
||||
]);
|
||||
|
||||
expect(byId).not.toBeNull();
|
||||
|
@ -123,7 +151,7 @@ describe('POST /variables', () => {
|
|||
expect(response.body.data?.key).not.toBe(toCreate.key);
|
||||
expect(response.body.data?.value).not.toBe(toCreate.value);
|
||||
|
||||
const byKey = await testDb.getVariableByKey(toCreate.key);
|
||||
const byKey = await getVariableByKey(toCreate.key);
|
||||
expect(byKey).toBeNull();
|
||||
});
|
||||
|
||||
|
@ -134,12 +162,12 @@ describe('POST /variables', () => {
|
|||
expect(response.body.data?.key).not.toBe(toCreate.key);
|
||||
expect(response.body.data?.value).not.toBe(toCreate.value);
|
||||
|
||||
const byKey = await testDb.getVariableByKey(toCreate.key);
|
||||
const byKey = await getVariableByKey(toCreate.key);
|
||||
expect(byKey).toBeNull();
|
||||
});
|
||||
|
||||
test('should fail to create a new variable and if one with the same key exists', async () => {
|
||||
await testDb.createVariable(toCreate.key, toCreate.value);
|
||||
await createVariable(toCreate.key, toCreate.value);
|
||||
const response = await authOwnerAgent.post('/variables').send(toCreate);
|
||||
expect(response.statusCode).toBe(500);
|
||||
expect(response.body.data?.key).not.toBe(toCreate.key);
|
||||
|
@ -151,7 +179,7 @@ describe('POST /variables', () => {
|
|||
let i = 1;
|
||||
let toCreate = generatePayload(i);
|
||||
while (i < 3) {
|
||||
await testDb.createVariable(toCreate.key, toCreate.value);
|
||||
await createVariable(toCreate.key, toCreate.value);
|
||||
i++;
|
||||
toCreate = generatePayload(i);
|
||||
}
|
||||
|
@ -166,7 +194,7 @@ describe('POST /variables', () => {
|
|||
let i = 1;
|
||||
let toCreate = generatePayload(i);
|
||||
while (i < 6) {
|
||||
await testDb.createVariable(toCreate.key, toCreate.value);
|
||||
await createVariable(toCreate.key, toCreate.value);
|
||||
i++;
|
||||
toCreate = generatePayload(i);
|
||||
}
|
||||
|
@ -224,15 +252,15 @@ describe('PATCH /variables/:id', () => {
|
|||
};
|
||||
|
||||
test('should modify existing variable if use is an owner', async () => {
|
||||
const variable = await testDb.createVariable('test1', 'value1');
|
||||
const variable = await createVariable('test1', 'value1');
|
||||
const response = await authOwnerAgent.patch(`/variables/${variable.id}`).send(toModify);
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.body.data.key).toBe(toModify.key);
|
||||
expect(response.body.data.value).toBe(toModify.value);
|
||||
|
||||
const [byId, byKey] = await Promise.all([
|
||||
testDb.getVariableById(response.body.data.id),
|
||||
testDb.getVariableByKey(toModify.key),
|
||||
getVariableById(response.body.data.id),
|
||||
getVariableByKey(toModify.key),
|
||||
]);
|
||||
|
||||
expect(byId).not.toBeNull();
|
||||
|
@ -245,15 +273,15 @@ describe('PATCH /variables/:id', () => {
|
|||
});
|
||||
|
||||
test('should modify existing variable if use is an owner', async () => {
|
||||
const variable = await testDb.createVariable('test1', 'value1');
|
||||
const variable = await createVariable('test1', 'value1');
|
||||
const response = await authOwnerAgent.patch(`/variables/${variable.id}`).send(toModify);
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.body.data.key).toBe(toModify.key);
|
||||
expect(response.body.data.value).toBe(toModify.value);
|
||||
|
||||
const [byId, byKey] = await Promise.all([
|
||||
testDb.getVariableById(response.body.data.id),
|
||||
testDb.getVariableByKey(toModify.key),
|
||||
getVariableById(response.body.data.id),
|
||||
getVariableByKey(toModify.key),
|
||||
]);
|
||||
|
||||
expect(byId).not.toBeNull();
|
||||
|
@ -266,13 +294,13 @@ describe('PATCH /variables/:id', () => {
|
|||
});
|
||||
|
||||
test('should not modify existing variable if use is a member', async () => {
|
||||
const variable = await testDb.createVariable('test1', 'value1');
|
||||
const variable = await createVariable('test1', 'value1');
|
||||
const response = await authMemberAgent.patch(`/variables/${variable.id}`).send(toModify);
|
||||
expect(response.statusCode).toBe(401);
|
||||
expect(response.body.data?.key).not.toBe(toModify.key);
|
||||
expect(response.body.data?.value).not.toBe(toModify.value);
|
||||
|
||||
const byId = await testDb.getVariableById(variable.id);
|
||||
const byId = await getVariableById(variable.id);
|
||||
expect(byId).not.toBeNull();
|
||||
expect(byId!.key).not.toBe(toModify.key);
|
||||
expect(byId!.value).not.toBe(toModify.value);
|
||||
|
@ -280,15 +308,15 @@ describe('PATCH /variables/:id', () => {
|
|||
|
||||
test('should not modify existing variable if one with the same key exists', async () => {
|
||||
const [var1, var2] = await Promise.all([
|
||||
testDb.createVariable('test1', 'value1'),
|
||||
testDb.createVariable(toModify.key, toModify.value),
|
||||
createVariable('test1', 'value1'),
|
||||
createVariable(toModify.key, toModify.value),
|
||||
]);
|
||||
const response = await authOwnerAgent.patch(`/variables/${var1.id}`).send(toModify);
|
||||
expect(response.statusCode).toBe(500);
|
||||
expect(response.body.data?.key).not.toBe(toModify.key);
|
||||
expect(response.body.data?.value).not.toBe(toModify.value);
|
||||
|
||||
const byId = await testDb.getVariableById(var1.id);
|
||||
const byId = await getVariableById(var1.id);
|
||||
expect(byId).not.toBeNull();
|
||||
expect(byId!.key).toBe(var1.key);
|
||||
expect(byId!.value).toBe(var1.value);
|
||||
|
@ -301,15 +329,15 @@ describe('PATCH /variables/:id', () => {
|
|||
describe('DELETE /variables/:id', () => {
|
||||
test('should delete a single variable for an owner', async () => {
|
||||
const [var1, var2, var3] = await Promise.all([
|
||||
testDb.createVariable('test1', 'value1'),
|
||||
testDb.createVariable('test2', 'value2'),
|
||||
testDb.createVariable('test3', 'value3'),
|
||||
createVariable('test1', 'value1'),
|
||||
createVariable('test2', 'value2'),
|
||||
createVariable('test3', 'value3'),
|
||||
]);
|
||||
|
||||
const delResponse = await authOwnerAgent.delete(`/variables/${var1.id}`);
|
||||
expect(delResponse.statusCode).toBe(200);
|
||||
|
||||
const byId = await testDb.getVariableById(var1.id);
|
||||
const byId = await getVariableById(var1.id);
|
||||
expect(byId).toBeNull();
|
||||
|
||||
const getResponse = await authOwnerAgent.get('/variables');
|
||||
|
@ -318,15 +346,15 @@ describe('DELETE /variables/:id', () => {
|
|||
|
||||
test('should not delete a single variable for a member', async () => {
|
||||
const [var1, var2, var3] = await Promise.all([
|
||||
testDb.createVariable('test1', 'value1'),
|
||||
testDb.createVariable('test2', 'value2'),
|
||||
testDb.createVariable('test3', 'value3'),
|
||||
createVariable('test1', 'value1'),
|
||||
createVariable('test2', 'value2'),
|
||||
createVariable('test3', 'value3'),
|
||||
]);
|
||||
|
||||
const delResponse = await authMemberAgent.delete(`/variables/${var1.id}`);
|
||||
expect(delResponse.statusCode).toBe(401);
|
||||
|
||||
const byId = await testDb.getVariableById(var1.id);
|
||||
const byId = await getVariableById(var1.id);
|
||||
expect(byId).not.toBeNull();
|
||||
|
||||
const getResponse = await authMemberAgent.get('/variables');
|
||||
|
|
|
@ -12,6 +12,8 @@ import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
|||
|
||||
import { mockInstance, initActiveWorkflowRunner } from './shared/utils';
|
||||
import * as testDb from './shared/testDb';
|
||||
import { createUser } from './shared/db/users';
|
||||
import { createWorkflow } from './shared/db/workflows';
|
||||
|
||||
describe('Webhook API', () => {
|
||||
mockInstance(ExternalHooks);
|
||||
|
@ -31,8 +33,8 @@ describe('Webhook API', () => {
|
|||
describe('Content-Type support', () => {
|
||||
beforeAll(async () => {
|
||||
const node = new WebhookTestingNode();
|
||||
const user = await testDb.createUser();
|
||||
await testDb.createWorkflow(createWebhookWorkflow(node), user);
|
||||
const user = await createUser();
|
||||
await createWorkflow(createWebhookWorkflow(node), user);
|
||||
|
||||
const nodeTypes = mockInstance(NodeTypes);
|
||||
nodeTypes.getByName.mockReturnValue(node);
|
||||
|
@ -134,8 +136,8 @@ describe('Webhook API', () => {
|
|||
describe('Params support', () => {
|
||||
beforeAll(async () => {
|
||||
const node = new WebhookTestingNode();
|
||||
const user = await testDb.createUser();
|
||||
await testDb.createWorkflow(createWebhookWorkflow(node, ':variable', 'PATCH'), user);
|
||||
const user = await createUser();
|
||||
await createWorkflow(createWebhookWorkflow(node, ':variable', 'PATCH'), user);
|
||||
|
||||
const nodeTypes = mockInstance(NodeTypes);
|
||||
nodeTypes.getByName.mockReturnValue(node);
|
||||
|
|
|
@ -4,6 +4,9 @@ import * as testDb from './shared/testDb';
|
|||
import * as utils from './shared/utils/';
|
||||
import type { User } from '@/databases/entities/User';
|
||||
import { WorkflowHistoryRepository } from '@/databases/repositories';
|
||||
import { createOwner, createUser } from './shared/db/users';
|
||||
import { createWorkflow } from './shared/db/workflows';
|
||||
import { createWorkflowHistoryItem } from './shared/db/workflowHistory';
|
||||
|
||||
let owner: User;
|
||||
let authOwnerAgent: SuperAgentTest;
|
||||
|
@ -18,9 +21,9 @@ const licenseLike = utils.mockInstance(License, {
|
|||
const testServer = utils.setupTestServer({ endpointGroups: ['workflowHistory'] });
|
||||
|
||||
beforeAll(async () => {
|
||||
owner = await testDb.createOwner();
|
||||
owner = await createOwner();
|
||||
authOwnerAgent = testServer.authAgentFor(owner);
|
||||
member = await testDb.createUser();
|
||||
member = await createUser();
|
||||
authMemberAgent = testServer.authAgentFor(member);
|
||||
});
|
||||
|
||||
|
@ -41,31 +44,31 @@ describe('GET /workflow-history/:workflowId', () => {
|
|||
});
|
||||
|
||||
test('should not return anything on an invalid workflow ID', async () => {
|
||||
await testDb.createWorkflow(undefined, owner);
|
||||
await createWorkflow(undefined, owner);
|
||||
const resp = await authOwnerAgent.get('/workflow-history/workflow/badid');
|
||||
expect(resp.status).toBe(404);
|
||||
});
|
||||
|
||||
test('should not return anything if not shared with user', async () => {
|
||||
const workflow = await testDb.createWorkflow(undefined, owner);
|
||||
const workflow = await createWorkflow(undefined, owner);
|
||||
const resp = await authMemberAgent.get('/workflow-history/workflow/' + workflow.id);
|
||||
expect(resp.status).toBe(404);
|
||||
});
|
||||
|
||||
test('should return any empty list if no versions', async () => {
|
||||
const workflow = await testDb.createWorkflow(undefined, owner);
|
||||
const workflow = await createWorkflow(undefined, owner);
|
||||
const resp = await authOwnerAgent.get('/workflow-history/workflow/' + workflow.id);
|
||||
expect(resp.status).toBe(200);
|
||||
expect(resp.body).toEqual({ data: [] });
|
||||
});
|
||||
|
||||
test('should return versions for workflow', async () => {
|
||||
const workflow = await testDb.createWorkflow(undefined, owner);
|
||||
const workflow = await createWorkflow(undefined, owner);
|
||||
const versions = await Promise.all(
|
||||
new Array(10)
|
||||
.fill(undefined)
|
||||
.map(async (_, i) =>
|
||||
testDb.createWorkflowHistoryItem(workflow.id, { createdAt: new Date(Date.now() + i) }),
|
||||
createWorkflowHistoryItem(workflow.id, { createdAt: new Date(Date.now() + i) }),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -84,20 +87,18 @@ describe('GET /workflow-history/:workflowId', () => {
|
|||
});
|
||||
|
||||
test('should return versions only for workflow id provided', async () => {
|
||||
const workflow = await testDb.createWorkflow(undefined, owner);
|
||||
const workflow2 = await testDb.createWorkflow(undefined, owner);
|
||||
const workflow = await createWorkflow(undefined, owner);
|
||||
const workflow2 = await createWorkflow(undefined, owner);
|
||||
const versions = await Promise.all(
|
||||
new Array(10)
|
||||
.fill(undefined)
|
||||
.map(async (_, i) =>
|
||||
testDb.createWorkflowHistoryItem(workflow.id, { createdAt: new Date(Date.now() + i) }),
|
||||
createWorkflowHistoryItem(workflow.id, { createdAt: new Date(Date.now() + i) }),
|
||||
),
|
||||
);
|
||||
|
||||
const versions2 = await Promise.all(
|
||||
new Array(10)
|
||||
.fill(undefined)
|
||||
.map(async (_) => testDb.createWorkflowHistoryItem(workflow2.id)),
|
||||
new Array(10).fill(undefined).map(async (_) => createWorkflowHistoryItem(workflow2.id)),
|
||||
);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
@ -115,12 +116,12 @@ describe('GET /workflow-history/:workflowId', () => {
|
|||
});
|
||||
|
||||
test('should work with take parameter', async () => {
|
||||
const workflow = await testDb.createWorkflow(undefined, owner);
|
||||
const workflow = await createWorkflow(undefined, owner);
|
||||
const versions = await Promise.all(
|
||||
new Array(10)
|
||||
.fill(undefined)
|
||||
.map(async (_, i) =>
|
||||
testDb.createWorkflowHistoryItem(workflow.id, { createdAt: new Date(Date.now() + i) }),
|
||||
createWorkflowHistoryItem(workflow.id, { createdAt: new Date(Date.now() + i) }),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -139,12 +140,12 @@ describe('GET /workflow-history/:workflowId', () => {
|
|||
});
|
||||
|
||||
test('should work with skip parameter', async () => {
|
||||
const workflow = await testDb.createWorkflow(undefined, owner);
|
||||
const workflow = await createWorkflow(undefined, owner);
|
||||
const versions = await Promise.all(
|
||||
new Array(10)
|
||||
.fill(undefined)
|
||||
.map(async (_, i) =>
|
||||
testDb.createWorkflowHistoryItem(workflow.id, { createdAt: new Date(Date.now() + i) }),
|
||||
createWorkflowHistoryItem(workflow.id, { createdAt: new Date(Date.now() + i) }),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -174,8 +175,8 @@ describe('GET /workflow-history/workflow/:workflowId/version/:versionId', () =>
|
|||
});
|
||||
|
||||
test('should not return anything on an invalid workflow ID', async () => {
|
||||
const workflow = await testDb.createWorkflow(undefined, owner);
|
||||
const version = await testDb.createWorkflowHistoryItem(workflow.id);
|
||||
const workflow = await createWorkflow(undefined, owner);
|
||||
const version = await createWorkflowHistoryItem(workflow.id);
|
||||
const resp = await authOwnerAgent.get(
|
||||
`/workflow-history/workflow/badid/version/${version.versionId}`,
|
||||
);
|
||||
|
@ -183,8 +184,8 @@ describe('GET /workflow-history/workflow/:workflowId/version/:versionId', () =>
|
|||
});
|
||||
|
||||
test('should not return anything on an invalid version ID', async () => {
|
||||
const workflow = await testDb.createWorkflow(undefined, owner);
|
||||
await testDb.createWorkflowHistoryItem(workflow.id);
|
||||
const workflow = await createWorkflow(undefined, owner);
|
||||
await createWorkflowHistoryItem(workflow.id);
|
||||
const resp = await authOwnerAgent.get(
|
||||
`/workflow-history/workflow/${workflow.id}/version/badid`,
|
||||
);
|
||||
|
@ -192,8 +193,8 @@ describe('GET /workflow-history/workflow/:workflowId/version/:versionId', () =>
|
|||
});
|
||||
|
||||
test('should return version', async () => {
|
||||
const workflow = await testDb.createWorkflow(undefined, owner);
|
||||
const version = await testDb.createWorkflowHistoryItem(workflow.id);
|
||||
const workflow = await createWorkflow(undefined, owner);
|
||||
const version = await createWorkflowHistoryItem(workflow.id);
|
||||
const resp = await authOwnerAgent.get(
|
||||
`/workflow-history/workflow/${workflow.id}/version/${version.versionId}`,
|
||||
);
|
||||
|
@ -206,8 +207,8 @@ describe('GET /workflow-history/workflow/:workflowId/version/:versionId', () =>
|
|||
});
|
||||
|
||||
test('should not return anything if not shared with user', async () => {
|
||||
const workflow = await testDb.createWorkflow(undefined, owner);
|
||||
const version = await testDb.createWorkflowHistoryItem(workflow.id);
|
||||
const workflow = await createWorkflow(undefined, owner);
|
||||
const version = await createWorkflowHistoryItem(workflow.id);
|
||||
const resp = await authMemberAgent.get(
|
||||
`/workflow-history/workflow/${workflow.id}/version/${version.versionId}`,
|
||||
);
|
||||
|
@ -215,9 +216,9 @@ describe('GET /workflow-history/workflow/:workflowId/version/:versionId', () =>
|
|||
});
|
||||
|
||||
test('should not return anything if not shared with user and using workflow owned by unshared user', async () => {
|
||||
const workflow = await testDb.createWorkflow(undefined, owner);
|
||||
const workflowMember = await testDb.createWorkflow(undefined, member);
|
||||
const version = await testDb.createWorkflowHistoryItem(workflow.id);
|
||||
const workflow = await createWorkflow(undefined, owner);
|
||||
const workflowMember = await createWorkflow(undefined, member);
|
||||
const version = await createWorkflowHistoryItem(workflow.id);
|
||||
const resp = await authMemberAgent.get(
|
||||
`/workflow-history/workflow/${workflowMember.id}/version/${version.versionId}`,
|
||||
);
|
||||
|
|
|
@ -9,6 +9,8 @@ import { WorkflowHistoryManager } from '@/workflows/workflowHistory/workflowHist
|
|||
|
||||
import * as testDb from './shared/testDb';
|
||||
import { mockInstance } from './shared/utils';
|
||||
import { createWorkflow } from './shared/db/workflows';
|
||||
import { createManyWorkflowHistoryItems } from './shared/db/workflowHistory';
|
||||
|
||||
describe('Workflow History Manager', () => {
|
||||
const license = mockInstance(License);
|
||||
|
@ -98,9 +100,9 @@ describe('Workflow History Manager', () => {
|
|||
});
|
||||
|
||||
const createWorkflowHistory = async (ageInDays = 2) => {
|
||||
const workflow = await testDb.createWorkflow();
|
||||
const workflow = await createWorkflow();
|
||||
const time = DateTime.now().minus({ days: ageInDays }).toJSDate();
|
||||
return testDb.createManyWorkflowHistoryItems(workflow.id, 10, time);
|
||||
return createManyWorkflowHistoryItems(workflow.id, 10, time);
|
||||
};
|
||||
|
||||
const pruneAndAssertCount = async (finalCount = 10, initialCount = 10) => {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import Container from 'typedi';
|
||||
import type { SuperAgentTest } from 'supertest';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import type { INode } from 'n8n-workflow';
|
||||
|
@ -5,17 +6,19 @@ import type { INode } from 'n8n-workflow';
|
|||
import * as UserManagementHelpers from '@/UserManagement/UserManagementHelper';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { getSharedWorkflowIds } from '@/WorkflowHelpers';
|
||||
import { License } from '@/License';
|
||||
import { WorkflowHistoryRepository } from '@/databases/repositories';
|
||||
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||
|
||||
import * as utils from './shared/utils/';
|
||||
import * as testDb from './shared/testDb';
|
||||
import { createWorkflow, getGlobalMemberRole, getGlobalOwnerRole } from './shared/testDb';
|
||||
import type { SaveCredentialFunction } from './shared/types';
|
||||
import { makeWorkflow } from './shared/utils/';
|
||||
import { randomCredentialPayload } from './shared/random';
|
||||
import { License } from '@/License';
|
||||
import { WorkflowHistoryRepository } from '@/databases/repositories';
|
||||
import Container from 'typedi';
|
||||
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||
import { affixRoleToSaveCredential, shareCredentialWithUsers } from './shared/db/credentials';
|
||||
import { getCredentialOwnerRole, getGlobalMemberRole, getGlobalOwnerRole } from './shared/db/roles';
|
||||
import { createUser } from './shared/db/users';
|
||||
import { createWorkflow, getWorkflowSharing, shareWorkflowWithUsers } from './shared/db/workflows';
|
||||
|
||||
let owner: User;
|
||||
let member: User;
|
||||
|
@ -38,19 +41,19 @@ const testServer = utils.setupTestServer({
|
|||
});
|
||||
|
||||
beforeAll(async () => {
|
||||
const globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||
const globalMemberRole = await testDb.getGlobalMemberRole();
|
||||
const credentialOwnerRole = await testDb.getCredentialOwnerRole();
|
||||
const globalOwnerRole = await getGlobalOwnerRole();
|
||||
const globalMemberRole = await getGlobalMemberRole();
|
||||
const credentialOwnerRole = await getCredentialOwnerRole();
|
||||
|
||||
owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
member = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
anotherMember = await testDb.createUser({ globalRole: globalMemberRole });
|
||||
owner = await createUser({ globalRole: globalOwnerRole });
|
||||
member = await createUser({ globalRole: globalMemberRole });
|
||||
anotherMember = await createUser({ globalRole: globalMemberRole });
|
||||
|
||||
authOwnerAgent = testServer.authAgentFor(owner);
|
||||
authMemberAgent = testServer.authAgentFor(member);
|
||||
authAnotherMemberAgent = testServer.authAgentFor(anotherMember);
|
||||
|
||||
saveCredential = testDb.affixRoleToSaveCredential(credentialOwnerRole);
|
||||
saveCredential = affixRoleToSaveCredential(credentialOwnerRole);
|
||||
|
||||
await utils.initNodeTypes();
|
||||
});
|
||||
|
@ -98,7 +101,7 @@ describe('PUT /workflows/:id', () => {
|
|||
|
||||
expect(response.statusCode).toBe(200);
|
||||
|
||||
const sharedWorkflows = await testDb.getWorkflowSharing(workflow);
|
||||
const sharedWorkflows = await getWorkflowSharing(workflow);
|
||||
expect(sharedWorkflows).toHaveLength(2);
|
||||
});
|
||||
|
||||
|
@ -111,7 +114,7 @@ describe('PUT /workflows/:id', () => {
|
|||
|
||||
expect(response.statusCode).toBe(200);
|
||||
|
||||
const sharedWorkflows = await testDb.getWorkflowSharing(workflow);
|
||||
const sharedWorkflows = await getWorkflowSharing(workflow);
|
||||
expect(sharedWorkflows).toHaveLength(1);
|
||||
});
|
||||
|
||||
|
@ -124,7 +127,7 @@ describe('PUT /workflows/:id', () => {
|
|||
|
||||
expect(response.statusCode).toBe(200);
|
||||
|
||||
const sharedWorkflows = await testDb.getWorkflowSharing(workflow);
|
||||
const sharedWorkflows = await getWorkflowSharing(workflow);
|
||||
expect(sharedWorkflows).toHaveLength(3);
|
||||
});
|
||||
|
||||
|
@ -137,7 +140,7 @@ describe('PUT /workflows/:id', () => {
|
|||
|
||||
expect(response.statusCode).toBe(200);
|
||||
|
||||
const sharedWorkflows = await testDb.getWorkflowSharing(workflow);
|
||||
const sharedWorkflows = await getWorkflowSharing(workflow);
|
||||
expect(sharedWorkflows).toHaveLength(3);
|
||||
|
||||
const secondResponse = await authOwnerAgent
|
||||
|
@ -145,7 +148,7 @@ describe('PUT /workflows/:id', () => {
|
|||
.send({ shareWithIds: [member.id] });
|
||||
expect(secondResponse.statusCode).toBe(200);
|
||||
|
||||
const secondSharedWorkflows = await testDb.getWorkflowSharing(workflow);
|
||||
const secondSharedWorkflows = await getWorkflowSharing(workflow);
|
||||
expect(secondSharedWorkflows).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
@ -198,7 +201,7 @@ describe('GET /workflows/:id', () => {
|
|||
|
||||
test('GET should return shared workflow with user data', async () => {
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
await testDb.shareWorkflowWithUsers(workflow, [member]);
|
||||
await shareWorkflowWithUsers(workflow, [member]);
|
||||
|
||||
const response = await authOwnerAgent.get(`/workflows/${workflow.id}`);
|
||||
|
||||
|
@ -221,7 +224,7 @@ describe('GET /workflows/:id', () => {
|
|||
|
||||
test('GET should return all sharees', async () => {
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
await testDb.shareWorkflowWithUsers(workflow, [member, anotherMember]);
|
||||
await shareWorkflowWithUsers(workflow, [member, anotherMember]);
|
||||
|
||||
const response = await authOwnerAgent.get(`/workflows/${workflow.id}`);
|
||||
|
||||
|
@ -290,7 +293,7 @@ describe('GET /workflows/:id', () => {
|
|||
withCredential: { id: savedCredential.id, name: savedCredential.name },
|
||||
});
|
||||
const workflow = await createWorkflow(workflowPayload, member);
|
||||
await testDb.shareWorkflowWithUsers(workflow, [anotherMember]);
|
||||
await shareWorkflowWithUsers(workflow, [anotherMember]);
|
||||
|
||||
const responseMember1 = await authMemberAgent.get(`/workflows/${workflow.id}`);
|
||||
expect(responseMember1.statusCode).toBe(200);
|
||||
|
@ -318,14 +321,14 @@ describe('GET /workflows/:id', () => {
|
|||
test('GET should return workflow with credentials for all users with access', async () => {
|
||||
const savedCredential = await saveCredential(randomCredentialPayload(), { user: member });
|
||||
// Both users have access to the credential (none is owner)
|
||||
await testDb.shareCredentialWithUsers(savedCredential, [anotherMember]);
|
||||
await shareCredentialWithUsers(savedCredential, [anotherMember]);
|
||||
|
||||
const workflowPayload = makeWorkflow({
|
||||
withPinData: false,
|
||||
withCredential: { id: savedCredential.id, name: savedCredential.name },
|
||||
});
|
||||
const workflow = await createWorkflow(workflowPayload, member);
|
||||
await testDb.shareWorkflowWithUsers(workflow, [anotherMember]);
|
||||
await shareWorkflowWithUsers(workflow, [anotherMember]);
|
||||
|
||||
const responseMember1 = await authMemberAgent.get(`/workflows/${workflow.id}`);
|
||||
expect(responseMember1.statusCode).toBe(200);
|
||||
|
@ -403,7 +406,7 @@ describe('POST /workflows', () => {
|
|||
|
||||
it('Should allow saving a workflow using a credential owned by others and shared with you', async () => {
|
||||
const savedCredential = await saveCredential(randomCredentialPayload(), { user: member });
|
||||
await testDb.shareCredentialWithUsers(savedCredential, [anotherMember]);
|
||||
await shareCredentialWithUsers(savedCredential, [anotherMember]);
|
||||
|
||||
const workflow = makeWorkflow({
|
||||
withPinData: false,
|
||||
|
@ -927,8 +930,8 @@ describe('getSharedWorkflowIds', () => {
|
|||
const workflow1 = await createWorkflow({}, anotherMember);
|
||||
const workflow2 = await createWorkflow({}, anotherMember);
|
||||
const workflow3 = await createWorkflow({}, anotherMember);
|
||||
await testDb.shareWorkflowWithUsers(workflow1, [member]);
|
||||
await testDb.shareWorkflowWithUsers(workflow3, [member]);
|
||||
await shareWorkflowWithUsers(workflow1, [member]);
|
||||
await shareWorkflowWithUsers(workflow3, [member]);
|
||||
const sharedWorkflowIds = await getSharedWorkflowIds(member);
|
||||
expect(sharedWorkflowIds).toHaveLength(2);
|
||||
expect(sharedWorkflowIds).toContain(workflow1.id);
|
||||
|
@ -939,7 +942,7 @@ describe('getSharedWorkflowIds', () => {
|
|||
describe('PATCH /workflows/:id - workflow history', () => {
|
||||
test('Should create workflow history version when licensed', async () => {
|
||||
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(true);
|
||||
const workflow = await testDb.createWorkflow({}, owner);
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
const payload = {
|
||||
name: 'name updated',
|
||||
versionId: workflow.versionId,
|
||||
|
@ -997,7 +1000,7 @@ describe('PATCH /workflows/:id - workflow history', () => {
|
|||
|
||||
test('Should not create workflow history version when not licensed', async () => {
|
||||
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
|
||||
const workflow = await testDb.createWorkflow({}, owner);
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
const payload = {
|
||||
name: 'name updated',
|
||||
versionId: workflow.versionId,
|
||||
|
@ -1049,7 +1052,7 @@ describe('PATCH /workflows/:id - workflow history', () => {
|
|||
describe('PATCH /workflows/:id - activate workflow', () => {
|
||||
test('should activate workflow without changing version ID', async () => {
|
||||
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
|
||||
const workflow = await testDb.createWorkflow({}, owner);
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
const payload = {
|
||||
versionId: workflow.versionId,
|
||||
active: true,
|
||||
|
@ -1071,7 +1074,7 @@ describe('PATCH /workflows/:id - activate workflow', () => {
|
|||
|
||||
test('should deactivate workflow without changing version ID', async () => {
|
||||
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
|
||||
const workflow = await testDb.createWorkflow({ active: true }, owner);
|
||||
const workflow = await createWorkflow({ active: true }, owner);
|
||||
const payload = {
|
||||
versionId: workflow.versionId,
|
||||
active: false,
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
import type { SuperAgentTest } from 'supertest';
|
||||
import type { INode, IPinData } from 'n8n-workflow';
|
||||
import * as UserManagementHelpers from '@/UserManagement/UserManagementHelper';
|
||||
|
||||
import * as utils from './shared/utils/';
|
||||
import * as testDb from './shared/testDb';
|
||||
import { makeWorkflow, MOCK_PINDATA } from './shared/utils/';
|
||||
import type { User } from '@/databases/entities/User';
|
||||
import { randomCredentialPayload } from './shared/random';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import Container from 'typedi';
|
||||
|
@ -15,6 +10,15 @@ import { License } from '@/License';
|
|||
import { WorkflowHistoryRepository } from '@/databases/repositories';
|
||||
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||
|
||||
import * as utils from './shared/utils/';
|
||||
import * as testDb from './shared/testDb';
|
||||
import { makeWorkflow, MOCK_PINDATA } from './shared/utils/';
|
||||
import { randomCredentialPayload } from './shared/random';
|
||||
import { saveCredential } from './shared/db/credentials';
|
||||
import { createOwner } from './shared/db/users';
|
||||
import { createWorkflow } from './shared/db/workflows';
|
||||
import { createTag } from './shared/db/tags';
|
||||
|
||||
let owner: User;
|
||||
let authOwnerAgent: SuperAgentTest;
|
||||
|
||||
|
@ -31,7 +35,7 @@ const licenseLike = utils.mockInstance(License, {
|
|||
const activeWorkflowRunnerLike = utils.mockInstance(ActiveWorkflowRunner);
|
||||
|
||||
beforeAll(async () => {
|
||||
owner = await testDb.createOwner();
|
||||
owner = await createOwner();
|
||||
authOwnerAgent = testServer.authAgentFor(owner);
|
||||
});
|
||||
|
||||
|
@ -172,7 +176,7 @@ describe('GET /workflows', () => {
|
|||
});
|
||||
|
||||
test('should return workflows', async () => {
|
||||
const credential = await testDb.saveCredential(randomCredentialPayload(), {
|
||||
const credential = await saveCredential(randomCredentialPayload(), {
|
||||
user: owner,
|
||||
role: await Container.get(RoleService).findCredentialOwnerRole(),
|
||||
});
|
||||
|
@ -194,10 +198,10 @@ describe('GET /workflows', () => {
|
|||
},
|
||||
];
|
||||
|
||||
const tag = await testDb.createTag({ name: 'A' });
|
||||
const tag = await createTag({ name: 'A' });
|
||||
|
||||
await testDb.createWorkflow({ name: 'First', nodes, tags: [tag] }, owner);
|
||||
await testDb.createWorkflow({ name: 'Second' }, owner);
|
||||
await createWorkflow({ name: 'First', nodes, tags: [tag] }, owner);
|
||||
await createWorkflow({ name: 'Second' }, owner);
|
||||
|
||||
const response = await authOwnerAgent.get('/workflows').expect(200);
|
||||
|
||||
|
@ -238,8 +242,8 @@ describe('GET /workflows', () => {
|
|||
|
||||
describe('filter', () => {
|
||||
test('should filter workflows by field: name', async () => {
|
||||
await testDb.createWorkflow({ name: 'First' }, owner);
|
||||
await testDb.createWorkflow({ name: 'Second' }, owner);
|
||||
await createWorkflow({ name: 'First' }, owner);
|
||||
await createWorkflow({ name: 'Second' }, owner);
|
||||
|
||||
const response = await authOwnerAgent
|
||||
.get('/workflows')
|
||||
|
@ -253,8 +257,8 @@ describe('GET /workflows', () => {
|
|||
});
|
||||
|
||||
test('should filter workflows by field: active', async () => {
|
||||
await testDb.createWorkflow({ active: true }, owner);
|
||||
await testDb.createWorkflow({ active: false }, owner);
|
||||
await createWorkflow({ active: true }, owner);
|
||||
await createWorkflow({ active: false }, owner);
|
||||
|
||||
const response = await authOwnerAgent
|
||||
.get('/workflows')
|
||||
|
@ -268,10 +272,10 @@ describe('GET /workflows', () => {
|
|||
});
|
||||
|
||||
test('should filter workflows by field: tags', async () => {
|
||||
const workflow = await testDb.createWorkflow({ name: 'First' }, owner);
|
||||
const workflow = await createWorkflow({ name: 'First' }, owner);
|
||||
|
||||
await testDb.createTag({ name: 'A' }, workflow);
|
||||
await testDb.createTag({ name: 'B' }, workflow);
|
||||
await createTag({ name: 'A' }, workflow);
|
||||
await createTag({ name: 'B' }, workflow);
|
||||
|
||||
const response = await authOwnerAgent
|
||||
.get('/workflows')
|
||||
|
@ -287,8 +291,8 @@ describe('GET /workflows', () => {
|
|||
|
||||
describe('select', () => {
|
||||
test('should select workflow field: name', async () => {
|
||||
await testDb.createWorkflow({ name: 'First' }, owner);
|
||||
await testDb.createWorkflow({ name: 'Second' }, owner);
|
||||
await createWorkflow({ name: 'First' }, owner);
|
||||
await createWorkflow({ name: 'Second' }, owner);
|
||||
|
||||
const response = await authOwnerAgent.get('/workflows').query('select=["name"]').expect(200);
|
||||
|
||||
|
@ -302,8 +306,8 @@ describe('GET /workflows', () => {
|
|||
});
|
||||
|
||||
test('should select workflow field: active', async () => {
|
||||
await testDb.createWorkflow({ active: true }, owner);
|
||||
await testDb.createWorkflow({ active: false }, owner);
|
||||
await createWorkflow({ active: true }, owner);
|
||||
await createWorkflow({ active: false }, owner);
|
||||
|
||||
const response = await authOwnerAgent
|
||||
.get('/workflows')
|
||||
|
@ -320,11 +324,11 @@ describe('GET /workflows', () => {
|
|||
});
|
||||
|
||||
test('should select workflow field: tags', async () => {
|
||||
const firstWorkflow = await testDb.createWorkflow({ name: 'First' }, owner);
|
||||
const secondWorkflow = await testDb.createWorkflow({ name: 'Second' }, owner);
|
||||
const firstWorkflow = await createWorkflow({ name: 'First' }, owner);
|
||||
const secondWorkflow = await createWorkflow({ name: 'Second' }, owner);
|
||||
|
||||
await testDb.createTag({ name: 'A' }, firstWorkflow);
|
||||
await testDb.createTag({ name: 'B' }, secondWorkflow);
|
||||
await createTag({ name: 'A' }, firstWorkflow);
|
||||
await createTag({ name: 'B' }, secondWorkflow);
|
||||
|
||||
const response = await authOwnerAgent.get('/workflows').query('select=["tags"]').expect(200);
|
||||
|
||||
|
@ -343,14 +347,14 @@ describe('GET /workflows', () => {
|
|||
const secondWorkflowCreatedAt = '2023-07-07T09:31:25.000Z';
|
||||
const secondWorkflowUpdatedAt = '2023-07-07T09:31:40.000Z';
|
||||
|
||||
await testDb.createWorkflow(
|
||||
await createWorkflow(
|
||||
{
|
||||
createdAt: new Date(firstWorkflowCreatedAt),
|
||||
updatedAt: new Date(firstWorkflowUpdatedAt),
|
||||
},
|
||||
owner,
|
||||
);
|
||||
await testDb.createWorkflow(
|
||||
await createWorkflow(
|
||||
{
|
||||
createdAt: new Date(secondWorkflowCreatedAt),
|
||||
updatedAt: new Date(secondWorkflowUpdatedAt),
|
||||
|
@ -384,8 +388,8 @@ describe('GET /workflows', () => {
|
|||
const firstWorkflowVersionId = 'e95ccdde-2b4e-4fd0-8834-220a2b5b4353';
|
||||
const secondWorkflowVersionId = 'd099b8dc-b1d8-4b2d-9b02-26f32c0ee785';
|
||||
|
||||
await testDb.createWorkflow({ versionId: firstWorkflowVersionId }, owner);
|
||||
await testDb.createWorkflow({ versionId: secondWorkflowVersionId }, owner);
|
||||
await createWorkflow({ versionId: firstWorkflowVersionId }, owner);
|
||||
await createWorkflow({ versionId: secondWorkflowVersionId }, owner);
|
||||
|
||||
const response = await authOwnerAgent
|
||||
.get('/workflows')
|
||||
|
@ -402,8 +406,8 @@ describe('GET /workflows', () => {
|
|||
});
|
||||
|
||||
test('should select workflow field: ownedBy', async () => {
|
||||
await testDb.createWorkflow({}, owner);
|
||||
await testDb.createWorkflow({}, owner);
|
||||
await createWorkflow({}, owner);
|
||||
await createWorkflow({}, owner);
|
||||
|
||||
const response = await authOwnerAgent
|
||||
.get('/workflows')
|
||||
|
@ -424,7 +428,7 @@ describe('GET /workflows', () => {
|
|||
describe('PATCH /workflows/:id', () => {
|
||||
test('should create workflow history version when licensed', async () => {
|
||||
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(true);
|
||||
const workflow = await testDb.createWorkflow({}, owner);
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
const payload = {
|
||||
name: 'name updated',
|
||||
versionId: workflow.versionId,
|
||||
|
@ -482,7 +486,7 @@ describe('PATCH /workflows/:id', () => {
|
|||
|
||||
test('should not create workflow history version when not licensed', async () => {
|
||||
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
|
||||
const workflow = await testDb.createWorkflow({}, owner);
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
const payload = {
|
||||
name: 'name updated',
|
||||
versionId: workflow.versionId,
|
||||
|
@ -532,7 +536,7 @@ describe('PATCH /workflows/:id', () => {
|
|||
|
||||
test('should activate workflow without changing version ID', async () => {
|
||||
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
|
||||
const workflow = await testDb.createWorkflow({}, owner);
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
const payload = {
|
||||
versionId: workflow.versionId,
|
||||
active: true,
|
||||
|
@ -554,7 +558,7 @@ describe('PATCH /workflows/:id', () => {
|
|||
|
||||
test('should deactivate workflow without changing version ID', async () => {
|
||||
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
|
||||
const workflow = await testDb.createWorkflow({ active: true }, owner);
|
||||
const workflow = await createWorkflow({ active: true }, owner);
|
||||
const payload = {
|
||||
versionId: workflow.versionId,
|
||||
active: false,
|
||||
|
|
|
@ -15,8 +15,6 @@ import { mockInstance } from '../integration/shared/utils';
|
|||
import Container from 'typedi';
|
||||
|
||||
describe('CredentialsHelper', () => {
|
||||
const TEST_ENCRYPTION_KEY = 'test';
|
||||
|
||||
const mockNodesAndCredentials = mockInstance(LoadNodesAndCredentials, {
|
||||
loadedNodes: {
|
||||
'test.set': {
|
||||
|
|
|
@ -12,7 +12,7 @@ let telemetry: Telemetry;
|
|||
describe('InternalHooks', () => {
|
||||
beforeAll(() => {
|
||||
telemetry = mockInstance(Telemetry);
|
||||
internalHooks = new InternalHooks(telemetry, mock(), mock(), mock(), mock(), mock());
|
||||
internalHooks = new InternalHooks(telemetry, mock(), mock(), mock(), mock());
|
||||
});
|
||||
|
||||
it('Should be defined', () => {
|
||||
|
|
|
@ -22,6 +22,9 @@ import {
|
|||
import * as testDb from '../integration/shared/testDb';
|
||||
import type { SaveCredentialFunction } from '../integration/shared/types';
|
||||
import { mockNodeTypesData } from './Helpers';
|
||||
import { affixRoleToSaveCredential } from '../integration/shared/db/credentials';
|
||||
import { getCredentialOwnerRole, getWorkflowOwnerRole } from '../integration/shared/db/roles';
|
||||
import { createOwner, createUser } from '../integration/shared/db/users';
|
||||
|
||||
let mockNodeTypes: INodeTypes;
|
||||
let credentialOwnerRole: Role;
|
||||
|
@ -37,10 +40,10 @@ beforeAll(async () => {
|
|||
|
||||
mockNodeTypes = Container.get(NodeTypes);
|
||||
|
||||
credentialOwnerRole = await testDb.getCredentialOwnerRole();
|
||||
workflowOwnerRole = await testDb.getWorkflowOwnerRole();
|
||||
credentialOwnerRole = await getCredentialOwnerRole();
|
||||
workflowOwnerRole = await getWorkflowOwnerRole();
|
||||
|
||||
saveCredential = testDb.affixRoleToSaveCredential(credentialOwnerRole);
|
||||
saveCredential = affixRoleToSaveCredential(credentialOwnerRole);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
|
@ -77,7 +80,7 @@ describe('PermissionChecker.check()', () => {
|
|||
});
|
||||
|
||||
test('should allow if requesting user is instance owner', async () => {
|
||||
const owner = await testDb.createOwner();
|
||||
const owner = await createOwner();
|
||||
|
||||
const workflow = new Workflow({
|
||||
id: randomPositiveDigit().toString(),
|
||||
|
@ -107,7 +110,7 @@ describe('PermissionChecker.check()', () => {
|
|||
});
|
||||
|
||||
test('should allow if workflow creds are valid subset', async () => {
|
||||
const [owner, member] = await Promise.all([testDb.createOwner(), testDb.createUser()]);
|
||||
const [owner, member] = await Promise.all([createOwner(), createUser()]);
|
||||
|
||||
const ownerCred = await saveCredential(randomCred(), { user: owner });
|
||||
const memberCred = await saveCredential(randomCred(), { user: member });
|
||||
|
@ -154,7 +157,7 @@ describe('PermissionChecker.check()', () => {
|
|||
});
|
||||
|
||||
test('should deny if workflow creds are not valid subset', async () => {
|
||||
const member = await testDb.createUser();
|
||||
const member = await createUser();
|
||||
|
||||
const memberCred = await saveCredential(randomCred(), { user: member });
|
||||
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import type { User } from '@db/entities/User';
|
||||
import * as testDb from '../integration/shared/testDb';
|
||||
import * as utils from '../integration/shared/utils/';
|
||||
import { createWorkflow, createExecution } from '../integration/shared/testDb';
|
||||
import { WorkflowRunner } from '@/WorkflowRunner';
|
||||
import { WorkflowHooks, type ExecutionError, type IWorkflowExecuteHooks } from 'n8n-workflow';
|
||||
import { Push } from '@/push';
|
||||
import { mockInstance } from '../integration/shared/utils';
|
||||
import Container from 'typedi';
|
||||
import config from '@/config';
|
||||
import { getGlobalOwnerRole } from '../integration/shared/db/roles';
|
||||
import { createUser } from '../integration/shared/db/users';
|
||||
import { createWorkflow } from '../integration/shared/db/workflows';
|
||||
import { createExecution } from '../integration/shared/db/executions';
|
||||
|
||||
let owner: User;
|
||||
let runner: WorkflowRunner;
|
||||
|
@ -21,8 +24,8 @@ const watchers = new Watchers();
|
|||
const watchedWorkflowExecuteAfter = jest.spyOn(watchers, 'workflowExecuteAfter');
|
||||
|
||||
beforeAll(async () => {
|
||||
const globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||
owner = await testDb.createUser({ globalRole: globalOwnerRole });
|
||||
const globalOwnerRole = await getGlobalOwnerRole();
|
||||
owner = await createUser({ globalRole: globalOwnerRole });
|
||||
|
||||
mockInstance(Push);
|
||||
Container.set(Push, new Push());
|
||||
|
|
|
@ -4,7 +4,7 @@ import jwt from 'jsonwebtoken';
|
|||
import { mock, anyObject, captor } from 'jest-mock-extended';
|
||||
import type { PublicUser } from '@/Interfaces';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { MeController } from '@/controllers';
|
||||
import { MeController } from '@/controllers/me.controller';
|
||||
import { AUTH_COOKIE_NAME } from '@/constants';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import type { AuthenticatedRequest, MeRequest } from '@/requests';
|
||||
|
|
|
@ -7,7 +7,7 @@ import type { SettingsRepository } from '@db/repositories';
|
|||
import type { Config } from '@/config';
|
||||
import { BadRequestError } from '@/ResponseHelper';
|
||||
import type { OwnerRequest } from '@/requests';
|
||||
import { OwnerController } from '@/controllers';
|
||||
import { OwnerController } from '@/controllers/owner.controller';
|
||||
import { badPasswords } from '../shared/testData';
|
||||
import { AUTH_COOKIE_NAME } from '@/constants';
|
||||
import { UserService } from '@/services/user.service';
|
||||
|
|
Loading…
Reference in a new issue