refactor(core): Refactor cli command tests (no-changelog) (#9731)

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™ 2024-06-18 10:50:39 +02:00 committed by GitHub
parent fb73ec3994
commit 2d02c73fbd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 160 additions and 250 deletions

View file

@ -14,7 +14,7 @@ import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData'
import config from '@/config';
import type { Job, JobId, JobResponse, WebhookResponse } from '@/Queue';
import { Queue } from '@/Queue';
import { N8N_VERSION } from '@/constants';
import { N8N_VERSION, inTest } from '@/constants';
import { ExecutionRepository } from '@db/repositories/execution.repository';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import type { ICredentialsOverwrite } from '@/Interfaces';
@ -498,7 +498,7 @@ export class Worker extends BaseCommand {
}
// Make sure that the process does not close
await new Promise(() => {});
if (!inTest) await new Promise(() => {});
}
async catch(error: Error) {

View file

@ -1,39 +1,24 @@
import { Config } from '@oclif/core';
import { nanoid } from 'nanoid';
import { InternalHooks } from '@/InternalHooks';
import { ImportCredentialsCommand } from '@/commands/import/credentials';
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
import { setupTestCommand } from '@test-integration/utils/testCommand';
import { mockInstance } from '../../shared/mocking';
import * as testDb from '../shared/testDb';
import { getAllCredentials, getAllSharedCredentials } from '../shared/db/credentials';
import { createMember, createOwner } from '../shared/db/users';
import { getPersonalProject } from '../shared/db/projects';
import { nanoid } from 'nanoid';
const oclifConfig = new Config({ root: __dirname });
async function importCredential(argv: string[]) {
const importer = new ImportCredentialsCommand(argv, oclifConfig);
await importer.init();
await importer.run();
}
beforeAll(async () => {
mockInstance(InternalHooks);
mockInstance(LoadNodesAndCredentials);
await testDb.init();
await oclifConfig.load();
});
mockInstance(InternalHooks);
mockInstance(LoadNodesAndCredentials);
const command = setupTestCommand(ImportCredentialsCommand);
beforeEach(async () => {
await testDb.truncate(['Credentials', 'SharedCredentials', 'User']);
});
afterAll(async () => {
await testDb.terminate();
});
test('import:credentials should import a credential', async () => {
//
// ARRANGE
@ -44,9 +29,7 @@ test('import:credentials should import a credential', async () => {
//
// ACT
//
await importCredential([
'--input=./test/integration/commands/importCredentials/credentials.json',
]);
await command.run(['--input=./test/integration/commands/importCredentials/credentials.json']);
//
// ASSERT
@ -78,7 +61,7 @@ test('import:credentials should import a credential from separated files', async
// ACT
//
// import credential the first time, assigning it to the owner
await importCredential([
await command.run([
'--separate',
'--input=./test/integration/commands/importCredentials/separate',
]);
@ -117,7 +100,7 @@ test('`import:credentials --userId ...` should fail if the credential exists alr
const member = await createMember();
// import credential the first time, assigning it to the owner
await importCredential([
await command.run([
'--input=./test/integration/commands/importCredentials/credentials.json',
`--userId=${owner.id}`,
]);
@ -145,7 +128,7 @@ test('`import:credentials --userId ...` should fail if the credential exists alr
// Import again while updating the name we try to assign the
// credential to another user.
await expect(
importCredential([
command.run([
'--input=./test/integration/commands/importCredentials/credentials-updated.json',
`--userId=${member.id}`,
]),
@ -188,7 +171,7 @@ test("only update credential, don't create or update owner if neither `--userId`
const memberProject = await getPersonalProject(member);
// import credential the first time, assigning it to a member
await importCredential([
await command.run([
'--input=./test/integration/commands/importCredentials/credentials.json',
`--userId=${member.id}`,
]);
@ -213,7 +196,7 @@ test("only update credential, don't create or update owner if neither `--userId`
// ACT
//
// Import again only updating the name and omitting `--userId`
await importCredential([
await command.run([
'--input=./test/integration/commands/importCredentials/credentials-updated.json',
]);
@ -253,7 +236,7 @@ test('`import:credential --projectId ...` should fail if the credential already
const memberProject = await getPersonalProject(member);
// import credential the first time, assigning it to the owner
await importCredential([
await command.run([
'--input=./test/integration/commands/importCredentials/credentials.json',
`--userId=${owner.id}`,
]);
@ -281,7 +264,7 @@ test('`import:credential --projectId ...` should fail if the credential already
// Import again while updating the name we try to assign the
// credential to another user.
await expect(
importCredential([
command.run([
'--input=./test/integration/commands/importCredentials/credentials-updated.json',
`--projectId=${memberProject.id}`,
]),
@ -317,7 +300,7 @@ test('`import:credential --projectId ...` should fail if the credential already
test('`import:credential --projectId ... --userId ...` fails explaining that only one of the options can be used at a time', async () => {
await expect(
importCredential([
command.run([
'--input=./test/integration/commands/importCredentials/credentials-updated.json',
`--projectId=${nanoid()}`,
`--userId=${nanoid()}`,

View file

@ -1,39 +1,24 @@
import { Config } from '@oclif/core';
import { nanoid } from 'nanoid';
import { InternalHooks } from '@/InternalHooks';
import { ImportWorkflowsCommand } from '@/commands/import/workflow';
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
import { setupTestCommand } from '@test-integration/utils/testCommand';
import { mockInstance } from '../../shared/mocking';
import * as testDb from '../shared/testDb';
import { getAllSharedWorkflows, getAllWorkflows } from '../shared/db/workflows';
import { createMember, createOwner } from '../shared/db/users';
import { getPersonalProject } from '../shared/db/projects';
import { nanoid } from 'nanoid';
const oclifConfig = new Config({ root: __dirname });
async function importWorkflow(argv: string[]) {
const importer = new ImportWorkflowsCommand(argv, oclifConfig);
await importer.init();
await importer.run();
}
beforeAll(async () => {
mockInstance(InternalHooks);
mockInstance(LoadNodesAndCredentials);
await testDb.init();
await oclifConfig.load();
});
mockInstance(InternalHooks);
mockInstance(LoadNodesAndCredentials);
const command = setupTestCommand(ImportWorkflowsCommand);
beforeEach(async () => {
await testDb.truncate(['Workflow', 'SharedWorkflow', 'User']);
});
afterAll(async () => {
await testDb.terminate();
});
test('import:workflow should import active workflow and deactivate it', async () => {
//
// ARRANGE
@ -44,10 +29,7 @@ test('import:workflow should import active workflow and deactivate it', async ()
//
// ACT
//
await importWorkflow([
'--separate',
'--input=./test/integration/commands/importWorkflows/separate',
]);
await command.run(['--separate', '--input=./test/integration/commands/importWorkflows/separate']);
//
// ASSERT
@ -86,9 +68,7 @@ test('import:workflow should import active workflow from combined file and deact
//
// ACT
//
await importWorkflow([
'--input=./test/integration/commands/importWorkflows/combined/combined.json',
]);
await command.run(['--input=./test/integration/commands/importWorkflows/combined/combined.json']);
//
// ASSERT
@ -126,7 +106,7 @@ test('`import:workflow --userId ...` should fail if the workflow exists already
const member = await createMember();
// Import workflow the first time, assigning it to a member.
await importWorkflow([
await command.run([
'--input=./test/integration/commands/importWorkflows/combined-with-update/original.json',
`--userId=${owner.id}`,
]);
@ -153,7 +133,7 @@ test('`import:workflow --userId ...` should fail if the workflow exists already
// Import the same workflow again, with another name but the same ID, and try
// to assign it to the member.
await expect(
importWorkflow([
command.run([
'--input=./test/integration/commands/importWorkflows/combined-with-update/updated.json',
`--userId=${member.id}`,
]),
@ -190,7 +170,7 @@ test("only update the workflow, don't create or update the owner if `--userId` i
const memberProject = await getPersonalProject(member);
// Import workflow the first time, assigning it to a member.
await importWorkflow([
await command.run([
'--input=./test/integration/commands/importWorkflows/combined-with-update/original.json',
`--userId=${member.id}`,
]);
@ -215,7 +195,7 @@ test("only update the workflow, don't create or update the owner if `--userId` i
// ACT
//
// Import the same workflow again, with another name but the same ID.
await importWorkflow([
await command.run([
'--input=./test/integration/commands/importWorkflows/combined-with-update/updated.json',
]);
@ -249,7 +229,7 @@ test('`import:workflow --projectId ...` should fail if the credential already ex
const memberProject = await getPersonalProject(member);
// Import workflow the first time, assigning it to a member.
await importWorkflow([
await command.run([
'--input=./test/integration/commands/importWorkflows/combined-with-update/original.json',
`--userId=${owner.id}`,
]);
@ -276,7 +256,7 @@ test('`import:workflow --projectId ...` should fail if the credential already ex
// Import the same workflow again, with another name but the same ID, and try
// to assign it to the member.
await expect(
importWorkflow([
command.run([
'--input=./test/integration/commands/importWorkflows/combined-with-update/updated.json',
`--projectId=${memberProject.id}`,
]),
@ -306,7 +286,7 @@ test('`import:workflow --projectId ...` should fail if the credential already ex
test('`import:workflow --projectId ... --userId ...` fails explaining that only one of the options can be used at a time', async () => {
await expect(
importWorkflow([
command.run([
'--input=./test/integration/commands/importWorkflows/combined-with-update/updated.json',
`--userId=${nanoid()}`,
`--projectId=${nanoid()}`,

View file

@ -1,57 +1,37 @@
import { Reset } from '@/commands/ldap/reset';
import { Config } from '@oclif/core';
import { Container } from 'typedi';
import { v4 as uuid } from 'uuid';
import { EntityNotFoundError } from '@n8n/typeorm';
import * as testDb from '../../shared/testDb';
import { Reset } from '@/commands/ldap/reset';
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
import { mockInstance } from '../../../shared/mocking';
import { InternalHooks } from '@/InternalHooks';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
import { getLdapSynchronizations, saveLdapSynchronization } from '@/Ldap/helpers';
import { LdapService } from '@/Ldap/ldap.service';
import { Push } from '@/push';
import { Telemetry } from '@/telemetry';
import { setupTestCommand } from '@test-integration/utils/testCommand';
import { mockInstance } from '../../../shared/mocking';
import { createLdapUser, createMember, getUserById } from '../../shared/db/users';
import { createWorkflow } from '../../shared/db/workflows';
import { randomCredentialPayload } from '../../shared/random';
import { saveCredential } from '../../shared/db/credentials';
import Container from 'typedi';
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
import { CredentialsRepository } from '@/databases/repositories/credentials.repository';
import { EntityNotFoundError } from '@n8n/typeorm';
import { Push } from '@/push';
import { SharedWorkflowRepository } from '@/databases/repositories/sharedWorkflow.repository';
import { SharedCredentialsRepository } from '@/databases/repositories/sharedCredentials.repository';
import { createTeamProject, findProject, getPersonalProject } from '../../shared/db/projects';
import { getLdapSynchronizations, saveLdapSynchronization } from '@/Ldap/helpers';
import { createLdapConfig } from '../../shared/ldap';
import { LdapService } from '@/Ldap/ldap.service';
import { v4 as uuid } from 'uuid';
import { Telemetry } from '@/telemetry';
import { createTeamProject, findProject, getPersonalProject } from '../../shared/db/projects';
mockInstance(Telemetry);
const oclifConfig = new Config({ root: __dirname });
async function resetLDAP(argv: string[]) {
const cmd = new Reset(argv, oclifConfig);
try {
await cmd.init();
} catch (error) {
console.error(error);
throw error;
}
await cmd.run();
}
beforeAll(async () => {
mockInstance(Push);
mockInstance(InternalHooks);
mockInstance(LoadNodesAndCredentials);
await testDb.init();
await oclifConfig.load();
});
afterAll(async () => {
await testDb.terminate();
});
mockInstance(Push);
mockInstance(InternalHooks);
mockInstance(LoadNodesAndCredentials);
const command = setupTestCommand(Reset);
test('fails if neither `--userId` nor `--projectId` nor `--deleteWorkflowsAndCredentials` is passed', async () => {
await expect(resetLDAP([])).rejects.toThrowError(
await expect(command.run()).rejects.toThrowError(
'You must use exactly one of `--userId`, `--projectId` or `--deleteWorkflowsAndCredentials`.',
);
});
@ -66,7 +46,7 @@ test.each([
])(
'fails if more than one of `--userId`, `--projectId`, `--deleteWorkflowsAndCredentials` are passed',
async (...argv) => {
await expect(resetLDAP(argv)).rejects.toThrowError(
await expect(command.run(argv)).rejects.toThrowError(
'You must use exactly one of `--userId`, `--projectId` or `--deleteWorkflowsAndCredentials`.',
);
},
@ -95,7 +75,7 @@ describe('--deleteWorkflowsAndCredentials', () => {
//
// ACT
//
await resetLDAP(['--deleteWorkflowsAndCredentials']);
await command.run(['--deleteWorkflowsAndCredentials']);
//
// ASSERT
@ -139,7 +119,7 @@ describe('--deleteWorkflowsAndCredentials', () => {
//
// ACT
//
await resetLDAP(['--deleteWorkflowsAndCredentials']);
await command.run(['--deleteWorkflowsAndCredentials']);
//
// ASSERT
@ -159,7 +139,7 @@ describe('--deleteWorkflowsAndCredentials', () => {
//
// ACT
//
await resetLDAP(['--deleteWorkflowsAndCredentials']);
await command.run(['--deleteWorkflowsAndCredentials']);
//
// ASSERT
@ -173,7 +153,7 @@ describe('--deleteWorkflowsAndCredentials', () => {
describe('--userId', () => {
test('fails if the user does not exist', async () => {
const userId = uuid();
await expect(resetLDAP([`--userId=${userId}`])).rejects.toThrowError(
await expect(command.run([`--userId=${userId}`])).rejects.toThrowError(
`Could not find the user with the ID ${userId} or their personalProject.`,
);
});
@ -184,7 +164,7 @@ describe('--userId', () => {
//
const member = await createLdapUser({ role: 'global:member' }, uuid());
await expect(resetLDAP([`--userId=${member.id}`])).rejects.toThrowError(
await expect(command.run([`--userId=${member.id}`])).rejects.toThrowError(
`Can't migrate workflows and credentials to the user with the ID ${member.id}. That user was created via LDAP and will be deleted as well.`,
);
});
@ -212,7 +192,7 @@ describe('--userId', () => {
//
// ACT
//
await resetLDAP([`--userId=${normalMember.id}`]);
await command.run([`--userId=${normalMember.id}`]);
//
// ASSERT
@ -249,7 +229,7 @@ describe('--userId', () => {
describe('--projectId', () => {
test('fails if the project does not exist', async () => {
const projectId = uuid();
await expect(resetLDAP([`--projectId=${projectId}`])).rejects.toThrowError(
await expect(command.run([`--projectId=${projectId}`])).rejects.toThrowError(
`Could not find the project with the ID ${projectId}.`,
);
});
@ -261,7 +241,7 @@ describe('--projectId', () => {
const member = await createLdapUser({ role: 'global:member' }, uuid());
const memberProject = await getPersonalProject(member);
await expect(resetLDAP([`--projectId=${memberProject.id}`])).rejects.toThrowError(
await expect(command.run([`--projectId=${memberProject.id}`])).rejects.toThrowError(
`Can't migrate workflows and credentials to the project with the ID ${memberProject.id}. That project is a personal project belonging to a user that was created via LDAP and will be deleted as well.`,
);
});
@ -289,7 +269,7 @@ describe('--projectId', () => {
//
// ACT
//
await resetLDAP([`--projectId=${normalMemberProject.id}`]);
await command.run([`--projectId=${normalMemberProject.id}`]);
//
// ASSERT
@ -346,7 +326,7 @@ describe('--projectId', () => {
//
// ACT
//
await resetLDAP([`--projectId=${teamProject.id}`]);
await command.run([`--projectId=${teamProject.id}`]);
//
// ASSERT

View file

@ -2,27 +2,18 @@ import { InternalHooks } from '@/InternalHooks';
import { License } from '@/License';
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
import { ClearLicenseCommand } from '@/commands/license/clear';
import { Config } from '@oclif/core';
import { setupTestCommand } from '@test-integration/utils/testCommand';
import { mockInstance } from '../../shared/mocking';
const oclifConfig = new Config({ root: __dirname });
beforeAll(async () => {
mockInstance(InternalHooks);
mockInstance(LoadNodesAndCredentials);
await oclifConfig.load();
});
mockInstance(InternalHooks);
mockInstance(LoadNodesAndCredentials);
const license = mockInstance(License);
const command = setupTestCommand(ClearLicenseCommand);
test('license:clear invokes shutdown() to release any floating entitlements', async () => {
const cmd = new ClearLicenseCommand([], oclifConfig);
await cmd.init();
const license = mockInstance(License);
await cmd.run();
await command.run();
expect(license.init).toHaveBeenCalledTimes(1);
expect(license.shutdown).toHaveBeenCalledTimes(1);
jest.restoreAllMocks();
});

View file

@ -1,38 +1,34 @@
import { Container } from 'typedi';
import { Reset } from '@/commands/user-management/reset';
import { InternalHooks } from '@/InternalHooks';
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
import { NodeTypes } from '@/NodeTypes';
import Container from 'typedi';
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import { CredentialsEntity } from '@db/entities/CredentialsEntity';
import { SettingsRepository } from '@db/repositories/settings.repository';
import { UserRepository } from '@db/repositories/user.repository';
import { setupTestCommand } from '@test-integration/utils/testCommand';
import { mockInstance } from '../../shared/mocking';
import * as testDb from '../shared/testDb';
import { createMember, createUser } from '../shared/db/users';
import { createWorkflow } from '../shared/db/workflows';
import { SharedWorkflowRepository } from '@/databases/repositories/sharedWorkflow.repository';
import { getPersonalProject } from '../shared/db/projects';
import { encryptCredentialData, saveCredential } from '../shared/db/credentials';
import { randomCredentialPayload } from '../shared/random';
import { SharedCredentialsRepository } from '@/databases/repositories/sharedCredentials.repository';
import { CredentialsRepository } from '@/databases/repositories/credentials.repository';
import { CredentialsEntity } from '@/databases/entities/CredentialsEntity';
import { SettingsRepository } from '@/databases/repositories/settings.repository';
beforeAll(async () => {
mockInstance(InternalHooks);
mockInstance(LoadNodesAndCredentials);
mockInstance(NodeTypes);
await testDb.init();
});
mockInstance(InternalHooks);
mockInstance(LoadNodesAndCredentials);
mockInstance(NodeTypes);
const command = setupTestCommand(Reset);
beforeEach(async () => {
await testDb.truncate(['User']);
});
afterAll(async () => {
await testDb.terminate();
});
// eslint-disable-next-line n8n-local-rules/no-skipped-tests
test('user-management:reset should reset DB to default user state', async () => {
//
@ -65,7 +61,7 @@ test('user-management:reset should reset DB to default user state', async () =>
//
// ACT
//
await Reset.run();
await command.run();
//
// ASSERT

View file

@ -1,29 +1,20 @@
import { Config } from '@oclif/core';
import { InternalHooks } from '@/InternalHooks';
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
import { UpdateWorkflowCommand } from '@/commands/update/workflow';
import { setupTestCommand } from '@test-integration/utils/testCommand';
import * as testDb from '../../shared/testDb';
import { createWorkflowWithTrigger, getAllWorkflows } from '../../shared/db/workflows';
import { mockInstance } from '../../../shared/mocking';
const oclifConfig = new Config({ root: __dirname });
beforeAll(async () => {
mockInstance(InternalHooks);
mockInstance(LoadNodesAndCredentials);
await testDb.init();
await oclifConfig.load();
});
mockInstance(InternalHooks);
mockInstance(LoadNodesAndCredentials);
const command = setupTestCommand(UpdateWorkflowCommand);
beforeEach(async () => {
await testDb.truncate(['Workflow']);
});
afterAll(async () => {
await testDb.terminate();
});
test('update:workflow can activate all workflows', async () => {
//
// ARRANGE
@ -37,9 +28,7 @@ test('update:workflow can activate all workflows', async () => {
//
// ACT
//
const updater = new UpdateWorkflowCommand(['--all', '--active=true'], oclifConfig);
await updater.init();
await updater.run();
await command.run(['--all', '--active=true']);
//
// ASSERT
@ -61,9 +50,7 @@ test('update:workflow can deactivate all workflows', async () => {
//
// ACT
//
const updater = new UpdateWorkflowCommand(['--all', '--active=false'], oclifConfig);
await updater.init();
await updater.run();
await command.run(['--all', '--active=false']);
//
// ASSERT
@ -87,12 +74,7 @@ test('update:workflow can activate a specific workflow', async () => {
//
// ACT
//
const updater = new UpdateWorkflowCommand(
[`--id=${workflows[0].id}`, '--active=true'],
oclifConfig,
);
await updater.init();
await updater.run();
await command.run([`--id=${workflows[0].id}`, '--active=true']);
//
// ASSERT
@ -116,12 +98,7 @@ test('update:workflow can deactivate a specific workflow', async () => {
//
// ACT
//
const updater = new UpdateWorkflowCommand(
[`--id=${workflows[0].id}`, '--active=false'],
oclifConfig,
);
await updater.init();
await updater.run();
await command.run([`--id=${workflows[0].id}`, '--active=false']);
//
// ASSERT

View file

@ -1,85 +1,51 @@
import { Config } from '@oclif/core';
import { BinaryDataService } from 'n8n-core';
import { mock } from 'jest-mock-extended';
import { Worker } from '@/commands/worker';
import config from '@/config';
import { Telemetry } from '@/telemetry';
import { ExternalSecretsManager } from '@/ExternalSecrets/ExternalSecretsManager.ee';
import { BinaryDataService } from 'n8n-core';
import { CacheService } from '@/services/cache/cache.service';
import { RedisServicePubSubPublisher } from '@/services/redis/RedisServicePubSubPublisher';
import { RedisServicePubSubSubscriber } from '@/services/redis/RedisServicePubSubSubscriber';
import { MessageEventBus } from '@/eventbus/MessageEventBus/MessageEventBus';
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
import { CredentialTypes } from '@/CredentialTypes';
import { NodeTypes } from '@/NodeTypes';
import { InternalHooks } from '@/InternalHooks';
import { PostHogClient } from '@/posthog';
import { RedisService } from '@/services/redis.service';
import { OrchestrationHandlerWorkerService } from '@/services/orchestration/worker/orchestration.handler.worker.service';
import { OrchestrationService } from '@/services/orchestration.service';
import { OrchestrationWorkerService } from '@/services/orchestration/worker/orchestration.worker.service';
import { License } from '@/License';
import { ExternalHooks } from '@/ExternalHooks';
import { type JobQueue, Queue } from '@/Queue';
import * as testDb from '../shared/testDb';
import { setupTestCommand } from '@test-integration/utils/testCommand';
import { mockInstance } from '../../shared/mocking';
const oclifConfig = new Config({ root: __dirname });
config.set('executions.mode', 'queue');
config.set('binaryDataManager.availableModes', 'filesystem');
mockInstance(InternalHooks);
mockInstance(LoadNodesAndCredentials);
const binaryDataService = mockInstance(BinaryDataService);
const externalHooks = mockInstance(ExternalHooks);
const externalSecretsManager = mockInstance(ExternalSecretsManager);
const license = mockInstance(License);
const messageEventBus = mockInstance(MessageEventBus);
const orchestrationHandlerWorkerService = mockInstance(OrchestrationHandlerWorkerService);
const queue = mockInstance(Queue);
const orchestrationWorkerService = mockInstance(OrchestrationWorkerService);
const command = setupTestCommand(Worker);
let eventBus: MessageEventBus;
beforeAll(async () => {
config.set('executions.mode', 'queue');
config.set('binaryDataManager.availableModes', 'filesystem');
mockInstance(Telemetry);
mockInstance(PostHogClient);
mockInstance(InternalHooks);
mockInstance(CacheService);
mockInstance(ExternalSecretsManager);
mockInstance(BinaryDataService);
eventBus = mockInstance(MessageEventBus);
mockInstance(LoadNodesAndCredentials);
mockInstance(CredentialTypes);
mockInstance(NodeTypes);
mockInstance(RedisService);
mockInstance(RedisServicePubSubPublisher);
mockInstance(RedisServicePubSubSubscriber);
mockInstance(OrchestrationService);
await testDb.init();
await oclifConfig.load();
});
afterAll(async () => {
await testDb.terminate();
});
queue.getBullObjectInstance.mockReturnValue(mock<JobQueue>({ on: jest.fn() }));
test('worker initializes all its components', async () => {
const worker = new Worker([], oclifConfig);
jest.spyOn(worker, 'init');
jest.spyOn(worker, 'initLicense').mockImplementation(async () => {});
jest.spyOn(worker, 'initBinaryDataService').mockImplementation(async () => {});
jest.spyOn(worker, 'initExternalHooks').mockImplementation(async () => {});
jest.spyOn(worker, 'initExternalSecrets').mockImplementation(async () => {});
jest.spyOn(worker, 'initEventBus').mockImplementation(async () => {});
jest.spyOn(worker, 'initOrchestration');
// jest.spyOn(MessageEventBus.prototype, 'send').mockImplementation(async () => {});
jest
.spyOn(OrchestrationHandlerWorkerService.prototype, 'initSubscriber')
.mockImplementation(async () => {});
jest.spyOn(RedisServicePubSubPublisher.prototype, 'init').mockImplementation(async () => {});
jest.spyOn(worker, 'initQueue').mockImplementation(async () => {});
await worker.init();
const worker = await command.run();
expect(worker.queueModeId).toBeDefined();
expect(worker.queueModeId).toContain('worker');
expect(worker.queueModeId.length).toBeGreaterThan(15);
expect(worker.initLicense).toHaveBeenCalledTimes(1);
expect(worker.initBinaryDataService).toHaveBeenCalledTimes(1);
expect(worker.initExternalHooks).toHaveBeenCalledTimes(1);
expect(worker.initExternalSecrets).toHaveBeenCalledTimes(1);
expect(worker.initEventBus).toHaveBeenCalledTimes(1);
expect(worker.initOrchestration).toHaveBeenCalledTimes(1);
expect(OrchestrationHandlerWorkerService.prototype.initSubscriber).toHaveBeenCalledTimes(1);
expect(eventBus.send).toHaveBeenCalledTimes(1);
expect(worker.initQueue).toHaveBeenCalledTimes(1);
jest.restoreAllMocks();
expect(license.init).toHaveBeenCalledTimes(1);
expect(binaryDataService.init).toHaveBeenCalledTimes(1);
expect(externalHooks.init).toHaveBeenCalledTimes(1);
expect(externalSecretsManager.init).toHaveBeenCalledTimes(1);
expect(messageEventBus.initialize).toHaveBeenCalledTimes(1);
expect(queue.init).toHaveBeenCalledTimes(1);
expect(queue.process).toHaveBeenCalledTimes(1);
expect(orchestrationWorkerService.init).toHaveBeenCalledTimes(1);
expect(orchestrationHandlerWorkerService.initWithOptions).toHaveBeenCalledTimes(1);
expect(messageEventBus.send).toHaveBeenCalledTimes(1);
});

View file

@ -0,0 +1,37 @@
import type { Config } from '@oclif/core';
import type { Class } from 'n8n-core';
import { mock } from 'jest-mock-extended';
import type { BaseCommand } from '@/commands/BaseCommand';
import * as testDb from '../testDb';
export const setupTestCommand = <T extends BaseCommand>(Command: Class<T>) => {
const config = mock<Config>();
config.runHook.mockResolvedValue({ successes: [], failures: [] });
// mock SIGINT/SIGTERM registration
process.once = jest.fn();
beforeAll(async () => {
await testDb.init();
});
beforeEach(() => {
jest.clearAllMocks();
});
afterAll(async () => {
await testDb.terminate();
jest.restoreAllMocks();
});
const run = async (argv: string[] = []) => {
const command = new Command(argv, config);
await command.init();
await command.run();
return command;
};
return { run };
};