fix: remove duplicate and keep old behavior

This commit is contained in:
leonace924 2026-01-06 01:13:42 -05:00
parent af0866ec7d
commit e6481fa8aa
2 changed files with 81 additions and 29 deletions

View File

@ -30,39 +30,84 @@ class MysqlMonitorType extends MonitorType {
// TODO: rename `radius_password` to `password` later for general use // TODO: rename `radius_password` to `password` later for general use
const password = monitor.radiusPassword; const password = monitor.radiusPassword;
let result; const conditions = ConditionExpressionGroup.fromMonitor(monitor);
const hasConditions = conditions && conditions.length > 0;
try { try {
result = await this.mysqlQuery(monitor.databaseConnectionString, query, password); if (hasConditions) {
// When conditions are enabled, expect a single value result
const result = await this.mysqlQuerySingleValue(monitor.databaseConnectionString, query, password);
heartbeat.ping = dayjs().valueOf() - startTime;
const conditionsResult = evaluateExpressionGroup(conditions, { result: String(result) });
if (!conditionsResult) {
throw new Error(`Query result did not meet the specified conditions (${result})`);
}
heartbeat.msg = "";
} else {
// Backwards compatible: just check connection and return row count
const result = await this.mysqlQuery(monitor.databaseConnectionString, query, password);
heartbeat.ping = dayjs().valueOf() - startTime;
heartbeat.msg = result;
}
} catch (error) { } catch (error) {
heartbeat.ping = dayjs().valueOf() - startTime;
log.error("mysql", "Database query failed:", error.message); log.error("mysql", "Database query failed:", error.message);
throw new Error(`Database connection/query failed: ${error.message}`); throw new Error(`Database connection/query failed: ${error.message}`);
} finally {
heartbeat.ping = dayjs().valueOf() - startTime;
} }
const conditions = ConditionExpressionGroup.fromMonitor(monitor);
const handleConditions = (data) =>
conditions ? evaluateExpressionGroup(conditions, data) : true;
// Since result is now a single value, pass it directly to conditions
const conditionsResult = handleConditions({ result: String(result) });
if (!conditionsResult) {
throw new Error(`Query result did not meet the specified conditions (${result})`);
}
heartbeat.msg = "";
heartbeat.status = UP; heartbeat.status = UP;
} }
/** /**
* Run a query on MySQL/MariaDB * Run a query on MySQL/MariaDB (backwards compatible - returns row count)
* @param {string} connectionString The database connection string
* @param {string} query The query to execute
* @param {string} password Optional password override
* @returns {Promise<string>} Row count message
*/
mysqlQuery(connectionString, query, password = undefined) {
return new Promise((resolve, reject) => {
const connection = mysql.createConnection({
uri: connectionString,
password
});
connection.on("error", (err) => {
reject(err);
});
connection.query(query, (err, res) => {
try {
connection.end();
} catch (_) {
connection.destroy();
}
if (err) {
reject(err);
return;
}
if (Array.isArray(res)) {
resolve("Rows: " + res.length);
} else {
resolve("No Error, but the result is not an array. Type: " + typeof res);
}
});
});
}
/**
* Run a query on MySQL/MariaDB expecting a single value result
* @param {string} connectionString The database connection string * @param {string} connectionString The database connection string
* @param {string} query The query to execute * @param {string} query The query to execute
* @param {string} password Optional password override * @param {string} password Optional password override
* @returns {Promise<any>} Single value from the first column of the first row * @returns {Promise<any>} Single value from the first column of the first row
*/ */
mysqlQuery(connectionString, query, password = undefined) { mysqlQuerySingleValue(connectionString, query, password = undefined) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const connection = mysql.createConnection({ const connection = mysql.createConnection({
uri: connectionString, uri: connectionString,

View File

@ -6,12 +6,19 @@ const { UP, PENDING } = require("../../../src/util");
/** /**
* Helper function to create and start a MariaDB container * Helper function to create and start a MariaDB container
* @returns {Promise<MariaDbContainer>} The started MariaDB container * @returns {Promise<{container: MariaDbContainer, connectionString: string}>} The started container and connection string
*/ */
async function createAndStartMariaDBContainer() { async function createAndStartMariaDBContainer() {
return await new MariaDbContainer("mariadb:10.11") const container = await new MariaDbContainer("mariadb:10.11")
.withStartupTimeout(90000) .withStartupTimeout(90000)
.start(); .start();
const connectionString = `mysql://${container.getUsername()}:${container.getUserPassword()}@${container.getHost()}:${container.getPort()}/${container.getDatabase()}`;
return {
container,
connectionString
};
} }
describe( describe(
@ -23,11 +30,11 @@ describe(
}, },
() => { () => {
test("check() sets status to UP when MariaDB server is reachable", async () => { test("check() sets status to UP when MariaDB server is reachable", async () => {
const mariadbContainer = await createAndStartMariaDBContainer(); const { container, connectionString } = await createAndStartMariaDBContainer();
const mysqlMonitor = new MysqlMonitorType(); const mysqlMonitor = new MysqlMonitorType();
const monitor = { const monitor = {
databaseConnectionString: `mysql://${mariadbContainer.getUsername()}:${mariadbContainer.getUserPassword()}@${mariadbContainer.getHost()}:${mariadbContainer.getPort()}/${mariadbContainer.getDatabase()}`, databaseConnectionString: connectionString,
conditions: "[]", conditions: "[]",
}; };
@ -44,7 +51,7 @@ describe(
`Expected status ${UP} but got ${heartbeat.status}` `Expected status ${UP} but got ${heartbeat.status}`
); );
} finally { } finally {
await mariadbContainer.stop(); await container.stop();
} }
}); });
@ -79,11 +86,11 @@ describe(
}); });
test("check() sets status to UP when custom query result meets condition", async () => { test("check() sets status to UP when custom query result meets condition", async () => {
const mariadbContainer = await createAndStartMariaDBContainer(); const { container, connectionString } = await createAndStartMariaDBContainer();
const mysqlMonitor = new MysqlMonitorType(); const mysqlMonitor = new MysqlMonitorType();
const monitor = { const monitor = {
databaseConnectionString: `mysql://${mariadbContainer.getUsername()}:${mariadbContainer.getUserPassword()}@${mariadbContainer.getHost()}:${mariadbContainer.getPort()}/${mariadbContainer.getDatabase()}`, databaseConnectionString: connectionString,
databaseQuery: "SELECT 42 AS value", databaseQuery: "SELECT 42 AS value",
conditions: JSON.stringify([ conditions: JSON.stringify([
{ {
@ -109,16 +116,16 @@ describe(
`Expected status ${UP} but got ${heartbeat.status}` `Expected status ${UP} but got ${heartbeat.status}`
); );
} finally { } finally {
await mariadbContainer.stop(); await container.stop();
} }
}); });
test("check() rejects when custom query result does not meet condition", async () => { test("check() rejects when custom query result does not meet condition", async () => {
const mariadbContainer = await createAndStartMariaDBContainer(); const { container, connectionString } = await createAndStartMariaDBContainer();
const mysqlMonitor = new MysqlMonitorType(); const mysqlMonitor = new MysqlMonitorType();
const monitor = { const monitor = {
databaseConnectionString: `mysql://${mariadbContainer.getUsername()}:${mariadbContainer.getUserPassword()}@${mariadbContainer.getHost()}:${mariadbContainer.getPort()}/${mariadbContainer.getDatabase()}`, databaseConnectionString: connectionString,
databaseQuery: "SELECT 99 AS value", databaseQuery: "SELECT 99 AS value",
conditions: JSON.stringify([ conditions: JSON.stringify([
{ {
@ -149,7 +156,7 @@ describe(
`Expected status should not be ${heartbeat.status}` `Expected status should not be ${heartbeat.status}`
); );
} finally { } finally {
await mariadbContainer.stop(); await container.stop();
} }
}); });
} }