2024-07-05 02:43:27 -07:00
|
|
|
import fs from 'fs';
|
|
|
|
import { mock } from 'jest-mock-extended';
|
2024-09-18 00:19:33 -07:00
|
|
|
import { Container } from 'typedi';
|
|
|
|
|
2024-07-05 02:43:27 -07:00
|
|
|
import { GlobalConfig } from '../src/index';
|
|
|
|
|
|
|
|
jest.mock('fs');
|
|
|
|
const mockFs = mock<typeof fs>();
|
|
|
|
fs.readFileSync = mockFs.readFileSync;
|
|
|
|
|
|
|
|
describe('GlobalConfig', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
Container.reset();
|
|
|
|
});
|
|
|
|
|
|
|
|
const originalEnv = process.env;
|
|
|
|
afterEach(() => {
|
|
|
|
process.env = originalEnv;
|
|
|
|
});
|
|
|
|
|
2024-08-27 04:51:26 -07:00
|
|
|
// deepCopy for diff to show plain objects
|
|
|
|
// eslint-disable-next-line n8n-local-rules/no-json-parse-json-stringify
|
|
|
|
const deepCopy = <T>(obj: T): T => JSON.parse(JSON.stringify(obj));
|
|
|
|
|
2024-07-23 04:32:50 -07:00
|
|
|
const defaultConfig: GlobalConfig = {
|
2024-07-29 05:32:20 -07:00
|
|
|
path: '/',
|
|
|
|
host: 'localhost',
|
|
|
|
port: 5678,
|
|
|
|
listen_address: '0.0.0.0',
|
|
|
|
protocol: 'http',
|
2024-07-05 02:43:27 -07:00
|
|
|
database: {
|
|
|
|
logging: {
|
|
|
|
enabled: false,
|
|
|
|
maxQueryExecutionTime: 0,
|
|
|
|
options: 'error',
|
|
|
|
},
|
|
|
|
mysqldb: {
|
|
|
|
database: 'n8n',
|
|
|
|
host: 'localhost',
|
|
|
|
password: '',
|
|
|
|
port: 3306,
|
|
|
|
user: 'root',
|
|
|
|
},
|
|
|
|
postgresdb: {
|
|
|
|
database: 'n8n',
|
|
|
|
host: 'localhost',
|
|
|
|
password: '',
|
|
|
|
poolSize: 2,
|
|
|
|
port: 5432,
|
|
|
|
schema: 'public',
|
2024-09-06 02:07:03 -07:00
|
|
|
connectionTimeoutMs: 20_000,
|
2024-07-05 02:43:27 -07:00
|
|
|
ssl: {
|
|
|
|
ca: '',
|
|
|
|
cert: '',
|
|
|
|
enabled: false,
|
|
|
|
key: '',
|
|
|
|
rejectUnauthorized: true,
|
|
|
|
},
|
|
|
|
user: 'postgres',
|
|
|
|
},
|
|
|
|
sqlite: {
|
|
|
|
database: 'database.sqlite',
|
|
|
|
enableWAL: false,
|
|
|
|
executeVacuumOnStartup: false,
|
|
|
|
poolSize: 0,
|
|
|
|
},
|
|
|
|
tablePrefix: '',
|
|
|
|
type: 'sqlite',
|
|
|
|
},
|
|
|
|
credentials: {
|
|
|
|
defaultName: 'My credentials',
|
|
|
|
overwrite: {
|
|
|
|
data: '{}',
|
|
|
|
endpoint: '',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
userManagement: {
|
|
|
|
emails: {
|
|
|
|
mode: 'smtp',
|
|
|
|
smtp: {
|
|
|
|
host: '',
|
|
|
|
port: 465,
|
|
|
|
secure: true,
|
|
|
|
sender: '',
|
|
|
|
startTLS: true,
|
|
|
|
auth: {
|
|
|
|
pass: '',
|
|
|
|
user: '',
|
|
|
|
privateKey: '',
|
|
|
|
serviceClient: '',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
template: {
|
2024-08-28 08:15:18 -07:00
|
|
|
'credentials-shared': '',
|
|
|
|
'user-invited': '',
|
|
|
|
'password-reset-requested': '',
|
|
|
|
'workflow-shared': '',
|
2024-07-05 02:43:27 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2024-07-23 03:17:29 -07:00
|
|
|
eventBus: {
|
|
|
|
checkUnsentInterval: 0,
|
|
|
|
crashRecoveryMode: 'extensive',
|
|
|
|
logWriter: {
|
|
|
|
keepLogCount: 3,
|
|
|
|
logBaseName: 'n8nEventLog',
|
|
|
|
maxFileSizeInKB: 10240,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
externalSecrets: {
|
|
|
|
preferGet: false,
|
|
|
|
updateInterval: 300,
|
|
|
|
},
|
2024-07-23 04:32:50 -07:00
|
|
|
nodes: {
|
|
|
|
communityPackages: {
|
|
|
|
enabled: true,
|
2024-08-14 00:44:19 -07:00
|
|
|
registry: 'https://registry.npmjs.org',
|
2024-08-05 02:52:06 -07:00
|
|
|
reinstallMissing: false,
|
2024-07-23 04:32:50 -07:00
|
|
|
},
|
|
|
|
errorTriggerType: 'n8n-nodes-base.errorTrigger',
|
|
|
|
include: [],
|
|
|
|
exclude: [],
|
|
|
|
},
|
2024-07-23 03:17:29 -07:00
|
|
|
publicApi: {
|
|
|
|
disabled: false,
|
|
|
|
path: 'api',
|
|
|
|
swaggerUiDisabled: false,
|
|
|
|
},
|
|
|
|
templates: {
|
|
|
|
enabled: true,
|
|
|
|
host: 'https://api.n8n.io/api/',
|
|
|
|
},
|
|
|
|
versionNotifications: {
|
|
|
|
enabled: true,
|
|
|
|
endpoint: 'https://api.n8n.io/api/versions/',
|
|
|
|
infoUrl: 'https://docs.n8n.io/hosting/installation/updating/',
|
|
|
|
},
|
2024-07-24 04:08:20 -07:00
|
|
|
externalStorage: {
|
|
|
|
s3: {
|
|
|
|
host: '',
|
|
|
|
bucket: {
|
|
|
|
name: '',
|
|
|
|
region: '',
|
|
|
|
},
|
|
|
|
credentials: {
|
|
|
|
accessKey: '',
|
|
|
|
accessSecret: '',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2024-07-24 05:38:29 -07:00
|
|
|
workflows: {
|
|
|
|
defaultName: 'My workflow',
|
|
|
|
onboardingFlowDisabled: false,
|
|
|
|
callerPolicyDefaultOption: 'workflowsFromSameOwner',
|
|
|
|
},
|
2024-07-31 08:45:11 -07:00
|
|
|
endpoints: {
|
|
|
|
metrics: {
|
|
|
|
enable: false,
|
|
|
|
prefix: 'n8n_',
|
|
|
|
includeWorkflowIdLabel: false,
|
|
|
|
includeDefaultMetrics: true,
|
|
|
|
includeMessageEventBusMetrics: false,
|
|
|
|
includeNodeTypeLabel: false,
|
|
|
|
includeCacheMetrics: false,
|
|
|
|
includeApiEndpoints: false,
|
|
|
|
includeApiPathLabel: false,
|
|
|
|
includeApiMethodLabel: false,
|
|
|
|
includeCredentialTypeLabel: false,
|
|
|
|
includeApiStatusCodeLabel: false,
|
2024-08-28 02:36:00 -07:00
|
|
|
includeQueueMetrics: false,
|
|
|
|
queueMetricsInterval: 20,
|
2024-07-31 08:45:11 -07:00
|
|
|
},
|
|
|
|
additionalNonUIRoutes: '',
|
|
|
|
disableProductionWebhooksOnMainProcess: false,
|
|
|
|
disableUi: false,
|
|
|
|
form: 'form',
|
|
|
|
formTest: 'form-test',
|
|
|
|
formWaiting: 'form-waiting',
|
|
|
|
payloadSizeMax: 16,
|
2024-09-17 06:55:51 -07:00
|
|
|
formDataFileSizeMax: 200,
|
2024-07-31 08:45:11 -07:00
|
|
|
rest: 'rest',
|
|
|
|
webhook: 'webhook',
|
|
|
|
webhookTest: 'webhook-test',
|
|
|
|
webhookWaiting: 'webhook-waiting',
|
|
|
|
},
|
2024-08-02 08:10:03 -07:00
|
|
|
cache: {
|
|
|
|
backend: 'auto',
|
|
|
|
memory: {
|
|
|
|
maxSize: 3145728,
|
|
|
|
ttl: 3600000,
|
|
|
|
},
|
|
|
|
redis: {
|
2024-08-22 23:19:59 -07:00
|
|
|
prefix: 'cache',
|
2024-08-02 08:10:03 -07:00
|
|
|
ttl: 3600000,
|
|
|
|
},
|
|
|
|
},
|
2024-08-12 02:03:37 -07:00
|
|
|
queue: {
|
|
|
|
health: {
|
|
|
|
active: false,
|
|
|
|
port: 5678,
|
2024-10-04 03:18:26 -07:00
|
|
|
address: '0.0.0.0',
|
2024-08-12 02:03:37 -07:00
|
|
|
},
|
|
|
|
bull: {
|
|
|
|
redis: {
|
|
|
|
db: 0,
|
|
|
|
host: 'localhost',
|
|
|
|
password: '',
|
|
|
|
port: 6379,
|
|
|
|
timeoutThreshold: 10_000,
|
|
|
|
username: '',
|
|
|
|
clusterNodes: '',
|
|
|
|
tls: false,
|
|
|
|
},
|
|
|
|
queueRecoveryInterval: 60,
|
|
|
|
gracefulShutdownTimeout: 30,
|
|
|
|
prefix: 'bull',
|
|
|
|
settings: {
|
|
|
|
lockDuration: 30_000,
|
|
|
|
lockRenewTime: 15_000,
|
|
|
|
stalledInterval: 30_000,
|
|
|
|
maxStalledCount: 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2024-10-02 01:31:56 -07:00
|
|
|
taskRunners: {
|
|
|
|
disabled: true,
|
|
|
|
path: '/runners',
|
|
|
|
authToken: '',
|
2024-10-02 06:38:42 -07:00
|
|
|
listen_address: '127.0.0.1',
|
|
|
|
port: 5679,
|
2024-10-14 06:19:17 -07:00
|
|
|
useLauncher: false,
|
|
|
|
launcherPath: '',
|
|
|
|
launcherRunner: 'javascript',
|
2024-10-02 01:31:56 -07:00
|
|
|
},
|
2024-09-24 08:49:22 -07:00
|
|
|
sentry: {
|
|
|
|
backendDsn: '',
|
|
|
|
frontendDsn: '',
|
|
|
|
},
|
2024-10-01 03:16:09 -07:00
|
|
|
logging: {
|
|
|
|
level: 'info',
|
|
|
|
outputs: ['console'],
|
|
|
|
file: {
|
|
|
|
fileCountMax: 100,
|
|
|
|
fileSizeMax: 16,
|
|
|
|
location: 'logs/n8n.log',
|
|
|
|
},
|
2024-10-09 03:56:31 -07:00
|
|
|
scopes: [],
|
2024-10-01 03:16:09 -07:00
|
|
|
},
|
2024-07-05 02:43:27 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
it('should use all default values when no env variables are defined', () => {
|
|
|
|
process.env = {};
|
|
|
|
const config = Container.get(GlobalConfig);
|
2024-07-31 08:45:11 -07:00
|
|
|
expect(deepCopy(config)).toEqual(defaultConfig);
|
2024-07-05 02:43:27 -07:00
|
|
|
expect(mockFs.readFileSync).not.toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should use values from env variables when defined', () => {
|
|
|
|
process.env = {
|
|
|
|
DB_POSTGRESDB_HOST: 'some-host',
|
|
|
|
DB_POSTGRESDB_USER: 'n8n',
|
|
|
|
DB_TABLE_PREFIX: 'test_',
|
2024-07-23 04:32:50 -07:00
|
|
|
NODES_INCLUDE: '["n8n-nodes-base.hackerNews"]',
|
2024-08-15 04:58:20 -07:00
|
|
|
DB_LOGGING_MAX_EXECUTION_TIME: '0',
|
2024-08-27 04:51:26 -07:00
|
|
|
N8N_METRICS: 'TRUE',
|
|
|
|
N8N_TEMPLATES_ENABLED: '0',
|
2024-07-05 02:43:27 -07:00
|
|
|
};
|
|
|
|
const config = Container.get(GlobalConfig);
|
2024-08-27 04:51:26 -07:00
|
|
|
expect(deepCopy(config)).toEqual({
|
2024-07-05 02:43:27 -07:00
|
|
|
...defaultConfig,
|
|
|
|
database: {
|
|
|
|
logging: defaultConfig.database.logging,
|
|
|
|
mysqldb: defaultConfig.database.mysqldb,
|
|
|
|
postgresdb: {
|
|
|
|
...defaultConfig.database.postgresdb,
|
|
|
|
host: 'some-host',
|
|
|
|
user: 'n8n',
|
|
|
|
},
|
|
|
|
sqlite: defaultConfig.database.sqlite,
|
|
|
|
tablePrefix: 'test_',
|
|
|
|
type: 'sqlite',
|
|
|
|
},
|
2024-08-27 04:51:26 -07:00
|
|
|
endpoints: {
|
|
|
|
...defaultConfig.endpoints,
|
|
|
|
metrics: {
|
|
|
|
...defaultConfig.endpoints.metrics,
|
|
|
|
enable: true,
|
|
|
|
},
|
|
|
|
},
|
2024-07-23 04:32:50 -07:00
|
|
|
nodes: {
|
|
|
|
...defaultConfig.nodes,
|
|
|
|
include: ['n8n-nodes-base.hackerNews'],
|
|
|
|
},
|
2024-08-27 04:51:26 -07:00
|
|
|
templates: {
|
|
|
|
...defaultConfig.templates,
|
|
|
|
enabled: false,
|
|
|
|
},
|
2024-07-05 02:43:27 -07:00
|
|
|
});
|
|
|
|
expect(mockFs.readFileSync).not.toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
2024-07-23 04:32:50 -07:00
|
|
|
it('should read values from files using _FILE env variables', () => {
|
2024-07-05 02:43:27 -07:00
|
|
|
const passwordFile = '/path/to/postgres/password';
|
|
|
|
process.env = {
|
|
|
|
DB_POSTGRESDB_PASSWORD_FILE: passwordFile,
|
|
|
|
};
|
|
|
|
mockFs.readFileSync.calledWith(passwordFile, 'utf8').mockReturnValueOnce('password-from-file');
|
|
|
|
|
|
|
|
const config = Container.get(GlobalConfig);
|
2024-08-27 04:51:26 -07:00
|
|
|
expect(deepCopy(config)).toEqual({
|
2024-07-05 02:43:27 -07:00
|
|
|
...defaultConfig,
|
|
|
|
database: {
|
|
|
|
...defaultConfig.database,
|
|
|
|
postgresdb: {
|
|
|
|
...defaultConfig.database.postgresdb,
|
|
|
|
password: 'password-from-file',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
expect(mockFs.readFileSync).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
});
|