Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
128 lines
3.3 KiB
TypeScript
128 lines
3.3 KiB
TypeScript
import { describe, test, expect, beforeAll, afterAll } from 'vitest';
|
|
import { createServiceStack, type N8NStack } from 'n8n-containers';
|
|
import { constructExecutionMetaData } from 'n8n-core';
|
|
import type { IDataObject, IExecuteFunctions, INode } from 'n8n-workflow';
|
|
|
|
import { router } from '../../v2/actions/router';
|
|
import type { MysqlNodeCredentials } from '../../v2/helpers/interfaces';
|
|
|
|
let stack: N8NStack;
|
|
let credentials: MysqlNodeCredentials;
|
|
|
|
beforeAll(async () => {
|
|
stack = await createServiceStack({ services: ['mysql'] });
|
|
const meta = stack.serviceResults.mysql!.meta as {
|
|
externalHost: string;
|
|
externalPort: number;
|
|
database: string;
|
|
username: string;
|
|
password: string;
|
|
};
|
|
credentials = {
|
|
host: meta.externalHost,
|
|
port: meta.externalPort,
|
|
database: meta.database,
|
|
user: meta.username,
|
|
password: meta.password,
|
|
connectTimeout: 10000,
|
|
ssl: false,
|
|
sshTunnel: false,
|
|
};
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await stack?.stop();
|
|
});
|
|
|
|
const node: INode = {
|
|
id: '1',
|
|
name: 'MySQL',
|
|
typeVersion: 2.5,
|
|
type: 'n8n-nodes-base.mySql',
|
|
position: [0, 0],
|
|
parameters: {},
|
|
};
|
|
|
|
function mockExecuteFunctions(
|
|
params: IDataObject,
|
|
creds: MysqlNodeCredentials,
|
|
continueOnFail = false,
|
|
): IExecuteFunctions {
|
|
return {
|
|
getNodeParameter: (name: string, _i: number, fallback?: unknown) => params[name] ?? fallback,
|
|
getNode: () => node,
|
|
getInputData: () => [{ json: {} }],
|
|
continueOnFail: () => continueOnFail,
|
|
getCredentials: async () => creds,
|
|
helpers: {
|
|
constructExecutionMetaData,
|
|
getSSHClient: () => {
|
|
throw new Error('No SSH');
|
|
},
|
|
},
|
|
} as unknown as IExecuteFunctions;
|
|
}
|
|
|
|
const badCreds: MysqlNodeCredentials = {
|
|
host: 'invalid.host',
|
|
port: 3306,
|
|
database: 'x',
|
|
user: 'x',
|
|
password: 'x',
|
|
connectTimeout: 1000,
|
|
ssl: false,
|
|
sshTunnel: false,
|
|
};
|
|
|
|
describe('MySQL Integration - NODE-4174', () => {
|
|
test('happy path: SELECT against real MySQL', async () => {
|
|
const params = {
|
|
resource: 'database',
|
|
operation: 'executeQuery',
|
|
query: 'SELECT 1 as result',
|
|
options: { queryBatching: 'single', nodeVersion: 2.5 },
|
|
};
|
|
|
|
const result = await router.call(mockExecuteFunctions(params, credentials));
|
|
|
|
expect(result[0][0].json).toEqual({ result: 1 });
|
|
});
|
|
|
|
test('bad path: query error returns error item with continueOnFail', async () => {
|
|
const params = {
|
|
resource: 'database',
|
|
operation: 'executeQuery',
|
|
query: 'SELECT * FROM table_that_does_not_exist',
|
|
options: { queryBatching: 'single', nodeVersion: 2.5 },
|
|
};
|
|
|
|
const result = await router.call(mockExecuteFunctions(params, credentials, true));
|
|
|
|
expect(result[0][0].json).toHaveProperty('message');
|
|
});
|
|
|
|
test('connection error should return error item with continueOnFail', async () => {
|
|
const params = {
|
|
resource: 'database',
|
|
operation: 'executeQuery',
|
|
query: 'SELECT 1',
|
|
options: { queryBatching: 'single', nodeVersion: 2.5, connectTimeout: 1000 },
|
|
};
|
|
|
|
const result = await router.call(mockExecuteFunctions(params, badCreds, true));
|
|
|
|
expect(result[0][0].json).toHaveProperty('error');
|
|
});
|
|
|
|
test('connection error throws when continueOnFail is false', async () => {
|
|
const params = {
|
|
resource: 'database',
|
|
operation: 'executeQuery',
|
|
query: 'SELECT 1',
|
|
options: { queryBatching: 'single', nodeVersion: 2.5, connectTimeout: 1000 },
|
|
};
|
|
|
|
await expect(router.call(mockExecuteFunctions(params, badCreds, false))).rejects.toThrow();
|
|
});
|
|
});
|