From 0346b211a763a001db92bcbf5934fca76d304e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Wed, 8 Nov 2023 16:29:39 +0100 Subject: [PATCH] ci(core): Reduce memory usage in tests (part-1) (no-changelog) (#7654) --- packages/cli/src/Server.ts | 31 +- packages/cli/src/WorkflowRunner.ts | 6 +- packages/cli/src/controllers/index.ts | 13 - .../cli/src/controllers/mfa.controller.ts | 3 + .../integration/ActiveWorkflowRunner.test.ts | 40 +- .../externalSecrets.api.test.ts | 6 +- .../cli/test/integration/auth.api.test.ts | 32 +- packages/cli/test/integration/auth.mw.test.ts | 7 +- .../test/integration/binaryData.api.test.ts | 4 +- .../commands/credentials.cmd.test.ts | 5 +- .../integration/commands/import.cmd.test.ts | 9 +- .../integration/commands/reset.cmd.test.ts | 6 +- .../community-packages.api.test.ts | 4 +- .../credentials.controller.test.ts | 76 +-- .../test/integration/credentials.ee.test.ts | 44 +- .../cli/test/integration/credentials.test.ts | 18 +- .../environments/SourceControl.test.ts | 11 +- .../cli/test/integration/eventbus.ee.test.ts | 10 +- .../cli/test/integration/eventbus.test.ts | 7 +- .../integration/executions.controller.test.ts | 13 +- .../test/integration/ldap/ldap.api.test.ts | 49 +- .../cli/test/integration/license.api.test.ts | 10 +- packages/cli/test/integration/me.api.test.ts | 14 +- .../cli/test/integration/mfa/mfa.api.test.ts | 29 +- .../cli/test/integration/owner.api.test.ts | 6 +- .../integration/passwordReset.api.test.ts | 14 +- .../test/integration/pruning.service.test.ts | 45 +- .../integration/publicApi/credentials.test.ts | 13 +- .../integration/publicApi/executions.test.ts | 149 +++-- .../integration/publicApi/users.ee.test.ts | 35 +- .../integration/publicApi/workflows.test.ts | 76 +-- .../test/integration/saml/saml.api.test.ts | 6 +- .../test/integration/shared/db/credentials.ts | 67 +++ .../test/integration/shared/db/executions.ts | 68 +++ .../cli/test/integration/shared/db/roles.ts | 31 + .../cli/test/integration/shared/db/tags.ts | 25 + .../cli/test/integration/shared/db/users.ts | 134 +++++ .../integration/shared/db/workflowHistory.ts | 43 ++ .../test/integration/shared/db/workflows.ts | 118 ++++ .../cli/test/integration/shared/testDb.ts | 543 +----------------- packages/cli/test/integration/shared/types.ts | 2 +- .../test/integration/shared/utils/index.ts | 4 +- .../integration/shared/utils/testServer.ts | 205 +++---- .../cli/test/integration/tags.api.test.ts | 6 +- .../cli/test/integration/users.api.test.ts | 28 +- .../test/integration/users.controller.test.ts | 11 +- .../cli/test/integration/variables.test.ts | 96 ++-- .../cli/test/integration/webhooks.api.test.ts | 10 +- .../integration/workflowHistory.api.test.ts | 57 +- .../workflowHistoryManager.test.ts | 6 +- .../workflows.controller.ee.test.ts | 61 +- .../integration/workflows.controller.test.ts | 74 +-- .../cli/test/unit/CredentialsHelper.test.ts | 2 - packages/cli/test/unit/InternalHooks.test.ts | 2 +- .../cli/test/unit/PermissionChecker.test.ts | 15 +- packages/cli/test/unit/WorkflowRunner.test.ts | 9 +- .../unit/controllers/me.controller.test.ts | 2 +- .../unit/controllers/owner.controller.test.ts | 2 +- 58 files changed, 1223 insertions(+), 1189 deletions(-) delete mode 100644 packages/cli/src/controllers/index.ts create mode 100644 packages/cli/test/integration/shared/db/credentials.ts create mode 100644 packages/cli/test/integration/shared/db/executions.ts create mode 100644 packages/cli/test/integration/shared/db/roles.ts create mode 100644 packages/cli/test/integration/shared/db/tags.ts create mode 100644 packages/cli/test/integration/shared/db/users.ts create mode 100644 packages/cli/test/integration/shared/db/workflowHistory.ts create mode 100644 packages/cli/test/integration/shared/db/workflows.ts diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 4dfd3423f6..3df0781de6 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -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'; diff --git a/packages/cli/src/WorkflowRunner.ts b/packages/cli/src/WorkflowRunner.ts index dad876e47e..02b88fd3ec 100644 --- a/packages/cli/src/WorkflowRunner.ts +++ b/packages/cli/src/WorkflowRunner.ts @@ -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, diff --git a/packages/cli/src/controllers/index.ts b/packages/cli/src/controllers/index.ts deleted file mode 100644 index 9351eff35f..0000000000 --- a/packages/cli/src/controllers/index.ts +++ /dev/null @@ -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'; diff --git a/packages/cli/src/controllers/mfa.controller.ts b/packages/cli/src/controllers/mfa.controller.ts index 70e3444851..415b4b1716 100644 --- a/packages/cli/src/controllers/mfa.controller.ts +++ b/packages/cli/src/controllers/mfa.controller.ts @@ -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 { diff --git a/packages/cli/test/integration/ActiveWorkflowRunner.test.ts b/packages/cli/test/integration/ActiveWorkflowRunner.test.ts index 3b01d57b8d..33c2ffad3e 100644 --- a/packages/cli/test/integration/ActiveWorkflowRunner.test.ts +++ b/packages/cli/test/integration/ActiveWorkflowRunner.test.ts @@ -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, diff --git a/packages/cli/test/integration/ExternalSecrets/externalSecrets.api.test.ts b/packages/cli/test/integration/ExternalSecrets/externalSecrets.api.test.ts index ba2b46ba7f..f07b948a4b 100644 --- a/packages/cli/test/integration/ExternalSecrets/externalSecrets.api.test.ts +++ b/packages/cli/test/integration/ExternalSecrets/externalSecrets.api.test.ts @@ -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); }); diff --git a/packages/cli/test/integration/auth.api.test.ts b/packages/cli/test/integration/auth.api.test.ts index 99944887b9..590263e6ec 100644 --- a/packages/cli/test/integration/auth.api.test.ts +++ b/packages/cli/test/integration/auth.api.test.ts @@ -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'); diff --git a/packages/cli/test/integration/auth.mw.test.ts b/packages/cli/test/integration/auth.mw.test.ts index c3db14926a..60c9eff8fe 100644 --- a/packages/cli/test/integration/auth.mw.test.ts +++ b/packages/cli/test/integration/auth.mw.test.ts @@ -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); }); diff --git a/packages/cli/test/integration/binaryData.api.test.ts b/packages/cli/test/integration/binaryData.api.test.ts index fbb47f2f12..6eddb97137 100644 --- a/packages/cli/test/integration/binaryData.api.test.ts +++ b/packages/cli/test/integration/binaryData.api.test.ts @@ -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); }); diff --git a/packages/cli/test/integration/commands/credentials.cmd.test.ts b/packages/cli/test/integration/commands/credentials.cmd.test.ts index d7ed10c60e..afb6698621 100644 --- a/packages/cli/test/integration/commands/credentials.cmd.test.ts +++ b/packages/cli/test/integration/commands/credentials.cmd.test.ts @@ -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'); diff --git a/packages/cli/test/integration/commands/import.cmd.test.ts b/packages/cli/test/integration/commands/import.cmd.test.ts index b8ad46a65f..ff16690e3b 100644 --- a/packages/cli/test/integration/commands/import.cmd.test.ts +++ b/packages/cli/test/integration/commands/import.cmd.test.ts @@ -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); diff --git a/packages/cli/test/integration/commands/reset.cmd.test.ts b/packages/cli/test/integration/commands/reset.cmd.test.ts index ee41c1f45c..47a973b05c 100644 --- a/packages/cli/test/integration/commands/reset.cmd.test.ts +++ b/packages/cli/test/integration/commands/reset.cmd.test.ts @@ -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(); diff --git a/packages/cli/test/integration/community-packages.api.test.ts b/packages/cli/test/integration/community-packages.api.test.ts index 24fb59dfde..40aa879fdd 100644 --- a/packages/cli/test/integration/community-packages.api.test.ts +++ b/packages/cli/test/integration/community-packages.api.test.ts @@ -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); }); diff --git a/packages/cli/test/integration/credentials.controller.test.ts b/packages/cli/test/integration/credentials.controller.test.ts index b9caa9f95a..12aa5231c4 100644 --- a/packages/cli/test/integration/credentials.controller.test.ts +++ b/packages/cli/test/integration/credentials.controller.test.ts @@ -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) diff --git a/packages/cli/test/integration/credentials.ee.test.ts b/packages/cli/test/integration/credentials.ee.test.ts index bc7222b850..dcef22c17e 100644 --- a/packages/cli/test/integration/credentials.ee.test.ts +++ b/packages/cli/test/integration/credentials.ee.test.ts @@ -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`) diff --git a/packages/cli/test/integration/credentials.test.ts b/packages/cli/test/integration/credentials.test.ts index 3916865fab..e8c8b7af0d 100644 --- a/packages/cli/test/integration/credentials.test.ts +++ b/packages/cli/test/integration/credentials.test.ts @@ -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, }); diff --git a/packages/cli/test/integration/environments/SourceControl.test.ts b/packages/cli/test/integration/environments/SourceControl.test.ts index 13ee4df1e3..b09eff5b4f 100644 --- a/packages/cli/test/integration/environments/SourceControl.test.ts +++ b/packages/cli/test/integration/environments/SourceControl.test.ts @@ -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); diff --git a/packages/cli/test/integration/eventbus.ee.test.ts b/packages/cli/test/integration/eventbus.ee.test.ts index c529109299..8790d365d5 100644 --- a/packages/cli/test/integration/eventbus.ee.test.ts +++ b/packages/cli/test/integration/eventbus.ee.test.ts @@ -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; @@ -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()); diff --git a/packages/cli/test/integration/eventbus.test.ts b/packages/cli/test/integration/eventbus.test.ts index c651215268..b2c62ba11c 100644 --- a/packages/cli/test/integration/eventbus.test.ts +++ b/packages/cli/test/integration/eventbus.test.ts @@ -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); }); diff --git a/packages/cli/test/integration/executions.controller.test.ts b/packages/cli/test/integration/executions.controller.test.ts index 2af9ec5b85..c302ea5660 100644 --- a/packages/cli/test/integration/executions.controller.test.ts +++ b/packages/cli/test/integration/executions.controller.test.ts @@ -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); }); diff --git a/packages/cli/test/integration/ldap/ldap.api.test.ts b/packages/cli/test/integration/ldap/ldap.api.test.ts index 64cf2525fe..cc166716cb 100644 --- a/packages/cli/test/integration/ldap/ldap.api.test.ts +++ b/packages/cli/test/integration/ldap/ldap.api.test.ts @@ -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 = {}): Promise { - 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}`); diff --git a/packages/cli/test/integration/license.api.test.ts b/packages/cli/test/integration/license.api.test.ts index 0688b352d7..30c64c213a 100644 --- a/packages/cli/test/integration/license.api.test.ts +++ b/packages/cli/test/integration/license.api.test.ts @@ -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); diff --git a/packages/cli/test/integration/me.api.test.ts b/packages/cli/test/integration/me.api.test.ts index 05371ce558..330345a12d 100644 --- a/packages/cli/test/integration/me.api.test.ts +++ b/packages/cli/test/integration/me.api.test.ts @@ -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) { diff --git a/packages/cli/test/integration/mfa/mfa.api.test.ts b/packages/cli/test/integration/mfa/mfa.api.test.ts index da959f4013..de94a3333f 100644 --- a/packages/cli/test/integration/mfa/mfa.api.test.ts +++ b/packages/cli/test/integration/mfa/mfa.api.test.ts @@ -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, }); diff --git a/packages/cli/test/integration/owner.api.test.ts b/packages/cli/test/integration/owner.api.test.ts index 6332ae39c1..0819dffc70 100644 --- a/packages/cli/test/integration/owner.api.test.ts +++ b/packages/cli/test/integration/owner.api.test.ts @@ -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); }); diff --git a/packages/cli/test/integration/passwordReset.api.test.ts b/packages/cli/test/integration/passwordReset.api.test.ts index 8bcbd38aba..cd6660deb2 100644 --- a/packages/cli/test/integration/passwordReset.api.test.ts +++ b/packages/cli/test/integration/passwordReset.api.test.ts @@ -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, }); diff --git a/packages/cli/test/integration/pruning.service.test.ts b/packages/cli/test/integration/pruning.service.test.ts index 630f3b4777..65fa9833dc 100644 --- a/packages/cli/test/integration/pruning.service.test.ts +++ b/packages/cli/test/integration/pruning.service.test.ts @@ -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>; + 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(); diff --git a/packages/cli/test/integration/publicApi/credentials.test.ts b/packages/cli/test/integration/publicApi/credentials.test.ts index 2a6e79ea06..e1a03df536 100644 --- a/packages/cli/test/integration/publicApi/credentials.test.ts +++ b/packages/cli/test/integration/publicApi/credentials.test.ts @@ -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(), }); diff --git a/packages/cli/test/integration/publicApi/executions.test.ts b/packages/cli/test/integration/publicApi/executions.test.ts index 0eece7838d..32c069bd0f 100644 --- a/packages/cli/test/integration/publicApi/executions.test.ts +++ b/packages/cli/test/integration/publicApi/executions.test.ts @@ -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'); diff --git a/packages/cli/test/integration/publicApi/users.ee.test.ts b/packages/cli/test/integration/publicApi/users.ee.test.ts index 0bc09448ba..1426486a8a 100644 --- a/packages/cli/test/integration/publicApi/users.ee.test.ts +++ b/packages/cli/test/integration/publicApi/users.ee.test.ts @@ -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(), }); diff --git a/packages/cli/test/integration/publicApi/workflows.test.ts b/packages/cli/test/integration/publicApi/workflows.test.ts index c23c1f3213..b6e18f5994 100644 --- a/packages/cli/test/integration/publicApi/workflows.test.ts +++ b/packages/cli/test/integration/publicApi/workflows.test.ts @@ -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', diff --git a/packages/cli/test/integration/saml/saml.api.test.ts b/packages/cli/test/integration/saml/saml.api.test.ts index 302070df16..768c03fb24 100644 --- a/packages/cli/test/integration/saml/saml.api.test.ts +++ b/packages/cli/test/integration/saml/saml.api.test.ts @@ -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); }); diff --git a/packages/cli/test/integration/shared/db/credentials.ts b/packages/cli/test/integration/shared/db/credentials.ts new file mode 100644 index 0000000000..0ad6edf3af --- /dev/null +++ b/packages/cli/test/integration/shared/db/credentials.ts @@ -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(); +} diff --git a/packages/cli/test/integration/shared/db/executions.ts b/packages/cli/test/integration/shared/db/executions.ts new file mode 100644 index 0000000000..a0f06071ca --- /dev/null +++ b/packages/cli/test/integration/shared/db/executions.ts @@ -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, +) { + 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, + 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(); +} diff --git a/packages/cli/test/integration/shared/db/roles.ts b/packages/cli/test/integration/shared/db/roles.ts new file mode 100644 index 0000000000..9392fc3cc5 --- /dev/null +++ b/packages/cli/test/integration/shared/db/roles.ts @@ -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(), + ]); +} diff --git a/packages/cli/test/integration/shared/db/tags.ts b/packages/cli/test/integration/shared/db/tags.ts new file mode 100644 index 0000000000..7543153cb8 --- /dev/null +++ b/packages/cli/test/integration/shared/db/tags.ts @@ -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 = {}, 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; +} diff --git a/packages/cli/test/integration/shared/db/users.ts b/packages/cli/test/integration/shared/db/users.ts new file mode 100644 index 0000000000..34e637b34f --- /dev/null +++ b/packages/cli/test/integration/shared/db/users.ts @@ -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 = {}): Promise { + const { email, password, firstName, lastName, globalRole, ...rest } = attributes; + const user: Partial = { + 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, ldapId: string): Promise { + 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 { + if (globalRole.scope !== 'global') { + throw new Error(`Invalid role received: ${JSON.stringify(globalRole)}`); + } + + const shell: Partial = { 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 = {}, +): Promise { + 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.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'], + }); diff --git a/packages/cli/test/integration/shared/db/workflowHistory.ts b/packages/cli/test/integration/shared/db/workflowHistory.ts new file mode 100644 index 0000000000..f9589c6469 --- /dev/null +++ b/packages/cli/test/integration/shared/db/workflowHistory.ts @@ -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, +) { + 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), + }), + ), + ); +} diff --git a/packages/cli/test/integration/shared/db/workflows.ts b/packages/cli/test/integration/shared/db/workflows.ts new file mode 100644 index 0000000000..285c5e94f7 --- /dev/null +++ b/packages/cli/test/integration/shared/db/workflows.ts @@ -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 = {}, + 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 = {}, 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 = {}, + 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(); +} diff --git a/packages/cli/test/integration/shared/testDb.ts b/packages/cli/test/integration/shared/testDb.ts index 7330b9c8e6..78f38a75ac 100644 --- a/packages/cli/test/integration/shared/testDb.ts +++ b/packages/cli/test/integration/shared/testDb.ts @@ -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 = {}): Promise { - const { email, password, firstName, lastName, globalRole, ...rest } = attributes; - const user: Partial = { - 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, ldapId: string): Promise { - 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 { - if (globalRole.scope !== 'global') { - throw new Error(`Invalid role received: ${JSON.stringify(globalRole)}`); - } - - const shell: Partial = { 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 = {}, -): Promise { - 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.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, -) { - 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, - 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 = {}, 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 = {}, - 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 = {}, 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 = {}, - 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, -) { - 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; -} diff --git a/packages/cli/test/integration/shared/types.ts b/packages/cli/test/integration/shared/types.ts index d6ff1a77b3..54c23b5dee 100644 --- a/packages/cli/test/integration/shared/types.ts +++ b/packages/cli/test/integration/shared/types.ts @@ -12,7 +12,7 @@ export type CollectionName = | keyof IDatabaseCollections | { new (dataSource: DataSource): Repository }; -export type EndpointGroup = +type EndpointGroup = | 'me' | 'users' | 'auth' diff --git a/packages/cli/test/integration/shared/utils/index.ts b/packages/cli/test/integration/shared/utils/index.ts index ac45600e69..280a8bc02b 100644 --- a/packages/cli/test/integration/shared/utils/index.ts +++ b/packages/cli/test/integration/shared/utils/index.ts @@ -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 { +export async function initActiveWorkflowRunner() { + const { ActiveWorkflowRunner } = await import('@/ActiveWorkflowRunner'); const workflowRunner = Container.get(ActiveWorkflowRunner); await workflowRunner.init(); return workflowRunner; diff --git a/packages/cli/test/integration/shared/utils/testServer.ts b/packages/cli/test/integration/shared/utils/testServer.ts index 3d202fe4e5..11c32c2512 100644 --- a/packages/cli/test/integration/shared/utils/testServer.ts +++ b/packages/cli/test/integration/shared/utils/testServer.ts @@ -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 = { - 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; } diff --git a/packages/cli/test/integration/tags.api.test.ts b/packages/cli/test/integration/tags.api.test.ts index eabe0d931f..b929c55f45 100644 --- a/packages/cli/test/integration/tags.api.test.ts +++ b/packages/cli/test/integration/tags.api.test.ts @@ -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); }); diff --git a/packages/cli/test/integration/users.api.test.ts b/packages/cli/test/integration/users.api.test.ts index 1373e3a0c5..0ce7d5a8e2 100644 --- a/packages/cli/test/integration/users.api.test.ts +++ b/packages/cli/test/integration/users.api.test.ts @@ -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); diff --git a/packages/cli/test/integration/users.controller.test.ts b/packages/cli/test/integration/users.controller.test.ts index 0dc5d41a28..8af36533a6 100644 --- a/packages/cli/test/integration/users.controller.test.ts +++ b/packages/cli/test/integration/users.controller.test.ts @@ -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) diff --git a/packages/cli/test/integration/variables.test.ts b/packages/cli/test/integration/variables.test.ts index 701e6c4b08..da1611c275 100644 --- a/packages/cli/test/integration/variables.test.ts +++ b/packages/cli/test/integration/variables.test.ts @@ -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'); diff --git a/packages/cli/test/integration/webhooks.api.test.ts b/packages/cli/test/integration/webhooks.api.test.ts index d38375f36d..b352bf395b 100644 --- a/packages/cli/test/integration/webhooks.api.test.ts +++ b/packages/cli/test/integration/webhooks.api.test.ts @@ -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); diff --git a/packages/cli/test/integration/workflowHistory.api.test.ts b/packages/cli/test/integration/workflowHistory.api.test.ts index 1a7fbe2bc0..03c6390557 100644 --- a/packages/cli/test/integration/workflowHistory.api.test.ts +++ b/packages/cli/test/integration/workflowHistory.api.test.ts @@ -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}`, ); diff --git a/packages/cli/test/integration/workflowHistoryManager.test.ts b/packages/cli/test/integration/workflowHistoryManager.test.ts index e03d3b4b0e..497e5919fe 100644 --- a/packages/cli/test/integration/workflowHistoryManager.test.ts +++ b/packages/cli/test/integration/workflowHistoryManager.test.ts @@ -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) => { diff --git a/packages/cli/test/integration/workflows.controller.ee.test.ts b/packages/cli/test/integration/workflows.controller.ee.test.ts index f09c716537..21e13885f2 100644 --- a/packages/cli/test/integration/workflows.controller.ee.test.ts +++ b/packages/cli/test/integration/workflows.controller.ee.test.ts @@ -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, diff --git a/packages/cli/test/integration/workflows.controller.test.ts b/packages/cli/test/integration/workflows.controller.test.ts index 2a816de1db..f8126a4480 100644 --- a/packages/cli/test/integration/workflows.controller.test.ts +++ b/packages/cli/test/integration/workflows.controller.test.ts @@ -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, diff --git a/packages/cli/test/unit/CredentialsHelper.test.ts b/packages/cli/test/unit/CredentialsHelper.test.ts index b2515b8a92..5556fb67b7 100644 --- a/packages/cli/test/unit/CredentialsHelper.test.ts +++ b/packages/cli/test/unit/CredentialsHelper.test.ts @@ -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': { diff --git a/packages/cli/test/unit/InternalHooks.test.ts b/packages/cli/test/unit/InternalHooks.test.ts index 3093dc109e..dea011723b 100644 --- a/packages/cli/test/unit/InternalHooks.test.ts +++ b/packages/cli/test/unit/InternalHooks.test.ts @@ -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', () => { diff --git a/packages/cli/test/unit/PermissionChecker.test.ts b/packages/cli/test/unit/PermissionChecker.test.ts index e0c8e33b0b..8784c1a517 100644 --- a/packages/cli/test/unit/PermissionChecker.test.ts +++ b/packages/cli/test/unit/PermissionChecker.test.ts @@ -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 }); diff --git a/packages/cli/test/unit/WorkflowRunner.test.ts b/packages/cli/test/unit/WorkflowRunner.test.ts index ecd3436494..91f8c7362f 100644 --- a/packages/cli/test/unit/WorkflowRunner.test.ts +++ b/packages/cli/test/unit/WorkflowRunner.test.ts @@ -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()); diff --git a/packages/cli/test/unit/controllers/me.controller.test.ts b/packages/cli/test/unit/controllers/me.controller.test.ts index 8ac2a3b826..5f4e8fdbba 100644 --- a/packages/cli/test/unit/controllers/me.controller.test.ts +++ b/packages/cli/test/unit/controllers/me.controller.test.ts @@ -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'; diff --git a/packages/cli/test/unit/controllers/owner.controller.test.ts b/packages/cli/test/unit/controllers/owner.controller.test.ts index b131f2c04d..58f37ec5ac 100644 --- a/packages/cli/test/unit/controllers/owner.controller.test.ts +++ b/packages/cli/test/unit/controllers/owner.controller.test.ts @@ -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';