refactor(core): Add central license mock for integration tests (no-changelog) (#7871)

Github issue / Community forum post (link here to close automatically):
This commit is contained in:
Val 2023-11-30 08:23:09 +00:00 committed by GitHub
parent b16dd21909
commit 5f4a9524ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 124 additions and 94 deletions

View file

@ -24,15 +24,13 @@ import {
let authOwnerAgent: SuperAgentTest; let authOwnerAgent: SuperAgentTest;
let authMemberAgent: SuperAgentTest; let authMemberAgent: SuperAgentTest;
const licenseLike = mockInstance(License, {
isExternalSecretsEnabled: jest.fn().mockReturnValue(true),
isWithinUsersLimit: jest.fn().mockReturnValue(true),
});
const mockProvidersInstance = new MockProviders(); const mockProvidersInstance = new MockProviders();
mockInstance(ExternalSecretsProviders, mockProvidersInstance); mockInstance(ExternalSecretsProviders, mockProvidersInstance);
const testServer = setupTestServer({ endpointGroups: ['externalSecrets'] }); const testServer = setupTestServer({
endpointGroups: ['externalSecrets'],
enabledFeatures: ['feat:externalSecrets'],
});
const connectedDate = '2023-08-01T12:32:29.000Z'; const connectedDate = '2023-08-01T12:32:29.000Z';
@ -57,7 +55,7 @@ const resetManager = async () => {
new ExternalSecretsManager( new ExternalSecretsManager(
mock(), mock(),
Container.get(SettingsRepository), Container.get(SettingsRepository),
licenseLike, Container.get(License),
mockProvidersInstance, mockProvidersInstance,
Container.get(Cipher), Container.get(Cipher),
), ),
@ -107,8 +105,6 @@ beforeAll(async () => {
}); });
beforeEach(async () => { beforeEach(async () => {
licenseLike.isExternalSecretsEnabled.mockReturnValue(true);
mockProvidersInstance.setProviders({ mockProvidersInstance.setProviders({
dummy: DummyProvider, dummy: DummyProvider,
}); });
@ -339,7 +335,7 @@ describe('POST /external-secrets/providers/:provider/update', () => {
'update', 'update',
); );
licenseLike.isExternalSecretsEnabled.mockReturnValue(false); testServer.license.disable('feat:externalSecrets');
const resp = await authOwnerAgent.post('/external-secrets/providers/dummy/update'); const resp = await authOwnerAgent.post('/external-secrets/providers/dummy/update');
expect(resp.status).toBe(400); expect(resp.status).toBe(400);

View file

@ -1,6 +1,5 @@
import type { SuperAgentTest } from 'supertest'; import type { SuperAgentTest } from 'supertest';
import { Container } from 'typedi'; import { Container } from 'typedi';
import { License } from '@/License';
import validator from 'validator'; import validator from 'validator';
import config from '@/config'; import config from '@/config';
import { AUTH_COOKIE_NAME } from '@/constants'; import { AUTH_COOKIE_NAME } from '@/constants';
@ -21,6 +20,7 @@ let authOwnerAgent: SuperAgentTest;
const ownerPassword = randomValidPassword(); const ownerPassword = randomValidPassword();
const testServer = utils.setupTestServer({ endpointGroups: ['auth'] }); const testServer = utils.setupTestServer({ endpointGroups: ['auth'] });
const license = testServer.license;
beforeAll(async () => { beforeAll(async () => {
globalOwnerRole = await getGlobalOwnerRole(); globalOwnerRole = await getGlobalOwnerRole();
@ -79,7 +79,7 @@ describe('POST /login', () => {
}); });
test('should throw AuthError for non-owner if not within users limit quota', async () => { test('should throw AuthError for non-owner if not within users limit quota', async () => {
jest.spyOn(Container.get(License), 'isWithinUsersLimit').mockReturnValueOnce(false); license.setQuota('quota:users', 0);
const password = 'testpassword'; const password = 'testpassword';
const member = await createUser({ const member = await createUser({
password, password,
@ -93,7 +93,7 @@ describe('POST /login', () => {
}); });
test('should not throw AuthError for owner if not within users limit quota', async () => { test('should not throw AuthError for owner if not within users limit quota', async () => {
jest.spyOn(Container.get(License), 'isWithinUsersLimit').mockReturnValueOnce(false); license.setQuota('quota:users', 0);
const ownerUser = await createUser({ const ownerUser = await createUser({
password: randomValidPassword(), password: randomValidPassword(),
globalRole: globalOwnerRole, globalRole: globalOwnerRole,
@ -315,7 +315,7 @@ describe('GET /resolve-signup-token', () => {
}); });
test('should return 403 if user quota reached', async () => { test('should return 403 if user quota reached', async () => {
jest.spyOn(Container.get(License), 'isWithinUsersLimit').mockReturnValueOnce(false); license.setQuota('quota:users', 0);
const memberShell = await createUserShell(globalMemberRole); const memberShell = await createUserShell(globalMemberRole);
const response = await authOwnerAgent const response = await authOwnerAgent

View file

@ -5,7 +5,6 @@ import type { User } from '@db/entities/User';
import * as UserManagementHelpers from '@/UserManagement/UserManagementHelper'; import * as UserManagementHelpers from '@/UserManagement/UserManagementHelper';
import Container from 'typedi'; import Container from 'typedi';
import config from '@/config'; import config from '@/config';
import { License } from '@/License';
import { SourceControlPreferencesService } from '@/environments/sourceControl/sourceControlPreferences.service.ee'; import { SourceControlPreferencesService } from '@/environments/sourceControl/sourceControlPreferences.service.ee';
import { SourceControlService } from '@/environments/sourceControl/sourceControl.service.ee'; import { SourceControlService } from '@/environments/sourceControl/sourceControl.service.ee';
import type { SourceControlledFile } from '@/environments/sourceControl/types/sourceControlledFile'; import type { SourceControlledFile } from '@/environments/sourceControl/types/sourceControlledFile';
@ -32,7 +31,6 @@ beforeAll(async () => {
authOwnerAgent = testServer.authAgentFor(owner); authOwnerAgent = testServer.authAgentFor(owner);
authMemberAgent = testServer.authAgentFor(member); authMemberAgent = testServer.authAgentFor(member);
Container.get(License).isSourceControlLicensed = () => true;
Container.get(SourceControlPreferencesService).isSourceControlConnected = () => true; Container.get(SourceControlPreferencesService).isSourceControlConnected = () => true;
}); });

View file

@ -2,7 +2,6 @@ import type { SuperAgentTest } from 'supertest';
import Container from 'typedi'; import Container from 'typedi';
import type { INode } from 'n8n-workflow'; import type { INode } from 'n8n-workflow';
import { STARTING_NODES } from '@/constants'; import { STARTING_NODES } from '@/constants';
import { License } from '@/License';
import type { Role } from '@db/entities/Role'; import type { Role } from '@db/entities/Role';
import type { TagEntity } from '@db/entities/TagEntity'; import type { TagEntity } from '@db/entities/TagEntity';
import type { User } from '@db/entities/User'; import type { User } from '@db/entities/User';
@ -10,7 +9,6 @@ import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.reposi
import { WorkflowHistoryRepository } from '@db/repositories/workflowHistory.repository'; import { WorkflowHistoryRepository } from '@db/repositories/workflowHistory.repository';
import type { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner'; import type { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
import { mockInstance } from '../../shared/mocking';
import { randomApiKey } from '../shared/random'; import { randomApiKey } from '../shared/random';
import * as utils from '../shared/utils/'; import * as utils from '../shared/utils/';
import * as testDb from '../shared/testDb'; import * as testDb from '../shared/testDb';
@ -27,11 +25,7 @@ let authMemberAgent: SuperAgentTest;
let workflowRunner: ActiveWorkflowRunner; let workflowRunner: ActiveWorkflowRunner;
const testServer = utils.setupTestServer({ endpointGroups: ['publicApi'] }); const testServer = utils.setupTestServer({ endpointGroups: ['publicApi'] });
const license = testServer.license;
const licenseLike = mockInstance(License, {
isWorkflowHistoryLicensed: jest.fn().mockReturnValue(false),
isWithinUsersLimit: jest.fn().mockReturnValue(true),
});
beforeAll(async () => { beforeAll(async () => {
const [globalOwnerRole, globalMemberRole, fetchedWorkflowOwnerRole] = await getAllRoles(); const [globalOwnerRole, globalMemberRole, fetchedWorkflowOwnerRole] = await getAllRoles();
@ -64,7 +58,6 @@ beforeEach(async () => {
authOwnerAgent = testServer.publicApiAgentFor(owner); authOwnerAgent = testServer.publicApiAgentFor(owner);
authMemberAgent = testServer.publicApiAgentFor(member); authMemberAgent = testServer.publicApiAgentFor(member);
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
}); });
afterEach(async () => { afterEach(async () => {
@ -700,7 +693,7 @@ describe('POST /workflows', () => {
}); });
test('should create workflow history version when licensed', async () => { test('should create workflow history version when licensed', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(true); license.enable('feat:workflowHistory');
const payload = { const payload = {
name: 'testing', name: 'testing',
nodes: [ nodes: [
@ -746,7 +739,7 @@ describe('POST /workflows', () => {
}); });
test('should not create workflow history version when not licensed', async () => { test('should not create workflow history version when not licensed', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false); license.disable('feat:workflowHistory');
const payload = { const payload = {
name: 'testing', name: 'testing',
nodes: [ nodes: [
@ -940,7 +933,7 @@ describe('PUT /workflows/:id', () => {
}); });
test('should create workflow history version when licensed', async () => { test('should create workflow history version when licensed', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(true); license.enable('feat:workflowHistory');
const workflow = await createWorkflow({}, member); const workflow = await createWorkflow({}, member);
const payload = { const payload = {
name: 'name updated', name: 'name updated',
@ -995,7 +988,7 @@ describe('PUT /workflows/:id', () => {
}); });
test('should not create workflow history when not licensed', async () => { test('should not create workflow history when not licensed', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false); license.disable('feat:workflowHistory');
const workflow = await createWorkflow({}, member); const workflow = await createWorkflow({}, member);
const payload = { const payload = {
name: 'name updated', name: 'name updated',

View file

@ -1,20 +1,17 @@
import { License } from '@/License';
import * as utils from './shared/utils/'; import * as utils from './shared/utils/';
import * as testDb from './shared/testDb'; import * as testDb from './shared/testDb';
import { mockInstance } from '../shared/mocking';
import { createAdmin, createMember, createOwner } from './shared/db/users'; import { createAdmin, createMember, createOwner } from './shared/db/users';
import type { SuperAgentTest } from 'supertest'; import type { SuperAgentTest } from 'supertest';
import type { User } from '@db/entities/User'; import type { User } from '@db/entities/User';
const testServer = utils.setupTestServer({ endpointGroups: ['role'] }); const testServer = utils.setupTestServer({
endpointGroups: ['role'],
const license = mockInstance(License, { enabledFeatures: ['feat:advancedPermissions'],
isAdvancedPermissionsLicensed: jest.fn().mockReturnValue(true),
isWithinUsersLimit: jest.fn().mockReturnValue(true),
}); });
const license = testServer.license;
describe('GET /roles', () => { describe('GET /roles', () => {
let owner: User; let owner: User;
let admin: User; let admin: User;
@ -46,7 +43,7 @@ describe('GET /roles', () => {
describe('with advanced permissions licensed', () => { describe('with advanced permissions licensed', () => {
test.each(['owner', 'admin', 'member'])('should return all roles to %s', async (user) => { test.each(['owner', 'admin', 'member'])('should return all roles to %s', async (user) => {
license.isAdvancedPermissionsLicensed.mockReturnValue(true); license.enable('feat:advancedPermissions');
const response = await toAgent[user].get('/roles').expect(200); const response = await toAgent[user].get('/roles').expect(200);
@ -64,7 +61,7 @@ describe('GET /roles', () => {
describe('with advanced permissions not licensed', () => { describe('with advanced permissions not licensed', () => {
test.each(['owner', 'admin', 'member'])('should return all roles to %s', async (user) => { test.each(['owner', 'admin', 'member'])('should return all roles to %s', async (user) => {
license.isAdvancedPermissionsLicensed.mockReturnValue(false); license.disable('feat:advancedPermissions');
const response = await toAgent[user].get('/roles').expect(200); const response = await toAgent[user].get('/roles').expect(200);

View file

@ -0,0 +1,59 @@
import type { BooleanLicenseFeature, NumericLicenseFeature } from '@/Interfaces';
import type { License } from '@/License';
export interface LicenseMockDefaults {
features?: BooleanLicenseFeature[];
quota?: Partial<{ [K in NumericLicenseFeature]: number }>;
}
export class LicenseMocker {
private _enabledFeatures: Set<BooleanLicenseFeature> = new Set();
private _defaultFeatures: Set<BooleanLicenseFeature> = new Set();
private _featureQuotas: Map<NumericLicenseFeature, number> = new Map();
private _defaultQuotas: Map<NumericLicenseFeature, number> = new Map();
mock(license: License) {
license.isFeatureEnabled = this.isFeatureEnabled.bind(this);
license.getFeatureValue = this.getFeatureValue.bind(this);
}
reset() {
this._enabledFeatures = new Set(this._defaultFeatures);
this._featureQuotas = new Map(this._defaultQuotas);
}
setDefaults(defaults: LicenseMockDefaults) {
this._defaultFeatures = new Set(defaults.features ?? []);
this._defaultQuotas = new Map(
Object.entries(defaults.quota ?? {}) as Array<[NumericLicenseFeature, number]>,
);
}
isFeatureEnabled(feature: BooleanLicenseFeature): boolean {
return this._enabledFeatures.has(feature);
}
getFeatureValue(feature: string): boolean | number | undefined {
if (this._featureQuotas.has(feature as NumericLicenseFeature)) {
return this._featureQuotas.get(feature as NumericLicenseFeature);
} else if (this._enabledFeatures.has(feature as BooleanLicenseFeature)) {
return true;
}
return undefined;
}
enable(feature: BooleanLicenseFeature) {
this._enabledFeatures.add(feature);
}
disable(feature: BooleanLicenseFeature) {
this._enabledFeatures.delete(feature);
}
setQuota(feature: NumericLicenseFeature, quota: number) {
this._featureQuotas.set(feature, quota);
}
}

View file

@ -6,6 +6,7 @@ import type { Server } from 'http';
import type { CredentialsEntity } from '@db/entities/CredentialsEntity'; import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
import type { User } from '@db/entities/User'; import type { User } from '@db/entities/User';
import type { BooleanLicenseFeature, ICredentialsDb } from '@/Interfaces'; import type { BooleanLicenseFeature, ICredentialsDb } from '@/Interfaces';
import type { LicenseMocker } from './license';
type EndpointGroup = type EndpointGroup =
| 'me' | 'me'
@ -45,6 +46,7 @@ export interface TestServer {
authAgentFor: (user: User) => SuperAgentTest; authAgentFor: (user: User) => SuperAgentTest;
publicApiAgentFor: (user: User) => SuperAgentTest; publicApiAgentFor: (user: User) => SuperAgentTest;
authlessAgent: SuperAgentTest; authlessAgent: SuperAgentTest;
license: LicenseMocker;
} }
export type CredentialPayload = { export type CredentialPayload = {

View file

@ -20,6 +20,7 @@ import * as testDb from '../../shared/testDb';
import { AUTHLESS_ENDPOINTS, PUBLIC_API_REST_PATH_SEGMENT, REST_PATH_SEGMENT } from '../constants'; import { AUTHLESS_ENDPOINTS, PUBLIC_API_REST_PATH_SEGMENT, REST_PATH_SEGMENT } from '../constants';
import type { SetupProps, TestServer } from '../types'; import type { SetupProps, TestServer } from '../types';
import { InternalHooks } from '@/InternalHooks'; import { InternalHooks } from '@/InternalHooks';
import { LicenseMocker } from '../license';
/** /**
* Plugin to prefix a path segment into a request URL pathname. * Plugin to prefix a path segment into a request URL pathname.
@ -83,6 +84,7 @@ export const setupTestServer = ({
authAgentFor: (user: User) => createAgent(app, { auth: true, user }), authAgentFor: (user: User) => createAgent(app, { auth: true, user }),
authlessAgent: createAgent(app), authlessAgent: createAgent(app),
publicApiAgentFor: (user) => publicApiAgent(app, { user }), publicApiAgentFor: (user) => publicApiAgent(app, { user }),
license: new LicenseMocker(),
}; };
beforeAll(async () => { beforeAll(async () => {
@ -91,8 +93,11 @@ export const setupTestServer = ({
config.set('userManagement.jwtSecret', 'My JWT secret'); config.set('userManagement.jwtSecret', 'My JWT secret');
config.set('userManagement.isInstanceOwnerSetUp', true); config.set('userManagement.isInstanceOwnerSetUp', true);
testServer.license.mock(Container.get(License));
if (enabledFeatures) { if (enabledFeatures) {
Container.get(License).isFeatureEnabled = (feature) => enabledFeatures.includes(feature); testServer.license.setDefaults({
features: enabledFeatures,
});
} }
const enablePublicAPI = endpointGroups?.includes('publicApi'); const enablePublicAPI = endpointGroups?.includes('publicApi');
@ -166,7 +171,7 @@ export const setupTestServer = ({
const { LdapManager } = await import('@/Ldap/LdapManager.ee'); const { LdapManager } = await import('@/Ldap/LdapManager.ee');
const { handleLdapInit } = await import('@/Ldap/helpers'); const { handleLdapInit } = await import('@/Ldap/helpers');
const { LdapController } = await import('@/controllers/ldap.controller'); const { LdapController } = await import('@/controllers/ldap.controller');
Container.get(License).isLdapEnabled = () => true; testServer.license.enable('feat:ldap');
await handleLdapInit(); await handleLdapInit();
const { service, sync } = LdapManager.getInstance(); const { service, sync } = LdapManager.getInstance();
registerController( registerController(
@ -312,5 +317,9 @@ export const setupTestServer = ({
testServer.httpServer.close(); testServer.httpServer.close();
}); });
beforeEach(() => {
testServer.license.reset();
});
return testServer; return testServer;
}; };

View file

@ -3,10 +3,8 @@ import type { SuperAgentTest } from 'supertest';
import type { Variables } from '@db/entities/Variables'; import type { Variables } from '@db/entities/Variables';
import { VariablesRepository } from '@db/repositories/variables.repository'; import { VariablesRepository } from '@db/repositories/variables.repository';
import { generateNanoId } from '@db/utils/generators'; import { generateNanoId } from '@db/utils/generators';
import { License } from '@/License';
import { VariablesService } from '@/environments/variables/variables.service.ee'; import { VariablesService } from '@/environments/variables/variables.service.ee';
import { mockInstance } from '../shared/mocking';
import * as testDb from './shared/testDb'; import * as testDb from './shared/testDb';
import * as utils from './shared/utils/'; import * as utils from './shared/utils/';
import { createOwner, createUser } from './shared/db/users'; import { createOwner, createUser } from './shared/db/users';
@ -14,14 +12,8 @@ import { createOwner, createUser } from './shared/db/users';
let authOwnerAgent: SuperAgentTest; let authOwnerAgent: SuperAgentTest;
let authMemberAgent: SuperAgentTest; let authMemberAgent: SuperAgentTest;
const licenseLike = {
isFeatureEnabled: jest.fn().mockReturnValue(true),
isVariablesEnabled: () => licenseLike.isFeatureEnabled(),
getVariablesLimit: jest.fn().mockReturnValue(-1),
isWithinUsersLimit: jest.fn().mockReturnValue(true),
};
const testServer = utils.setupTestServer({ endpointGroups: ['variables'] }); const testServer = utils.setupTestServer({ endpointGroups: ['variables'] });
const license = testServer.license;
async function createVariable(key: string, value: string) { async function createVariable(key: string, value: string) {
const result = await Container.get(VariablesRepository).save({ const result = await Container.get(VariablesRepository).save({
@ -50,18 +42,21 @@ async function getVariableById(id: string) {
} }
beforeAll(async () => { beforeAll(async () => {
mockInstance(License, licenseLike);
const owner = await createOwner(); const owner = await createOwner();
authOwnerAgent = testServer.authAgentFor(owner); authOwnerAgent = testServer.authAgentFor(owner);
const member = await createUser(); const member = await createUser();
authMemberAgent = testServer.authAgentFor(member); authMemberAgent = testServer.authAgentFor(member);
license.setDefaults({
features: ['feat:variables'],
// quota: {
// 'quota:maxVariables': -1,
// },
});
}); });
beforeEach(async () => { beforeEach(async () => {
await testDb.truncate(['Variables']); await testDb.truncate(['Variables']);
licenseLike.isFeatureEnabled.mockReturnValue(true);
licenseLike.getVariablesLimit.mockReturnValue(-1);
}); });
// ---------------------------------------- // ----------------------------------------
@ -159,7 +154,7 @@ describe('POST /variables', () => {
}); });
test("POST /variables should not create a new variable and return it if the instance doesn't have a license", async () => { test("POST /variables should not create a new variable and return it if the instance doesn't have a license", async () => {
licenseLike.isFeatureEnabled.mockReturnValue(false); license.disable('feat:variables');
const response = await authOwnerAgent.post('/variables').send(toCreate); const response = await authOwnerAgent.post('/variables').send(toCreate);
expect(response.statusCode).toBe(403); expect(response.statusCode).toBe(403);
expect(response.body.data?.key).not.toBe(toCreate.key); expect(response.body.data?.key).not.toBe(toCreate.key);
@ -178,7 +173,7 @@ describe('POST /variables', () => {
}); });
test('should not fail if variable limit not reached', async () => { test('should not fail if variable limit not reached', async () => {
licenseLike.getVariablesLimit.mockReturnValue(5); license.setQuota('quota:maxVariables', 5);
let i = 1; let i = 1;
let toCreate = generatePayload(i); let toCreate = generatePayload(i);
while (i < 3) { while (i < 3) {
@ -193,7 +188,7 @@ describe('POST /variables', () => {
}); });
test('should fail if variable limit reached', async () => { test('should fail if variable limit reached', async () => {
licenseLike.getVariablesLimit.mockReturnValue(5); license.setQuota('quota:maxVariables', 5);
let i = 1; let i = 1;
let toCreate = generatePayload(i); let toCreate = generatePayload(i);
while (i < 6) { while (i < 6) {

View file

@ -1,8 +1,6 @@
import type { SuperAgentTest } from 'supertest'; import type { SuperAgentTest } from 'supertest';
import { License } from '@/License';
import type { User } from '@db/entities/User'; import type { User } from '@db/entities/User';
import { mockInstance } from '../shared/mocking';
import * as testDb from './shared/testDb'; import * as testDb from './shared/testDb';
import * as utils from './shared/utils/'; import * as utils from './shared/utils/';
import { createOwner, createUser } from './shared/db/users'; import { createOwner, createUser } from './shared/db/users';
@ -14,13 +12,11 @@ let authOwnerAgent: SuperAgentTest;
let member: User; let member: User;
let authMemberAgent: SuperAgentTest; let authMemberAgent: SuperAgentTest;
const licenseLike = mockInstance(License, { const testServer = utils.setupTestServer({
isWorkflowHistoryLicensed: jest.fn().mockReturnValue(true), endpointGroups: ['workflowHistory'],
isWithinUsersLimit: jest.fn().mockReturnValue(true), enabledFeatures: ['feat:workflowHistory'],
}); });
const testServer = utils.setupTestServer({ endpointGroups: ['workflowHistory'] });
beforeAll(async () => { beforeAll(async () => {
owner = await createOwner(); owner = await createOwner();
authOwnerAgent = testServer.authAgentFor(owner); authOwnerAgent = testServer.authAgentFor(owner);
@ -28,17 +24,13 @@ beforeAll(async () => {
authMemberAgent = testServer.authAgentFor(member); authMemberAgent = testServer.authAgentFor(member);
}); });
beforeEach(() => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(true);
});
afterEach(async () => { afterEach(async () => {
await testDb.truncate(['Workflow', 'SharedWorkflow', 'WorkflowHistory']); await testDb.truncate(['Workflow', 'SharedWorkflow', 'WorkflowHistory']);
}); });
describe('GET /workflow-history/:workflowId', () => { describe('GET /workflow-history/:workflowId', () => {
test('should not work when license is not available', async () => { test('should not work when license is not available', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false); testServer.license.disable('feat:workflowHistory');
const resp = await authOwnerAgent.get('/workflow-history/workflow/badid'); const resp = await authOwnerAgent.get('/workflow-history/workflow/badid');
expect(resp.status).toBe(403); expect(resp.status).toBe(403);
expect(resp.text).toBe('Workflow History license data not found'); expect(resp.text).toBe('Workflow History license data not found');
@ -165,7 +157,7 @@ describe('GET /workflow-history/:workflowId', () => {
describe('GET /workflow-history/workflow/:workflowId/version/:versionId', () => { describe('GET /workflow-history/workflow/:workflowId/version/:versionId', () => {
test('should not work when license is not available', async () => { test('should not work when license is not available', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false); testServer.license.disable('feat:workflowHistory');
const resp = await authOwnerAgent.get('/workflow-history/workflow/badid/version/badid'); const resp = await authOwnerAgent.get('/workflow-history/workflow/badid/version/badid');
expect(resp.status).toBe(403); expect(resp.status).toBe(403);
expect(resp.text).toBe('Workflow History license data not found'); expect(resp.text).toBe('Workflow History license data not found');

View file

@ -6,7 +6,6 @@ import type { INode } from 'n8n-workflow';
import * as UserManagementHelpers from '@/UserManagement/UserManagementHelper'; import * as UserManagementHelpers from '@/UserManagement/UserManagementHelper';
import type { User } from '@db/entities/User'; import type { User } from '@db/entities/User';
import { getSharedWorkflowIds } from '@/WorkflowHelpers'; import { getSharedWorkflowIds } from '@/WorkflowHelpers';
import { License } from '@/License';
import { WorkflowHistoryRepository } from '@db/repositories/workflowHistory.repository'; import { WorkflowHistoryRepository } from '@db/repositories/workflowHistory.repository';
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner'; import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
@ -31,10 +30,6 @@ let authMemberAgent: SuperAgentTest;
let authAnotherMemberAgent: SuperAgentTest; let authAnotherMemberAgent: SuperAgentTest;
let saveCredential: SaveCredentialFunction; let saveCredential: SaveCredentialFunction;
const licenseLike = mockInstance(License, {
isWorkflowHistoryLicensed: jest.fn().mockReturnValue(false),
isWithinUsersLimit: jest.fn().mockReturnValue(true),
});
const activeWorkflowRunnerLike = mockInstance(ActiveWorkflowRunner); const activeWorkflowRunnerLike = mockInstance(ActiveWorkflowRunner);
const sharingSpy = jest.spyOn(UserManagementHelpers, 'isSharingEnabled').mockReturnValue(true); const sharingSpy = jest.spyOn(UserManagementHelpers, 'isSharingEnabled').mockReturnValue(true);
@ -42,6 +37,7 @@ const testServer = utils.setupTestServer({
endpointGroups: ['workflows'], endpointGroups: ['workflows'],
enabledFeatures: ['feat:sharing'], enabledFeatures: ['feat:sharing'],
}); });
const license = testServer.license;
beforeAll(async () => { beforeAll(async () => {
const globalOwnerRole = await getGlobalOwnerRole(); const globalOwnerRole = await getGlobalOwnerRole();
@ -66,7 +62,6 @@ beforeEach(async () => {
activeWorkflowRunnerLike.remove.mockReset(); activeWorkflowRunnerLike.remove.mockReset();
await testDb.truncate(['Workflow', 'SharedWorkflow', 'WorkflowHistory']); await testDb.truncate(['Workflow', 'SharedWorkflow', 'WorkflowHistory']);
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
}); });
describe('router should switch based on flag', () => { describe('router should switch based on flag', () => {
@ -490,7 +485,7 @@ describe('POST /workflows', () => {
}); });
test('Should create workflow history version when licensed', async () => { test('Should create workflow history version when licensed', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(true); license.enable('feat:workflowHistory');
const payload = { const payload = {
name: 'testing', name: 'testing',
nodes: [ nodes: [
@ -539,7 +534,7 @@ describe('POST /workflows', () => {
}); });
test('Should not create workflow history version when not licensed', async () => { test('Should not create workflow history version when not licensed', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false); license.disable('feat:workflowHistory');
const payload = { const payload = {
name: 'testing', name: 'testing',
nodes: [ nodes: [
@ -1013,7 +1008,7 @@ describe('getSharedWorkflowIds', () => {
describe('PATCH /workflows/:id - workflow history', () => { describe('PATCH /workflows/:id - workflow history', () => {
test('Should create workflow history version when licensed', async () => { test('Should create workflow history version when licensed', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(true); license.enable('feat:workflowHistory');
const workflow = await createWorkflow({}, owner); const workflow = await createWorkflow({}, owner);
const payload = { const payload = {
name: 'name updated', name: 'name updated',
@ -1071,7 +1066,7 @@ describe('PATCH /workflows/:id - workflow history', () => {
}); });
test('Should not create workflow history version when not licensed', async () => { test('Should not create workflow history version when not licensed', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false); license.disable('feat:workflowHistory');
const workflow = await createWorkflow({}, owner); const workflow = await createWorkflow({}, owner);
const payload = { const payload = {
name: 'name updated', name: 'name updated',
@ -1123,7 +1118,7 @@ describe('PATCH /workflows/:id - workflow history', () => {
describe('PATCH /workflows/:id - activate workflow', () => { describe('PATCH /workflows/:id - activate workflow', () => {
test('should activate workflow without changing version ID', async () => { test('should activate workflow without changing version ID', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false); license.disable('feat:workflowHistory');
const workflow = await createWorkflow({}, owner); const workflow = await createWorkflow({}, owner);
const payload = { const payload = {
versionId: workflow.versionId, versionId: workflow.versionId,
@ -1145,7 +1140,7 @@ describe('PATCH /workflows/:id - activate workflow', () => {
}); });
test('should deactivate workflow without changing version ID', async () => { test('should deactivate workflow without changing version ID', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false); license.disable('feat:workflowHistory');
const workflow = await createWorkflow({ active: true }, owner); const workflow = await createWorkflow({ active: true }, owner);
const payload = { const payload = {
versionId: workflow.versionId, versionId: workflow.versionId,

View file

@ -6,7 +6,6 @@ import { v4 as uuid } from 'uuid';
import { RoleService } from '@/services/role.service'; import { RoleService } from '@/services/role.service';
import Container from 'typedi'; import Container from 'typedi';
import type { ListQuery } from '@/requests'; import type { ListQuery } from '@/requests';
import { License } from '@/License';
import { WorkflowHistoryRepository } from '@db/repositories/workflowHistory.repository'; import { WorkflowHistoryRepository } from '@db/repositories/workflowHistory.repository';
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner'; import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
@ -25,14 +24,10 @@ let authOwnerAgent: SuperAgentTest;
jest.spyOn(UserManagementHelpers, 'isSharingEnabled').mockReturnValue(false); jest.spyOn(UserManagementHelpers, 'isSharingEnabled').mockReturnValue(false);
const testServer = utils.setupTestServer({ endpointGroups: ['workflows'] }); const testServer = utils.setupTestServer({ endpointGroups: ['workflows'] });
const license = testServer.license;
const { objectContaining, arrayContaining, any } = expect; const { objectContaining, arrayContaining, any } = expect;
const licenseLike = mockInstance(License, {
isWorkflowHistoryLicensed: jest.fn().mockReturnValue(false),
isWithinUsersLimit: jest.fn().mockReturnValue(true),
});
const activeWorkflowRunnerLike = mockInstance(ActiveWorkflowRunner); const activeWorkflowRunnerLike = mockInstance(ActiveWorkflowRunner);
beforeAll(async () => { beforeAll(async () => {
@ -43,7 +38,6 @@ beforeAll(async () => {
beforeEach(async () => { beforeEach(async () => {
jest.resetAllMocks(); jest.resetAllMocks();
await testDb.truncate(['Workflow', 'SharedWorkflow', 'Tag', 'WorkflowHistory']); await testDb.truncate(['Workflow', 'SharedWorkflow', 'Tag', 'WorkflowHistory']);
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
}); });
describe('POST /workflows', () => { describe('POST /workflows', () => {
@ -65,7 +59,7 @@ describe('POST /workflows', () => {
}); });
test('should create workflow history version when licensed', async () => { test('should create workflow history version when licensed', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(true); license.enable('feat:workflowHistory');
const payload = { const payload = {
name: 'testing', name: 'testing',
nodes: [ nodes: [
@ -114,7 +108,7 @@ describe('POST /workflows', () => {
}); });
test('should not create workflow history version when not licensed', async () => { test('should not create workflow history version when not licensed', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false); license.disable('feat:workflowHistory');
const payload = { const payload = {
name: 'testing', name: 'testing',
nodes: [ nodes: [
@ -428,7 +422,7 @@ describe('GET /workflows', () => {
describe('PATCH /workflows/:id', () => { describe('PATCH /workflows/:id', () => {
test('should create workflow history version when licensed', async () => { test('should create workflow history version when licensed', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(true); license.enable('feat:workflowHistory');
const workflow = await createWorkflow({}, owner); const workflow = await createWorkflow({}, owner);
const payload = { const payload = {
name: 'name updated', name: 'name updated',
@ -486,7 +480,7 @@ describe('PATCH /workflows/:id', () => {
}); });
test('should not create workflow history version when not licensed', async () => { test('should not create workflow history version when not licensed', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false); license.disable('feat:workflowHistory');
const workflow = await createWorkflow({}, owner); const workflow = await createWorkflow({}, owner);
const payload = { const payload = {
name: 'name updated', name: 'name updated',
@ -536,7 +530,7 @@ describe('PATCH /workflows/:id', () => {
}); });
test('should activate workflow without changing version ID', async () => { test('should activate workflow without changing version ID', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false); license.disable('feat:workflowHistory');
const workflow = await createWorkflow({}, owner); const workflow = await createWorkflow({}, owner);
const payload = { const payload = {
versionId: workflow.versionId, versionId: workflow.versionId,
@ -558,7 +552,7 @@ describe('PATCH /workflows/:id', () => {
}); });
test('should deactivate workflow without changing version ID', async () => { test('should deactivate workflow without changing version ID', async () => {
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false); license.disable('feat:workflowHistory');
const workflow = await createWorkflow({ active: true }, owner); const workflow = await createWorkflow({ active: true }, owner);
const payload = { const payload = {
versionId: workflow.versionId, versionId: workflow.versionId,