mirror of
https://github.com/louislam/uptime-kuma.git
synced 2026-04-18 12:09:43 +00:00
feat: add OracleDB monitor (#7156)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
46
package-lock.json
generated
46
package-lock.json
generated
@@ -66,6 +66,7 @@
|
||||
"nostr-tools": "~2.20.0",
|
||||
"notp": "~2.0.3",
|
||||
"openid-client": "~5.7.1",
|
||||
"oracledb": "~6.10.0",
|
||||
"password-hash": "~1.2.2",
|
||||
"pg": "~8.11.6",
|
||||
"pg-connection-string": "~2.6.4",
|
||||
@@ -104,6 +105,7 @@
|
||||
"@testcontainers/mariadb": "^10.28.0",
|
||||
"@testcontainers/mssqlserver": "^10.28.0",
|
||||
"@testcontainers/mysql": "^11.12.0",
|
||||
"@testcontainers/oraclefree": "^11.13.0",
|
||||
"@testcontainers/postgresql": "^11.12.0",
|
||||
"@testcontainers/rabbitmq": "^10.28.0",
|
||||
"@types/bootstrap": "~5.1.13",
|
||||
@@ -4133,6 +4135,16 @@
|
||||
"testcontainers": "^11.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@testcontainers/oraclefree": {
|
||||
"version": "11.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@testcontainers/oraclefree/-/oraclefree-11.13.0.tgz",
|
||||
"integrity": "sha512-qYy7Q9L5XOM++4aCjcJnmxvRIXaAkyR0zOL0Sa6nkI2YfTeLgZ+GUFaLht4Tox3COuCEw5po8DJWqYcKmmgtjw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"testcontainers": "^11.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@testcontainers/postgresql": {
|
||||
"version": "11.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@testcontainers/postgresql/-/postgresql-11.12.0.tgz",
|
||||
@@ -7670,9 +7682,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/docker-compose": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-1.3.1.tgz",
|
||||
"integrity": "sha512-rF0wH69G3CCcmkN9J1RVMQBaKe8o77LT/3XmqcLIltWWVxcWAzp2TnO7wS3n/umZHN3/EVrlT3exSBMal+Ou1w==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-1.3.2.tgz",
|
||||
"integrity": "sha512-FO/Jemn08gf9o9E6qtqOPQpyauwf2rQAzfpoUlMyqNpdaVb0ImR/wXKoutLZKp1tks58F8Z8iR7va7H1ne09cw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -12731,6 +12743,16 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/oracledb": {
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/oracledb/-/oracledb-6.10.0.tgz",
|
||||
"integrity": "sha512-kGUumXmrEWbSpBuKJyb9Ip3rXcNgKK6grunI3/cLPzrRvboZ6ZoLi9JQ+z6M/RIG924tY8BLflihL4CKKQAYMA==",
|
||||
"hasInstallScript": true,
|
||||
"license": "(Apache-2.0 OR UPL-1.0)",
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/own-keys": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
|
||||
@@ -16139,9 +16161,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/testcontainers": {
|
||||
"version": "11.12.0",
|
||||
"resolved": "https://registry.npmjs.org/testcontainers/-/testcontainers-11.12.0.tgz",
|
||||
"integrity": "sha512-VWtH+UQejVYYvb53ohEZRbx2naxyDvwO9lQ6A0VgmVE2Oh8r9EF09I+BfmrXpd9N9ntpzhao9di2yNwibSz5KA==",
|
||||
"version": "11.13.0",
|
||||
"resolved": "https://registry.npmjs.org/testcontainers/-/testcontainers-11.13.0.tgz",
|
||||
"integrity": "sha512-fzTvgOtd6U/esOzgmDatJh79OSK0tU6vjDOJ3B6ICrrJf0dqCWtFdpOr6f/g/KixMxKDTDbszmZYjSORJXsVCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -16151,21 +16173,21 @@
|
||||
"async-lock": "^1.4.1",
|
||||
"byline": "^5.0.0",
|
||||
"debug": "^4.4.3",
|
||||
"docker-compose": "^1.3.1",
|
||||
"docker-compose": "^1.3.2",
|
||||
"dockerode": "^4.0.9",
|
||||
"get-port": "^7.1.0",
|
||||
"proper-lockfile": "^4.1.2",
|
||||
"properties-reader": "^3.0.1",
|
||||
"ssh-remote-port-forward": "^1.0.4",
|
||||
"tar-fs": "^3.1.1",
|
||||
"tar-fs": "^3.1.2",
|
||||
"tmp": "^0.2.5",
|
||||
"undici": "^7.22.0"
|
||||
"undici": "^7.24.3"
|
||||
}
|
||||
},
|
||||
"node_modules/testcontainers/node_modules/undici": {
|
||||
"version": "7.22.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz",
|
||||
"integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==",
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-7.24.4.tgz",
|
||||
"integrity": "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
||||
@@ -126,6 +126,7 @@
|
||||
"nostr-tools": "~2.20.0",
|
||||
"notp": "~2.0.3",
|
||||
"openid-client": "~5.7.1",
|
||||
"oracledb": "~6.10.0",
|
||||
"password-hash": "~1.2.2",
|
||||
"pg": "~8.11.6",
|
||||
"pg-connection-string": "~2.6.4",
|
||||
@@ -164,6 +165,7 @@
|
||||
"@testcontainers/mariadb": "^10.28.0",
|
||||
"@testcontainers/mssqlserver": "^10.28.0",
|
||||
"@testcontainers/mysql": "^11.12.0",
|
||||
"@testcontainers/oraclefree": "^11.13.0",
|
||||
"@testcontainers/postgresql": "^11.12.0",
|
||||
"@testcontainers/rabbitmq": "^10.28.0",
|
||||
"@types/bootstrap": "~5.1.13",
|
||||
|
||||
155
server/monitor-types/oracledb.js
Normal file
155
server/monitor-types/oracledb.js
Normal file
@@ -0,0 +1,155 @@
|
||||
const { MonitorType } = require("./monitor-type");
|
||||
const { log, UP } = require("../../src/util");
|
||||
const dayjs = require("dayjs");
|
||||
const oracledb = require("oracledb");
|
||||
const { ConditionVariable } = require("../monitor-conditions/variables");
|
||||
const { defaultStringOperators } = require("../monitor-conditions/operators");
|
||||
const { ConditionExpressionGroup } = require("../monitor-conditions/expression");
|
||||
const { evaluateExpressionGroup } = require("../monitor-conditions/evaluator");
|
||||
|
||||
class OracleDbMonitorType extends MonitorType {
|
||||
name = "oracledb";
|
||||
|
||||
supportsConditions = true;
|
||||
conditionVariables = [new ConditionVariable("result", defaultStringOperators)];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async check(monitor, heartbeat, _server) {
|
||||
let query = monitor.databaseQuery;
|
||||
if (!query || (typeof query === "string" && query.trim() === "")) {
|
||||
query = "SELECT 1 FROM DUAL";
|
||||
}
|
||||
|
||||
const conditions = monitor.conditions ? ConditionExpressionGroup.fromMonitor(monitor) : null;
|
||||
const hasConditions = conditions && conditions.children && conditions.children.length > 0;
|
||||
|
||||
const startTime = dayjs().valueOf();
|
||||
try {
|
||||
if (hasConditions) {
|
||||
const result = await this.oracledbQuerySingleValue(
|
||||
monitor.databaseConnectionString,
|
||||
query,
|
||||
monitor.basic_auth_user,
|
||||
monitor.basic_auth_pass
|
||||
);
|
||||
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.status = UP;
|
||||
heartbeat.msg = "Query did meet specified conditions";
|
||||
} else {
|
||||
const result = await this.oracledbQuery(
|
||||
monitor.databaseConnectionString,
|
||||
query,
|
||||
monitor.basic_auth_user,
|
||||
monitor.basic_auth_pass
|
||||
);
|
||||
heartbeat.ping = dayjs().valueOf() - startTime;
|
||||
heartbeat.status = UP;
|
||||
heartbeat.msg = result;
|
||||
}
|
||||
} catch (error) {
|
||||
heartbeat.ping = dayjs().valueOf() - startTime;
|
||||
if (error.message.includes("did not meet the specified conditions")) {
|
||||
throw error;
|
||||
}
|
||||
throw new Error(`Database connection/query failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a query on Oracle Database.
|
||||
* @param {string} connectionString The Oracle DB connection string
|
||||
* @param {string} query The query to execute
|
||||
* @param {string} username Oracle DB username
|
||||
* @param {string} password Oracle DB password
|
||||
* @returns {Promise<string>} Row count or execution message
|
||||
*/
|
||||
async oracledbQuery(connectionString, query, username, password) {
|
||||
let connection;
|
||||
try {
|
||||
connection = await oracledb.getConnection({
|
||||
connectString: connectionString.trim(),
|
||||
user: username.trim(),
|
||||
password: password.trim(),
|
||||
});
|
||||
const result = await connection.execute(query, [], {
|
||||
outFormat: oracledb.OUT_FORMAT_OBJECT,
|
||||
});
|
||||
|
||||
if (Array.isArray(result.rows)) {
|
||||
return `Rows: ${result.rows.length}`;
|
||||
}
|
||||
|
||||
if (typeof result.rowsAffected === "number") {
|
||||
return `Rows affected: ${result.rowsAffected}`;
|
||||
}
|
||||
|
||||
return "Query executed successfully";
|
||||
} catch (error) {
|
||||
log.debug(this.name, "Error caught in the query execution.", error.message);
|
||||
throw error;
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a query on Oracle Database expecting a single value result.
|
||||
* @param {string} connectionString The Oracle DB connection string
|
||||
* @param {string} query The query to execute
|
||||
* @param {string} username Oracle DB username
|
||||
* @param {string} password Oracle DB password
|
||||
* @returns {Promise<any>} Single value from the first column of the first row
|
||||
*/
|
||||
async oracledbQuerySingleValue(connectionString, query, username, password) {
|
||||
let connection;
|
||||
try {
|
||||
connection = await oracledb.getConnection({
|
||||
connectString: connectionString,
|
||||
user: username,
|
||||
password: password,
|
||||
});
|
||||
const result = await connection.execute(query, [], {
|
||||
outFormat: oracledb.OUT_FORMAT_OBJECT,
|
||||
});
|
||||
|
||||
if (!result.rows || result.rows.length === 0) {
|
||||
throw new Error("Query returned no results");
|
||||
}
|
||||
|
||||
if (result.rows.length > 1) {
|
||||
throw new Error("Multiple values were found, expected only one value");
|
||||
}
|
||||
|
||||
const firstRow = result.rows[0];
|
||||
const columnNames = Object.keys(firstRow);
|
||||
|
||||
if (columnNames.length > 1) {
|
||||
throw new Error("Multiple columns were found, expected only one value");
|
||||
}
|
||||
|
||||
return firstRow[columnNames[0]];
|
||||
} catch (error) {
|
||||
log.debug(this.name, "Error caught in the query execution.", error.message);
|
||||
throw error;
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
OracleDbMonitorType,
|
||||
};
|
||||
@@ -131,6 +131,7 @@ class UptimeKumaServer {
|
||||
UptimeKumaServer.monitorTypeList["system-service"] = new SystemServiceMonitorType();
|
||||
UptimeKumaServer.monitorTypeList["sqlserver"] = new MssqlMonitorType();
|
||||
UptimeKumaServer.monitorTypeList["mysql"] = new MysqlMonitorType();
|
||||
UptimeKumaServer.monitorTypeList["oracledb"] = new OracleDbMonitorType();
|
||||
|
||||
// Allow all CORS origins (polling) in development
|
||||
let cors = undefined;
|
||||
@@ -582,4 +583,5 @@ const { RedisMonitorType } = require("./monitor-types/redis");
|
||||
const { SystemServiceMonitorType } = require("./monitor-types/system-service");
|
||||
const { MssqlMonitorType } = require("./monitor-types/mssql");
|
||||
const { MysqlMonitorType } = require("./monitor-types/mysql");
|
||||
const { OracleDbMonitorType } = require("./monitor-types/oracledb");
|
||||
const Monitor = require("./model/monitor");
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"setupDatabaseSQLite": "A simple database file, recommended for small-scale deployments. Prior to v2.0.0, Uptime Kuma used SQLite as the default database.",
|
||||
"settingUpDatabaseMSG": "Setting up the database. It may take a while, please be patient.",
|
||||
"dbName": "Database Name",
|
||||
"oracledbConnectionString": "Oracle Database: {connectionString}",
|
||||
"enableSSL": "Enable SSL/TLS",
|
||||
"mariadbUseSSLHelptext": "Enable to use a encrypted connection to your database. Required for most cloud databases.",
|
||||
"mariadbCaCertificateLabel": "CA Certificate",
|
||||
|
||||
@@ -86,6 +86,13 @@
|
||||
MQTT: {{ monitor.hostname }}:{{ monitor.port }}/{{ monitor.mqttTopic }}
|
||||
</span>
|
||||
<span v-if="monitor.type === 'mysql'">{{ filterPassword(monitor.databaseConnectionString) }}</span>
|
||||
<span v-if="monitor.type === 'oracledb'">
|
||||
{{
|
||||
$t("oracledbConnectionString", {
|
||||
connectionString: filterPassword(monitor.databaseConnectionString),
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
<span v-if="monitor.type === 'postgres'">{{ filterPassword(monitor.databaseConnectionString) }}</span>
|
||||
<span v-if="monitor.type === 'push'">
|
||||
Push:
|
||||
|
||||
@@ -98,6 +98,7 @@
|
||||
<option value="sqlserver">Microsoft SQL Server</option>
|
||||
<option value="mongodb">MongoDB</option>
|
||||
<option value="mysql">MySQL/MariaDB</option>
|
||||
<option value="oracledb">Oracle Database</option>
|
||||
<option value="postgres">PostgreSQL</option>
|
||||
<option value="radius">Radius</option>
|
||||
<option value="redis">Redis</option>
|
||||
@@ -1161,12 +1162,13 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- SQL Server / PostgreSQL / MySQL / Redis / MongoDB -->
|
||||
<!-- SQL Server / PostgreSQL / MySQL / Oracle / Redis / MongoDB -->
|
||||
<template
|
||||
v-if="
|
||||
monitor.type === 'sqlserver' ||
|
||||
monitor.type === 'postgres' ||
|
||||
monitor.type === 'mysql' ||
|
||||
monitor.type === 'oracledb' ||
|
||||
monitor.type === 'redis' ||
|
||||
monitor.type === 'mongodb'
|
||||
"
|
||||
@@ -1185,6 +1187,29 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="monitor.type === 'oracledb'">
|
||||
<div class="my-3">
|
||||
<label for="oracledb-user" class="form-label">{{ $t("Username") }}</label>
|
||||
<input
|
||||
id="oracledb-user"
|
||||
v-model="monitor.basic_auth_user"
|
||||
type="text"
|
||||
class="form-control"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="my-3">
|
||||
<label for="oracledb-pass" class="form-label">{{ $t("Password") }}</label>
|
||||
<HiddenInput
|
||||
id="oracledb-pass"
|
||||
v-model="monitor.basic_auth_pass"
|
||||
autocomplete="new-password"
|
||||
:required="true"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="monitor.type === 'system-service'">
|
||||
<div class="my-3">
|
||||
<label for="system-service-name" class="form-label">{{ $t("Service Name") }}</label>
|
||||
@@ -1276,12 +1301,13 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- SQL Server / PostgreSQL / MySQL -->
|
||||
<!-- SQL Server / PostgreSQL / MySQL / Oracle -->
|
||||
<template
|
||||
v-if="
|
||||
monitor.type === 'sqlserver' ||
|
||||
monitor.type === 'postgres' ||
|
||||
monitor.type === 'mysql'
|
||||
monitor.type === 'mysql' ||
|
||||
monitor.type === 'oracledb'
|
||||
"
|
||||
>
|
||||
<div class="my-3">
|
||||
@@ -1290,7 +1316,11 @@
|
||||
id="sqlQuery"
|
||||
v-model="monitor.databaseQuery"
|
||||
class="form-control"
|
||||
:placeholder="$t('Example:', ['SELECT 1'])"
|
||||
:placeholder="
|
||||
$t('Example:', [
|
||||
monitor.type === 'oracledb' ? 'SELECT 1 FROM DUAL' : 'SELECT 1',
|
||||
])
|
||||
"
|
||||
></textarea>
|
||||
</div>
|
||||
</template>
|
||||
@@ -2880,6 +2910,8 @@ const monitorDefaults = {
|
||||
docker_container: "",
|
||||
docker_host: null,
|
||||
proxyId: null,
|
||||
basic_auth_user: "",
|
||||
basic_auth_pass: "",
|
||||
mqttUsername: "",
|
||||
mqttPassword: "",
|
||||
mqttTopic: "",
|
||||
@@ -2944,6 +2976,7 @@ export default {
|
||||
"Server=<hostname>,<port>;Database=<your database>;User Id=<your user id>;Password=<your password>;Encrypt=<true/false>;TrustServerCertificate=<Yes/No>;Connection Timeout=<int>",
|
||||
postgres: "postgres://username:password@host:port/database",
|
||||
mysql: "mysql://username:password@host:port/database",
|
||||
oracledb: "localhost:1521/FREEPDB1",
|
||||
redis: "redis://user:password@host:port",
|
||||
mongodb: "mongodb://username:password@host:port/database",
|
||||
},
|
||||
@@ -3842,6 +3875,20 @@ message HealthCheckResponse {
|
||||
this.monitor.url = this.monitor.url.trim();
|
||||
}
|
||||
|
||||
if (this.monitor.databaseConnectionString) {
|
||||
this.monitor.databaseConnectionString = this.monitor.databaseConnectionString.trim();
|
||||
}
|
||||
|
||||
if (this.monitor.type === "oracledb") {
|
||||
if (this.monitor.basic_auth_user) {
|
||||
this.monitor.basic_auth_user = this.monitor.basic_auth_user.trim();
|
||||
}
|
||||
|
||||
if (this.monitor.basic_auth_pass) {
|
||||
this.monitor.basic_auth_pass = this.monitor.basic_auth_pass.trim();
|
||||
}
|
||||
}
|
||||
|
||||
let createdNewParent = false;
|
||||
|
||||
if (this.draftGroupName && this.monitor.parent === -1) {
|
||||
|
||||
232
test/backend-test/monitors/test-oracledb.js
Normal file
232
test/backend-test/monitors/test-oracledb.js
Normal file
@@ -0,0 +1,232 @@
|
||||
const { after, before, describe, test } = require("node:test");
|
||||
const assert = require("node:assert");
|
||||
const { OracleDbContainer } = require("@testcontainers/oraclefree");
|
||||
const { OracleDbMonitorType } = require("../../../server/monitor-types/oracledb");
|
||||
const { UP, PENDING } = require("../../../src/util");
|
||||
|
||||
const ORACLE_IMAGE = "gvenzl/oracle-free:23-slim-faststart";
|
||||
const APP_USER = "uptimekuma";
|
||||
const APP_USER_PASSWORD = "Oracle123";
|
||||
|
||||
/**
|
||||
* Create a monitor payload for Oracle monitor tests.
|
||||
* @param {object} overrides Partial monitor overrides
|
||||
* @returns {object} Monitor payload
|
||||
*/
|
||||
function createMonitor(overrides = {}) {
|
||||
return {
|
||||
basic_auth_user: APP_USER,
|
||||
basic_auth_pass: APP_USER_PASSWORD,
|
||||
conditions: "[]",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a baseline heartbeat object for Oracle monitor tests.
|
||||
* @returns {{msg: string, status: string}} Heartbeat payload
|
||||
*/
|
||||
function createHeartbeat() {
|
||||
return {
|
||||
msg: "",
|
||||
status: PENDING,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create and start an Oracle container.
|
||||
* @returns {Promise<{container: import("@testcontainers/oraclefree").StartedOracleDbContainer, connectString: string}>}
|
||||
*/
|
||||
async function createAndStartOracleContainer() {
|
||||
const container = await new OracleDbContainer(ORACLE_IMAGE)
|
||||
.withUsername(APP_USER)
|
||||
.withPassword(APP_USER_PASSWORD)
|
||||
.start();
|
||||
|
||||
return {
|
||||
container,
|
||||
connectString: container.getUrl(),
|
||||
};
|
||||
}
|
||||
|
||||
describe(
|
||||
"Oracle Database Monitor",
|
||||
{
|
||||
skip: !!process.env.CI && (process.platform !== "linux" || process.arch !== "x64"),
|
||||
},
|
||||
() => {
|
||||
/** @type {import("@testcontainers/oraclefree").StartedOracleDbContainer | undefined} */
|
||||
let container;
|
||||
/** @type {string | undefined} */
|
||||
let connectString;
|
||||
|
||||
before(async () => {
|
||||
const oracle = await createAndStartOracleContainer();
|
||||
container = oracle.container;
|
||||
connectString = oracle.connectString;
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
if (container) {
|
||||
await container.stop();
|
||||
}
|
||||
});
|
||||
|
||||
test("check() sets status to UP when Oracle server is reachable", async () => {
|
||||
const oracleMonitor = new OracleDbMonitorType();
|
||||
const monitor = createMonitor({
|
||||
databaseConnectionString: connectString,
|
||||
});
|
||||
const heartbeat = createHeartbeat();
|
||||
|
||||
await oracleMonitor.check(monitor, heartbeat, {});
|
||||
assert.strictEqual(heartbeat.status, UP, `Expected status ${UP} but got ${heartbeat.status}`);
|
||||
});
|
||||
|
||||
test("check() rejects when Oracle server is not reachable", async () => {
|
||||
const oracleMonitor = new OracleDbMonitorType();
|
||||
const monitor = createMonitor({
|
||||
databaseConnectionString: "localhost:1/FREEPDB1",
|
||||
});
|
||||
const heartbeat = createHeartbeat();
|
||||
|
||||
await assert.rejects(oracleMonitor.check(monitor, heartbeat, {}), (err) => {
|
||||
assert.ok(
|
||||
err.message.includes("Database connection/query failed"),
|
||||
`Expected error message to include "Database connection/query failed" but got: ${err.message}`
|
||||
);
|
||||
return true;
|
||||
});
|
||||
assert.notStrictEqual(heartbeat.status, UP, `Expected status should not be ${UP}`);
|
||||
});
|
||||
|
||||
test("check() sets status to UP when custom query returns single value", async () => {
|
||||
const oracleMonitor = new OracleDbMonitorType();
|
||||
const monitor = createMonitor({
|
||||
databaseConnectionString: connectString,
|
||||
databaseQuery: "SELECT 42 FROM DUAL",
|
||||
});
|
||||
const heartbeat = createHeartbeat();
|
||||
|
||||
await oracleMonitor.check(monitor, heartbeat, {});
|
||||
assert.strictEqual(heartbeat.status, UP, `Expected status ${UP} but got ${heartbeat.status}`);
|
||||
});
|
||||
|
||||
test("check() sets status to UP when custom query result meets condition", async () => {
|
||||
const oracleMonitor = new OracleDbMonitorType();
|
||||
const monitor = createMonitor({
|
||||
databaseConnectionString: connectString,
|
||||
databaseQuery: "SELECT 42 AS value FROM DUAL",
|
||||
conditions: JSON.stringify([
|
||||
{
|
||||
type: "expression",
|
||||
andOr: "and",
|
||||
variable: "result",
|
||||
operator: "equals",
|
||||
value: "42",
|
||||
},
|
||||
]),
|
||||
});
|
||||
const heartbeat = createHeartbeat();
|
||||
|
||||
await oracleMonitor.check(monitor, heartbeat, {});
|
||||
assert.strictEqual(heartbeat.status, UP, `Expected status ${UP} but got ${heartbeat.status}`);
|
||||
});
|
||||
|
||||
test("check() rejects when custom query result does not meet condition", async () => {
|
||||
const oracleMonitor = new OracleDbMonitorType();
|
||||
const monitor = createMonitor({
|
||||
databaseConnectionString: connectString,
|
||||
databaseQuery: "SELECT 99 AS value FROM DUAL",
|
||||
conditions: JSON.stringify([
|
||||
{
|
||||
type: "expression",
|
||||
andOr: "and",
|
||||
variable: "result",
|
||||
operator: "equals",
|
||||
value: "42",
|
||||
},
|
||||
]),
|
||||
});
|
||||
const heartbeat = createHeartbeat();
|
||||
|
||||
await assert.rejects(
|
||||
oracleMonitor.check(monitor, heartbeat, {}),
|
||||
new Error("Query result did not meet the specified conditions (99)")
|
||||
);
|
||||
assert.strictEqual(heartbeat.status, PENDING, `Expected status should not be ${heartbeat.status}`);
|
||||
});
|
||||
|
||||
test("check() rejects when query returns no results with conditions", async () => {
|
||||
const oracleMonitor = new OracleDbMonitorType();
|
||||
const monitor = createMonitor({
|
||||
databaseConnectionString: connectString,
|
||||
databaseQuery: "SELECT 1 AS value FROM DUAL WHERE 1 = 0",
|
||||
conditions: JSON.stringify([
|
||||
{
|
||||
type: "expression",
|
||||
andOr: "and",
|
||||
variable: "result",
|
||||
operator: "equals",
|
||||
value: "1",
|
||||
},
|
||||
]),
|
||||
});
|
||||
const heartbeat = createHeartbeat();
|
||||
|
||||
await assert.rejects(
|
||||
oracleMonitor.check(monitor, heartbeat, {}),
|
||||
new Error("Database connection/query failed: Query returned no results")
|
||||
);
|
||||
assert.strictEqual(heartbeat.status, PENDING, `Expected status should not be ${heartbeat.status}`);
|
||||
});
|
||||
|
||||
test("check() rejects when query returns multiple rows with conditions", async () => {
|
||||
const oracleMonitor = new OracleDbMonitorType();
|
||||
const monitor = createMonitor({
|
||||
databaseConnectionString: connectString,
|
||||
databaseQuery: "SELECT 1 AS value FROM DUAL UNION ALL SELECT 2 AS value FROM DUAL",
|
||||
conditions: JSON.stringify([
|
||||
{
|
||||
type: "expression",
|
||||
andOr: "and",
|
||||
variable: "result",
|
||||
operator: "equals",
|
||||
value: "1",
|
||||
},
|
||||
]),
|
||||
});
|
||||
const heartbeat = createHeartbeat();
|
||||
|
||||
await assert.rejects(
|
||||
oracleMonitor.check(monitor, heartbeat, {}),
|
||||
new Error("Database connection/query failed: Multiple values were found, expected only one value")
|
||||
);
|
||||
assert.strictEqual(heartbeat.status, PENDING, `Expected status should not be ${heartbeat.status}`);
|
||||
});
|
||||
|
||||
test("check() rejects when query returns multiple columns with conditions", async () => {
|
||||
const oracleMonitor = new OracleDbMonitorType();
|
||||
const monitor = createMonitor({
|
||||
databaseConnectionString: connectString,
|
||||
databaseQuery: "SELECT 1 AS col1, 2 AS col2 FROM DUAL",
|
||||
conditions: JSON.stringify([
|
||||
{
|
||||
type: "expression",
|
||||
andOr: "and",
|
||||
variable: "result",
|
||||
operator: "equals",
|
||||
value: "1",
|
||||
},
|
||||
]),
|
||||
});
|
||||
const heartbeat = createHeartbeat();
|
||||
|
||||
await assert.rejects(
|
||||
oracleMonitor.check(monitor, heartbeat, {}),
|
||||
new Error("Database connection/query failed: Multiple columns were found, expected only one value")
|
||||
);
|
||||
assert.strictEqual(heartbeat.status, PENDING, `Expected status should not be ${heartbeat.status}`);
|
||||
});
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user