Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Test Postgres and MySQL schemas
name: Test Postgres schemas

on:
schedule:
Expand All @@ -14,7 +14,7 @@ on:
- packages/cli/test/shared/db/**
- packages/@n8n/db/**
- packages/cli/**/__tests__/**
- .github/workflows/ci-postgres-mysql.yml
- .github/workflows/ci-postgres.yml
- .github/docker-compose.yml

concurrency:
Expand Down Expand Up @@ -53,65 +53,6 @@ jobs:
working-directory: packages/cli
run: pnpm test:sqlite

mariadb:
name: MariaDB
needs: build
runs-on: blacksmith-4vcpu-ubuntu-2204
timeout-minutes: 30
if: false
env:
DB_MYSQLDB_PASSWORD: password
DB_MYSQLDB_POOL_SIZE: 1
DB_MYSQLDB_CONNECTION_TIMEOUT: 120000
DB_MYSQLDB_ACQUIRE_TIMEOUT: 120000
DB_MYSQLDB_TIMEOUT: 120000
NODE_OPTIONS: '--max-old-space-size=7168'
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

- name: Setup and Build
uses: ./.github/actions/setup-nodejs

- name: Start MariaDB
uses: isbang/compose-action@802a148945af6399a338c7906c267331b39a71af # v2.0.0
with:
compose-file: ./.github/docker-compose.yml
services: |
mariadb

- name: Test MariaDB
working-directory: packages/cli
run: pnpm test:mariadb --testTimeout 120000

mysql:
name: MySQL 8.4
needs: build
runs-on: blacksmith-2vcpu-ubuntu-2204
timeout-minutes: 20
if: false
env:
DB_MYSQLDB_PASSWORD: password
DB_MYSQLDB_POOL_SIZE: 1
DB_MYSQLDB_CONNECTION_TIMEOUT: 120000
DB_MYSQLDB_ACQUIRE_TIMEOUT: 120000
DB_MYSQLDB_TIMEOUT: 120000
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

- name: Setup and Build
uses: ./.github/actions/setup-nodejs

- name: Start MySQL
uses: isbang/compose-action@802a148945af6399a338c7906c267331b39a71af # v2.0.0
with:
compose-file: ./.github/docker-compose.yml
services: mysql-8.4

- name: Test MySQL
working-directory: packages/cli
# We sleep here due to flakiness with DB tests if we connect to the database too soon
run: sleep 2s && pnpm test:mysql --testTimeout 120000

postgres:
name: Postgres
needs: build
Expand Down Expand Up @@ -149,4 +90,4 @@ jobs:
status: ${{ job.status }}
channel: '#alerts-build'
webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
message: Postgres, MariaDB or MySQL tests failed (${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
message: Postgres tests failed (${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
2 changes: 1 addition & 1 deletion packages/@n8n/api-types/src/frontend-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export interface FrontendSettings {
settingsMode?: 'public' | 'authenticated';
inE2ETests: boolean;
isDocker: boolean;
databaseType: 'sqlite' | 'mariadb' | 'mysqldb' | 'postgresdb';
databaseType: 'sqlite' | 'postgresdb';
endpointForm: string;
endpointFormTest: string;
endpointFormWaiting: string;
Expand Down
68 changes: 24 additions & 44 deletions packages/@n8n/backend-test-utils/src/test-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,14 @@ let isInitialized = false;
/**
* Generate options for a bootstrap DB connection, to create and drop test databases.
*/
export const getBootstrapDBOptions = (dbType: 'postgresdb' | 'mysqldb'): DataSourceOptions => {
export const getBootstrapDBOptions = (dbType: 'postgresdb'): DataSourceOptions => {
const globalConfig = Container.get(GlobalConfig);
const type = dbType === 'postgresdb' ? 'postgres' : 'mysql';
return {
type,
type: 'postgres',
...Container.get(DbConnectionOptions).getOverrides(dbType),
database: type,
database: 'postgres',
entityPrefix: globalConfig.database.tablePrefix,
schema: dbType === 'postgresdb' ? globalConfig.database.postgresdb.schema : undefined,
schema: globalConfig.database.postgresdb.schema,
};
};

Expand All @@ -42,12 +41,6 @@ export async function init() {
await bootstrapPostgres.destroy();

globalConfig.database.postgresdb.database = testDbName;
} else if (dbType === 'mysqldb' || dbType === 'mariadb') {
const bootstrapMysql = await new Connection(getBootstrapDBOptions('mysqldb')).initialize();
await bootstrapMysql.query(`CREATE DATABASE ${testDbName} DEFAULT CHARACTER SET utf8mb4`);
await bootstrapMysql.destroy();

globalConfig.database.mysqldb.database = testDbName;
}

const dbConnection = Container.get(DbConnection);
Expand Down Expand Up @@ -97,44 +90,31 @@ type EntityName =
*/
export async function truncate(entities: EntityName[]) {
const connection = Container.get(Connection);
const dbType = connection.options.type;

// Disable FK checks for MySQL/MariaDB to handle circular dependencies
if (dbType === 'mysql' || dbType === 'mariadb') {
await connection.query('SET FOREIGN_KEY_CHECKS=0');
}

try {
// Collect junction tables to clean
const junctionTablesToClean = new Set<string>();

// Find all junction tables associated with the entities being truncated
for (const name of entities) {
try {
const metadata = connection.getMetadata(name);
for (const relation of metadata.manyToManyRelations) {
if (relation.junctionEntityMetadata) {
const junctionTableName = relation.junctionEntityMetadata.tablePath;
junctionTablesToClean.add(junctionTableName);
}
// Collect junction tables to clean
const junctionTablesToClean = new Set<string>();

// Find all junction tables associated with the entities being truncated
for (const name of entities) {
try {
const metadata = connection.getMetadata(name);
for (const relation of metadata.manyToManyRelations) {
if (relation.junctionEntityMetadata) {
const junctionTableName = relation.junctionEntityMetadata.tablePath;
junctionTablesToClean.add(junctionTableName);
}
} catch (error) {
// Skip
}
} catch (error) {
// Skip
}
}

// Clean junction tables first (since they reference the entities)
for (const tableName of junctionTablesToClean) {
await connection.query(`DELETE FROM ${tableName}`);
}
// Clean junction tables first (since they reference the entities)
for (const tableName of junctionTablesToClean) {
await connection.query(`DELETE FROM ${tableName}`);
}

for (const name of entities) {
await connection.getRepository(name).delete({});
}
} finally {
// Re-enable FK checks
if (dbType === 'mysql' || dbType === 'mariadb') {
await connection.query('SET FOREIGN_KEY_CHECKS=1');
}
for (const name of entities) {
await connection.getRepository(name).delete({});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe('DatabaseConfig', () => {
jest.clearAllMocks();
});

test.each(['sqlite', 'mariadb', 'mysqldb', 'postgresdb'] satisfies Array<DatabaseConfig['type']>)(
test.each(['sqlite', 'postgresdb'] satisfies Array<DatabaseConfig['type']>)(
'`isLegacySqlite` returns false if dbType is `%s`',
(dbType) => {
const databaseConfig = Container.get(DatabaseConfig);
Expand Down
49 changes: 1 addition & 48 deletions packages/@n8n/config/src/configs/database.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,6 @@ import { Config, Env, Nested } from '../decorators';
const dbLoggingOptionsSchema = z.enum(['query', 'error', 'schema', 'warn', 'info', 'log', 'all']);
type DbLoggingOptions = z.infer<typeof dbLoggingOptionsSchema>;

class MySqlMariaDbNotSupportedError extends Error {
// Workaround to not get this reported to Sentry
readonly cause: { level: 'warning' } = {
level: 'warning',
};

constructor() {
super('MySQL and MariaDB have been removed. Please migrate to PostgreSQL.');
}
}

@Config
class LoggingConfig {
/** Whether database logging is enabled. */
Expand Down Expand Up @@ -103,33 +92,6 @@ class PostgresConfig {
ssl: PostgresSSLConfig;
}

@Config
class MysqlConfig {
/** @deprecated MySQL database name */
@Env('DB_MYSQLDB_DATABASE')
database: string = 'n8n';

/** MySQL database host */
@Env('DB_MYSQLDB_HOST')
host: string = 'localhost';

/** MySQL database password */
@Env('DB_MYSQLDB_PASSWORD')
password: string = '';

/** MySQL database port */
@Env('DB_MYSQLDB_PORT')
port: number = 3306;

/** MySQL database user */
@Env('DB_MYSQLDB_USER')
user: string = 'root';

/** MySQL connection pool size */
@Env('DB_MYSQLDB_POOL_SIZE')
poolSize: number = 10;
}

const sqlitePoolSizeSchema = z.coerce.number().int().gte(1);

@Config
Expand Down Expand Up @@ -157,7 +119,7 @@ export class SqliteConfig {
executeVacuumOnStartup: boolean = false;
}

const dbTypeSchema = z.enum(['sqlite', 'mariadb', 'mysqldb', 'postgresdb']);
const dbTypeSchema = z.enum(['sqlite', 'postgresdb']);
type DbType = z.infer<typeof dbTypeSchema>;

@Config
Expand Down Expand Up @@ -189,15 +151,6 @@ export class DatabaseConfig {
@Nested
postgresdb: PostgresConfig;

@Nested
mysqldb: MysqlConfig;

@Nested
sqlite: SqliteConfig;

sanitize() {
if (this.type === 'mariadb' || this.type === 'mysqldb') {
throw new MySqlMariaDbNotSupportedError();
}
}
}
9 changes: 0 additions & 9 deletions packages/@n8n/config/test/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,6 @@ describe('GlobalConfig', () => {
maxQueryExecutionTime: 0,
options: 'error',
},
mysqldb: {
database: 'n8n',
host: 'localhost',
password: '',
port: 3306,
user: 'root',
poolSize: 10,
},
postgresdb: {
database: 'n8n',
host: 'localhost',
Expand Down Expand Up @@ -451,7 +443,6 @@ describe('GlobalConfig', () => {
...defaultConfig,
database: {
logging: defaultConfig.database.logging,
mysqldb: defaultConfig.database.mysqldb,
postgresdb: {
...defaultConfig.database.postgresdb,
host: 'some-host',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { GlobalConfig, InstanceSettingsConfig } from '@n8n/config';
import { mock } from 'jest-mock-extended';
import path from 'path';

import { mysqlMigrations } from '../../migrations/mysqldb';
import { postgresMigrations } from '../../migrations/postgresdb';
import { sqliteMigrations } from '../../migrations/sqlite';
import { DbConnectionOptions } from '../db-connection-options';
Expand Down Expand Up @@ -149,57 +148,6 @@ describe('DbConnectionOptions', () => {
});
});

describe('for MySQL / MariaDB', () => {
beforeEach(() => {
dbConfig.mysqldb = {
database: 'test_db',
host: 'localhost',
port: 3306,
user: 'root',
password: 'password',
poolSize: 10,
};
});

it('should return MySQL connection options when type is mysqldb', () => {
dbConfig.type = 'mysqldb';

const result = dbConnectionOptions.getOptions();

expect(result).toEqual({
type: 'mysql',
...commonOptions,
database: 'test_db',
host: 'localhost',
port: 3306,
username: 'root',
password: 'password',
migrations: mysqlMigrations,
timezone: 'Z',
poolSize: 10,
});
});

it('should return MariaDB connection options when type is mariadb', () => {
dbConfig.type = 'mariadb';

const result = dbConnectionOptions.getOptions();

expect(result).toEqual({
type: 'mariadb',
...commonOptions,
database: 'test_db',
host: 'localhost',
port: 3306,
username: 'root',
password: 'password',
migrations: mysqlMigrations,
timezone: 'Z',
poolSize: 10,
});
});
});

describe('logging', () => {
beforeEach(() => {
dbConfig.type = 'sqlite';
Expand Down
Loading