From 496195f055a9c717e294260b5a610c64e65eb894 Mon Sep 17 00:00:00 2001 From: Noemi <45180344+unflxw@users.noreply.github.com> Date: Mon, 6 May 2024 15:39:01 +0200 Subject: [PATCH] Avoid silently swallowing connection errors When a connection error takes place, the test setup would silently swallow it (missing callback for `connection.connect()`) Rewrite the whole thing so that it's easier to follow, to make sure it awaits the promises, and to use a type interface that aliases over `mysql` and `mysql2` instead of `any`. --- test/koa-mysql/app/src/app.ts | 83 +++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 18 deletions(-) diff --git a/test/koa-mysql/app/src/app.ts b/test/koa-mysql/app/src/app.ts index 8939fd9d..911eb0ac 100644 --- a/test/koa-mysql/app/src/app.ts +++ b/test/koa-mysql/app/src/app.ts @@ -1,7 +1,7 @@ import Koa from "koa" import Router from "@koa/router" import bodyParser from "koa-bodyparser" -import mysql, { Connection } from "mysql" +import mysql from "mysql" import mysql2 from "mysql2" const mysqlConfig = { @@ -11,6 +11,68 @@ const mysqlConfig = { database: process.env.MYSQL_DATABASE } +type MaybeMysqlError = mysql.MysqlError | mysql2.QueryError | null | undefined + +interface MysqlConnection { + connect(callback: (err: MaybeMysqlError) => void): void + query( + sql: string, + callback: (err: MaybeMysqlError, rows: any, fields: any) => void + ): void + end(callback: (err: MaybeMysqlError) => void): void +} + +function connectionPromise(mysqlClient: MysqlModule): Promise { + return new Promise((resolve, reject) => { + let connection = mysqlClient.createConnection(mysqlConfig) + + connection.connect((err: MaybeMysqlError) => { + if (err) reject(err) + resolve(connection) + }) + }) +} + +function dummyQueryPromise(connection: MysqlConnection): Promise { + return new Promise((resolve, reject) => { + connection.query( + "SELECT 1 + 1 AS solution", + (err: MaybeMysqlError, rows: any, _fields: any) => { + if (err) reject(err) + try { + resolve(rows[0].solution) + } catch (err) { + reject(err) + } + } + ) + }) +} + +function endConnectionPromise(connection: MysqlConnection): Promise { + return new Promise((resolve, reject) => { + connection.end((err: MaybeMysqlError) => { + if (err) reject(err) + resolve() + }) + }) +} + +async function dummyQuery(mysqlClient: MysqlModule): Promise { + let connection = await connectionPromise(mysqlClient) + let result = await dummyQueryPromise(connection) + await endConnectionPromise(connection) + + return result +} + +interface MysqlModule { + createConnection(config: typeof mysqlConfig): MysqlConnection +} + +const mysqlModule: MysqlModule = mysql +const mysql2Module: MysqlModule = mysql2 + const app = new Koa() const router = new Router() const port = process.env.PORT @@ -26,32 +88,17 @@ router.get("/error", async (_ctx: any) => { }) router.get("/mysql-query", async (ctx: any) => { - await dummyQuery(mysql) + await dummyQuery(mysqlModule) ctx.body = "MySQL query received!" }) router.get("/mysql2-query", async (ctx: any) => { - await dummyQuery(mysql2) + await dummyQuery(mysql2Module) ctx.body = "MySQL2 query received!" }) -function dummyQuery(mysqlClient: any) { - let connection: Connection - - return new Promise((resolve, reject) => { - connection = mysqlClient.createConnection(mysqlConfig) - - connection.connect() - - connection.query("SELECT 1 + 1 AS solution", (err, rows, _fields) => { - if (err) reject(err) - resolve(rows[0].solution) - }) - }).finally(() => connection.end()) -} - app.use(router.routes()).use(router.allowedMethods()) app.listen(port)