From a81a7ac92d2deae4db3c71058d7175664299a809 Mon Sep 17 00:00:00 2001 From: Sebastian-Webster <84299475+Sebastian-Webster@users.noreply.github.com> Date: Wed, 15 Jan 2025 16:39:41 +0400 Subject: [PATCH 1/2] move internal options to env --- README.md | 29 --------------------------- src/cli.ts | 5 ++--- src/constants.ts | 39 ++++++++++++------------------------- src/index.ts | 10 ++-------- src/libraries/Downloader.ts | 3 ++- src/libraries/Executor.ts | 19 +++++++++--------- stress-tests/stress.test.ts | 7 ++++--- tests/sql.test.ts | 9 ++++----- tests/versions.test.ts | 8 ++++---- types/index.ts | 12 ++---------- 10 files changed, 42 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index 30372461..689e95cb 100644 --- a/README.md +++ b/README.md @@ -200,32 +200,3 @@ The internal queries that are ran before the queries in ```initSQLString``` are Default: process.arch Description: The MySQL binary architecture to execute. MySQL does not offer server builds for Windows on ARM, so to get this package working on Windows on ARM, set the arch option to "x64" and Windows will emulate MySQL. - -*** -### :warning: Internal Options :warning: - -The following options are only meant for internal use (such as for testing this package or the internals for running this package via the CLI). Their behaviour may change or they may get removed between major/minor/patch versions and they are not to be considered stable. The options below will not follow Semantic Versioning so it is advised to not use them. - -- `_DO_NOT_USE_deleteDBAfterStopped: boolean` - -Default: true - -Description: Changes whether or not the database will be deleted after it has been stopped. If set to `true`, the database WILL be deleted after it has been stopped. - -- `_DO_NOT_USE_dbPath: string` - -Default: `TMPDIR/mysqlmsn/dbs/UUID` (replacing TMPDIR with the OS temp directory and UUID with a UUIDv4 without seperating dashes). - -Description: The folder to store database-related data in - -- `_DO_NOT_USE_binaryDirectoryPath: string` - -Default: `TMPDIR/mysqlmsn/binaries` (replacing TMPDIR with the OS temp directory) - -Description: The folder to store the MySQL binaries when they are downloaded from the CDN. - -- `_DO_NOT_USE_cli: boolean` - -Default: ```false``` if the package is not being executed via the CLI and ```true``` if it is. - -Description: If set to ```true```, this enables certain CLI-only functionality. For example, when ran by the CLI, logging a message to the console when a shutdown signal (like CTRL + C) has been received and the MySQL database is shutting down and getting deleted. diff --git a/src/cli.ts b/src/cli.ts index 1c7541d4..a8bab6a3 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -5,9 +5,8 @@ import { ServerOptions } from "../types"; function main() { const definedOptions = process.argv.filter((option) => option.startsWith('--')) - const options: ServerOptions = { - _DO_NOT_USE_cli: true - } + const options: ServerOptions = {} + process.env.mysqlmsn_internal_DO_NOT_USE_cli = 'true' for (const opt of definedOptions) { if (!DEFAULT_OPTIONS_KEYS.includes(opt.replace('--', ''))) { console.error(`Option ${opt} is not a valid option.`) diff --git a/src/constants.ts b/src/constants.ts index d011328b..8ced887c 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -20,12 +20,7 @@ export const DEFAULT_OPTIONS_GENERATOR: () => InternalServerOptions = () => ({ xPort: 0, downloadRetries: 10, initSQLString: '', - arch: process.arch, - _DO_NOT_USE_deleteDBAfterStopped: true, - //mysqlmsn = MySQL Memory Server Node.js - _DO_NOT_USE_dbPath: normalizePath(`${tmpdir()}/mysqlmsn/dbs/${randomUUID().replace(/-/g, '')}`), - _DO_NOT_USE_binaryDirectoryPath: `${tmpdir()}/mysqlmsn/binaries`, - _DO_NOT_USE_cli: false + arch: process.arch }); export const DEFAULT_OPTIONS_KEYS = Object.freeze(Object.keys(DEFAULT_OPTIONS_GENERATOR())) @@ -36,7 +31,17 @@ export const LOG_LEVELS = { 'ERROR': 2 } as const; -export const INTERNAL_OPTIONS = ['_DO_NOT_USE_deleteDBAfterStopped', '_DO_NOT_USE_dbPath', '_DO_NOT_USE_binaryDirectoryPath', '_DO_NOT_USE_cli'] as const; +const internalOptions = { + deleteDBAfterStopped: 'true', + //mysqlmsn = MySQL Memory Server Node.js + dbPath: normalizePath(`${tmpdir()}/mysqlmsn/dbs/${randomUUID().replace(/-/g, '')}`), + binaryDirectoryPath: `${tmpdir()}/mysqlmsn/binaries`, + cli: 'false' +} + +export function getInternalEnvVariable(envVar: keyof typeof internalOptions): string { + return process.env['mysqlmsn_internal_DO_NOT_USE_' + envVar] || internalOptions[envVar] +} const allowedArches = ['x64', 'arm64', undefined] export const OPTION_TYPE_CHECKS: OptionTypeChecks = { @@ -109,25 +114,5 @@ export const OPTION_TYPE_CHECKS: OptionTypeChecks = { check: (opt: any) => allowedArches.includes(opt), errorMessage: `Option arch must be either of the following: ${allowedArches.join(', ')}`, definedType: 'string' - }, - _DO_NOT_USE_deleteDBAfterStopped: { - check: (opt: any) => opt === undefined || typeof opt === 'boolean', - errorMessage: 'Option _DO_NOT_USE_deleteDBAfterStopped must be either undefined or a boolean.', - definedType: 'boolean' - }, - _DO_NOT_USE_dbPath: { - check: (opt: any) => opt === undefined || typeof opt === 'string', - errorMessage: 'Option _DO_NOT_USE_dbPath must be either undefined or a string.', - definedType: 'string' - }, - _DO_NOT_USE_binaryDirectoryPath: { - check: (opt: any) => opt === undefined || typeof opt === 'string', - errorMessage: 'Option _DO_NOT_USE_binaryDirectoryPath must be either undefined or a string.', - definedType: 'string' - }, - _DO_NOT_USE_cli: { - check: (opt: any) => opt === undefined || typeof opt === 'boolean', - errorMessage: 'Option _DO_NOT_USE_cli must be either undefined or a boolean.', - definedType: 'boolean' } } as const; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index d105ae94..4556a5ce 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,22 +2,16 @@ import Logger from './libraries/Logger' import * as os from 'node:os' import Executor from "./libraries/Executor" import { satisfies, lt, coerce } from "semver" -import { BinaryInfo, InternalServerOptions, ServerOptions } from '../types' +import { BinaryInfo, ServerOptions } from '../types' import getBinaryURL from './libraries/Version' import MySQLVersions from './versions.json' import { downloadBinary } from './libraries/Downloader' -import { MIN_SUPPORTED_MYSQL, DEFAULT_OPTIONS_KEYS, OPTION_TYPE_CHECKS, INTERNAL_OPTIONS, DEFAULT_OPTIONS_GENERATOR } from './constants' +import { MIN_SUPPORTED_MYSQL, DEFAULT_OPTIONS_KEYS, OPTION_TYPE_CHECKS, DEFAULT_OPTIONS_GENERATOR } from './constants' export async function createDB(opts?: ServerOptions) { const suppliedOpts = opts || {}; const suppliedOptsKeys = Object.keys(suppliedOpts); - for (const opt of INTERNAL_OPTIONS) { - if (suppliedOptsKeys.includes(opt)) { - console.warn(`[ mysql-memory-server - Options WARN ]: Creating MySQL database with option ${opt}. This is considered unstable and should not be used externally. Please consider removing this option.`) - } - } - const options = DEFAULT_OPTIONS_GENERATOR(); for (const opt of suppliedOptsKeys) { diff --git a/src/libraries/Downloader.ts b/src/libraries/Downloader.ts index aa429590..71ffeb43 100644 --- a/src/libraries/Downloader.ts +++ b/src/libraries/Downloader.ts @@ -8,6 +8,7 @@ import { randomUUID } from 'crypto'; import { execFile } from 'child_process'; import { BinaryInfo, InternalServerOptions } from '../../types'; import { lockFile, waitForLock } from './FileLock'; +import { getInternalEnvVariable } from '../constants'; function getZipData(entry: AdmZip.IZipEntry): Promise { return new Promise((resolve, reject) => { @@ -181,7 +182,7 @@ function extractBinary(url: string, archiveLocation: string, extractedLocation: export function downloadBinary(binaryInfo: BinaryInfo, options: InternalServerOptions, logger: Logger): Promise { return new Promise(async (resolve, reject) => { const {url, version} = binaryInfo; - const dirpath = options._DO_NOT_USE_binaryDirectoryPath + const dirpath = getInternalEnvVariable('binaryDirectoryPath') logger.log('Binary path:', dirpath) await fsPromises.mkdir(dirpath, {recursive: true}) diff --git a/src/libraries/Executor.ts b/src/libraries/Executor.ts index 21a148f3..2af7ed2c 100644 --- a/src/libraries/Executor.ts +++ b/src/libraries/Executor.ts @@ -10,6 +10,7 @@ import {normalize as normalizePath, resolve as resolvePath} from 'path' import { lockFile, waitForLock } from "./FileLock"; import { onExit } from "signal-exit"; import { randomUUID } from "crypto"; +import { getInternalEnvVariable } from "../constants"; class Executor { logger: Logger; @@ -117,7 +118,7 @@ class Executor { if (portIssue || xPortIssue) { this.logger.log('Error log when exiting for port in use error:', errorLog) try { - await this.#deleteDatabaseDirectory(options._DO_NOT_USE_dbPath) + await this.#deleteDatabaseDirectory(getInternalEnvVariable('dbPath')) } catch (e) { this.logger.error(e) return reject(`MySQL failed to listen on a certain port. To restart MySQL with a different port, the database directory needed to be deleted. An error occurred while deleting the database directory. Aborting. The error was: ${e}`) @@ -126,7 +127,7 @@ class Executor { } try { - if (options._DO_NOT_USE_deleteDBAfterStopped) { + if (getInternalEnvVariable('deleteDBAfterStopped') === 'true') { await this.#deleteDatabaseDirectory(dbPath) } } catch (e) { @@ -421,7 +422,7 @@ class Executor { this.logger.log('Writing init file') - await fsPromises.writeFile(`${options._DO_NOT_USE_dbPath}/init.sql`, initText, {encoding: 'utf8'}) + await fsPromises.writeFile(`${getInternalEnvVariable('dbPath')}/init.sql`, initText, {encoding: 'utf8'}) this.logger.log('Finished writing init file') } @@ -430,15 +431,15 @@ class Executor { this.version = installedMySQLBinary.version this.versionInstalledOnSystem = installedMySQLBinary.installedOnSystem this.removeExitHandler = onExit(() => { - if (options._DO_NOT_USE_cli) { + if (getInternalEnvVariable('cli') === 'true') { console.log('\nShutting down the ephemeral MySQL database and cleaning all related files...') } this.DBDestroySignal.abort() - if (options._DO_NOT_USE_deleteDBAfterStopped) { + if (getInternalEnvVariable('deleteDBAfterStopped') === 'true') { try { - fs.rmSync(options._DO_NOT_USE_dbPath, {recursive: true, maxRetries: 50, force: true}) + fs.rmSync(getInternalEnvVariable('dbPath'), {recursive: true, maxRetries: 50, force: true}) } catch (e) { this.logger.error('An error occurred while deleting database directory path:', e) } @@ -453,14 +454,14 @@ class Executor { } } - if (options._DO_NOT_USE_cli) { + if (getInternalEnvVariable('cli') === 'true') { console.log('Shutdown and cleanup is complete.') } }) let retries = 0; - const datadir = normalizePath(`${options._DO_NOT_USE_dbPath}/data`) + const datadir = normalizePath(`${getInternalEnvVariable('dbPath')}/data`) do { await this.#setupDataDirectories(options, installedMySQLBinary.path, datadir, true); @@ -472,7 +473,7 @@ class Executor { try { this.logger.log('Starting MySQL process') - const resolved = await this.#startMySQLProcess(options, port, mySQLXPort, datadir, options._DO_NOT_USE_dbPath, installedMySQLBinary.path) + const resolved = await this.#startMySQLProcess(options, port, mySQLXPort, datadir, getInternalEnvVariable('dbPath'), installedMySQLBinary.path) this.logger.log('Starting process was successful') return resolved } catch (e) { diff --git a/stress-tests/stress.test.ts b/stress-tests/stress.test.ts index 7fab4316..7ec3717a 100644 --- a/stress-tests/stress.test.ts +++ b/stress-tests/stress.test.ts @@ -14,17 +14,18 @@ for (let i = 0; i < 100; i++) { test.concurrent(`if run ${i} is successful`, async () => { Error.stackTraceLimit = Infinity console.log('CI:', process.env.useCIDBPath) + + process.env.mysqlmsn_internal_DO_NOT_USE_deleteDBAfterStopped = String(!process.env.useCIDBPath) const options: ServerOptions = { username: 'dbuser', logLevel: 'LOG', - _DO_NOT_USE_deleteDBAfterStopped: !process.env.useCIDBPath, ignoreUnsupportedSystemVersion: true } if (process.env.useCIDBPath) { - options._DO_NOT_USE_dbPath = `${dbPath}/${i}` - options._DO_NOT_USE_binaryDirectoryPath = binaryPath + process.env.mysqlmsn_internal_DO_NOT_USE_dbPath = `${dbPath}/${i}` + process.env.mysqlmsn_internal_DO_NOT_USE_binaryDirectoryPath = binaryPath } const db = await createDB(options) diff --git a/tests/sql.test.ts b/tests/sql.test.ts index 29b6f550..f4cdbb12 100644 --- a/tests/sql.test.ts +++ b/tests/sql.test.ts @@ -14,24 +14,23 @@ const dbPath = normalize(GitHubActionsTempFolder + '/dbs') const binaryPath = normalize(GitHubActionsTempFolder + '/binaries') beforeEach(async () => { - Error.stackTraceLimit = Infinity + process.env.mysqlmsn_internal_DO_NOT_USE_deleteDBAfterStopped = String(!process.env.useCIDBPath) + const options: ServerOptions = { username: 'root', logLevel: 'LOG', - _DO_NOT_USE_deleteDBAfterStopped: !process.env.useCIDBPath, ignoreUnsupportedSystemVersion: true } if (process.env.useCIDBPath) { - options._DO_NOT_USE_dbPath = `${dbPath}/${randomUUID()}` - options._DO_NOT_USE_binaryDirectoryPath = binaryPath + process.env.mysqlmsn_internal_DO_NOT_USE_dbPath = `${dbPath}/${randomUUID()}` + process.env.mysqlmsn_internal_DO_NOT_USE_binaryDirectoryPath = binaryPath } db = await createDB(options) }) afterEach(async () => { - Error.stackTraceLimit = Infinity await db.stop(); }) diff --git a/tests/versions.test.ts b/tests/versions.test.ts index 8e00f579..d04c83dc 100644 --- a/tests/versions.test.ts +++ b/tests/versions.test.ts @@ -18,20 +18,20 @@ jest.setTimeout(500_000); for (const version of versions) { for (const username of usernames) { test.concurrent(`running on version ${version} with username ${username}`, async () => { - Error.stackTraceLimit = Infinity + process.env.mysqlmsn_internal_DO_NOT_USE_deleteDBAfterStopped = String(!process.env.useCIDBPath) + const options: ServerOptions = { version, dbName: 'testingdata', username: username, logLevel: 'LOG', - _DO_NOT_USE_deleteDBAfterStopped: !process.env.useCIDBPath, ignoreUnsupportedSystemVersion: true, initSQLString: 'CREATE DATABASE mytestdb;' } if (process.env.useCIDBPath) { - options._DO_NOT_USE_dbPath = `${dbPath}/${randomUUID()}` - options._DO_NOT_USE_binaryDirectoryPath = binaryPath + process.env.mysqlmsn_internal_DO_NOT_USE_dbPath = `${dbPath}/${randomUUID()}` + process.env.mysqlmsn_internal_DO_NOT_USE_binaryDirectoryPath = binaryPath } const db = await createDB(options) diff --git a/types/index.ts b/types/index.ts index 5a701f92..6038dbee 100644 --- a/types/index.ts +++ b/types/index.ts @@ -16,11 +16,7 @@ export type ServerOptions = { xPort?: number | undefined, downloadRetries?: number | undefined, initSQLString?: string | undefined, - arch?: "arm64" | "x64" | undefined, - _DO_NOT_USE_deleteDBAfterStopped?: boolean | undefined, - _DO_NOT_USE_dbPath?: string | undefined, - _DO_NOT_USE_binaryDirectoryPath?: string | undefined, - _DO_NOT_USE_cli?: boolean | undefined + arch?: "arm64" | "x64" | undefined } export type InternalServerOptions = { @@ -37,11 +33,7 @@ export type InternalServerOptions = { xPort: number, downloadRetries: number, initSQLString: string, - arch: string, - _DO_NOT_USE_deleteDBAfterStopped: boolean, - _DO_NOT_USE_dbPath: string, - _DO_NOT_USE_binaryDirectoryPath: string, - _DO_NOT_USE_cli: boolean + arch: string } export type ExecutorOptions = { From db5421d98d93c4ae30280e10720f5916108fbcf4 Mon Sep 17 00:00:00 2001 From: Sebastian-Webster <84299475+Sebastian-Webster@users.noreply.github.com> Date: Wed, 15 Jan 2025 17:54:30 +0400 Subject: [PATCH 2/2] remove jest concurrency --- stress-tests/stress.test.ts | 3 +-- tests/versions.test.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/stress-tests/stress.test.ts b/stress-tests/stress.test.ts index 7ec3717a..78012180 100644 --- a/stress-tests/stress.test.ts +++ b/stress-tests/stress.test.ts @@ -11,8 +11,7 @@ const dbPath = normalize(GitHubActionsTempFolder + '/dbs') const binaryPath = normalize(GitHubActionsTempFolder + '/binaries') for (let i = 0; i < 100; i++) { - test.concurrent(`if run ${i} is successful`, async () => { - Error.stackTraceLimit = Infinity + test(`if run ${i} is successful`, async () => { console.log('CI:', process.env.useCIDBPath) process.env.mysqlmsn_internal_DO_NOT_USE_deleteDBAfterStopped = String(!process.env.useCIDBPath) diff --git a/tests/versions.test.ts b/tests/versions.test.ts index d04c83dc..e57dbd57 100644 --- a/tests/versions.test.ts +++ b/tests/versions.test.ts @@ -17,7 +17,7 @@ jest.setTimeout(500_000); for (const version of versions) { for (const username of usernames) { - test.concurrent(`running on version ${version} with username ${username}`, async () => { + test(`running on version ${version} with username ${username}`, async () => { process.env.mysqlmsn_internal_DO_NOT_USE_deleteDBAfterStopped = String(!process.env.useCIDBPath) const options: ServerOptions = {