fix(cli): Fix community nodes tests on Postgres and MySQL (#3861)

* 📘 Fix type

*  Adjust constants

* 🧪 Skip failing pagination fix

* 🧪 Make truncation sequential
This commit is contained in:
Iván Ovejero
2022-08-11 11:02:21 +02:00
committed by GitHub
parent a6e1b82c02
commit 620525ea85
6 changed files with 62 additions and 56 deletions

View File

@@ -58,7 +58,6 @@ export const MAPPING_TABLES_TO_CLEAR: Record<string, string[] | undefined> = {
Tag: ['workflows_tags'],
};
/**
* Name of the connection used for creating and dropping a Postgres DB
* for each suite test run.
@@ -71,16 +70,15 @@ export const BOOTSTRAP_POSTGRES_CONNECTION_NAME: Readonly<string> = 'n8n_bs_post
*/
export const BOOTSTRAP_MYSQL_CONNECTION_NAME: Readonly<string> = 'n8n_bs_mysql';
/**
* Timeout (in milliseconds) to account for fake SMTP service being slow to respond.
*/
export const SMTP_TEST_TIMEOUT = 30_000;
export const COMMUNITY_PACKAGE_VERSION = {
CURRENT: '0.1.0',
UPDATED: '0.2.0',
};
/**
* Nodes
*/
export const CURRENT_PACKAGE_VERSION = '0.1.0';
export const UPDATED_PACKAGE_VERSION = '0.2.0';
export const COMMUNITY_NODE_VERSION = {
CURRENT: 1,
UPDATED: 2,
};
/**
* Timeout (in milliseconds) to account for DB being slow to initialize.

View File

@@ -24,7 +24,13 @@ import { categorize, getPostgresSchemaSection } from './utils';
import { createCredentiasFromCredentialsEntity } from '../../../src/CredentialsHelper';
import type { Role } from '../../../src/databases/entities/Role';
import type { CollectionName, CredentialPayload, InstalledNodePayload, InstalledPackagePayload, MappingName } from './types';
import type {
CollectionName,
CredentialPayload,
InstalledNodePayload,
InstalledPackagePayload,
MappingName,
} from './types';
import { InstalledPackages } from '../../../src/databases/entities/InstalledPackages';
import { InstalledNodes } from '../../../src/databases/entities/InstalledNodes';
import { User } from '../../../src/databases/entities/User';
@@ -167,7 +173,7 @@ async function truncateMappingTables(
if (dbType === 'postgresdb') {
const schema = config.getEnv('database.postgresdb.schema');
// `TRUNCATE` in postgres cannot be parallelized
// sequential TRUNCATEs to prevent race conditions
for (const tableName of mappingTables) {
const fullTableName = `${schema}.${tableName}`;
await testDb.query(`TRUNCATE TABLE ${fullTableName} RESTART IDENTITY CASCADE;`);
@@ -217,29 +223,37 @@ export async function truncate(collections: Array<CollectionName>, testDbName: s
if (dbType === 'postgresdb') {
const schema = config.getEnv('database.postgresdb.schema');
// `TRUNCATE` in postgres cannot be parallelized
// sequential TRUNCATEs to prevent race conditions
for (const collection of collections) {
const fullTableName = `${schema}.${toTableName(collection)}`;
await testDb.query(`TRUNCATE TABLE ${fullTableName} RESTART IDENTITY CASCADE;`);
}
return await truncateMappingTables(dbType, collections, testDb);
return truncateMappingTables(dbType, collections, testDb);
}
/**
* MySQL `TRUNCATE` requires enabling and disabling the global variable `foreign_key_checks`,
* which cannot be safely manipulated by parallel tests, so use `DELETE` and `AUTO_INCREMENT`.
* Clear shared tables first to avoid deadlock: https://stackoverflow.com/a/41174997
*/
if (dbType === 'mysqldb') {
const { pass: isShared, fail: isNotShared } = categorize(
collections,
(collectionName: CollectionName) => collectionName.toLowerCase().startsWith('shared'),
const { pass: sharedTables, fail: rest } = categorize(collections, (c: CollectionName) =>
c.toLowerCase().startsWith('shared'),
);
await truncateMySql(testDb, isShared);
await truncateMappingTables(dbType, collections, testDb);
await truncateMySql(testDb, isNotShared);
// sequential DELETEs to prevent race conditions
// clear foreign-key tables first to avoid deadlocks on MySQL: https://stackoverflow.com/a/41174997
for (const collection of [...sharedTables, ...rest]) {
const tableName = toTableName(collection);
await testDb.query(`DELETE FROM ${tableName};`);
const hasIdColumn = await testDb
.query(`SHOW COLUMNS FROM ${tableName}`)
.then((columns: { Field: string }[]) => columns.find((c) => c.Field === 'id'));
if (!hasIdColumn) continue;
await testDb.query(`ALTER TABLE ${tableName} AUTO_INCREMENT = 1;`);
}
return truncateMappingTables(dbType, collections, testDb);
}
}
@@ -265,16 +279,6 @@ function toTableName(sourceName: CollectionName | MappingName) {
}[sourceName];
}
function truncateMySql(connection: Connection, collections: CollectionName[]) {
return Promise.all(
collections.map(async (collection) => {
const tableName = toTableName(collection);
await connection.query(`DELETE FROM ${tableName};`);
await connection.query(`ALTER TABLE ${tableName} AUTO_INCREMENT = 1;`);
}),
);
}
// ----------------------------------
// credential creation
// ----------------------------------
@@ -346,23 +350,25 @@ export function createUserShell(globalRole: Role): Promise<User> {
// Installed nodes and packages creation
// --------------------------------------
export async function saveInstalledPackage(installedPackagePayload: InstalledPackagePayload): Promise<InstalledPackages> {
export async function saveInstalledPackage(
installedPackagePayload: InstalledPackagePayload,
): Promise<InstalledPackages> {
const newInstalledPackage = new InstalledPackages();
Object.assign(newInstalledPackage, installedPackagePayload);
const savedInstalledPackage = await Db.collections.InstalledPackages.save(newInstalledPackage);
return savedInstalledPackage;
}
export async function saveInstalledNode(installedNodePayload: InstalledNodePayload): Promise<InstalledNodes> {
export function saveInstalledNode(
installedNodePayload: InstalledNodePayload,
): Promise<InstalledNodes> {
const newInstalledNode = new InstalledNodes();
Object.assign(newInstalledNode, installedNodePayload);
const savedInstalledNode = await Db.collections.InstalledNodes.save(newInstalledNode);
return savedInstalledNode;
return Db.collections.InstalledNodes.save(newInstalledNode);
}
export function addApiKey(user: User): Promise<User> {

View File

@@ -58,6 +58,6 @@ export type InstalledPackagePayload = {
export type InstalledNodePayload = {
name: string;
type: string;
latestVersion: string;
latestVersion: number;
package: string;
};

View File

@@ -25,7 +25,8 @@ import {
import config from '../../../config';
import {
AUTHLESS_ENDPOINTS,
CURRENT_PACKAGE_VERSION,
COMMUNITY_NODE_VERSION,
COMMUNITY_PACKAGE_VERSION,
PUBLIC_API_REST_PATH_SEGMENT,
REST_PATH_SEGMENT,
} from './constants';
@@ -908,7 +909,7 @@ export function getPostgresSchemaSection(
export function installedPackagePayload(): InstalledPackagePayload {
return {
packageName: NODE_PACKAGE_PREFIX + randomName(),
installedVersion: CURRENT_PACKAGE_VERSION,
installedVersion: COMMUNITY_PACKAGE_VERSION.CURRENT,
};
}
@@ -917,7 +918,7 @@ export function installedNodePayload(packageName: string): InstalledNodePayload
return {
name: nodeName,
type: nodeName,
latestVersion: CURRENT_PACKAGE_VERSION,
latestVersion: COMMUNITY_NODE_VERSION.CURRENT,
package: packageName,
};
}