mirror of
https://github.com/louislam/uptime-kuma.git
synced 2026-01-31 11:03:11 +08:00
Merge branch 'master' into wait-for-analaytics-e2e
This commit is contained in:
18
.github/workflows/auto-test.yml
vendored
18
.github/workflows/auto-test.yml
vendored
@@ -22,6 +22,7 @@ jobs:
|
||||
contents: read
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-22.04, windows-latest, ubuntu-22.04-arm]
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
@@ -41,13 +42,13 @@ jobs:
|
||||
id: node-modules-cache
|
||||
with:
|
||||
path: node_modules
|
||||
key: node-modules-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
|
||||
key: node-modules-${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }}
|
||||
|
||||
- name: Use Node.js ${{ matrix.node }}
|
||||
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
- run: npm install
|
||||
- run: npm clean-install --no-fund
|
||||
|
||||
- name: Rebuild native modules for ARM64
|
||||
if: matrix.os == 'ubuntu-22.04-arm'
|
||||
@@ -65,6 +66,7 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node: [ 20, 22 ]
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
@@ -86,8 +88,8 @@ jobs:
|
||||
docker run --rm --platform linux/arm/v7 \
|
||||
-v $PWD:/workspace \
|
||||
-w /workspace \
|
||||
arm32v7/node:${{ matrix.node }}-slim \
|
||||
bash -c "npm install --production"
|
||||
arm32v7/node:${{ matrix.node }} \
|
||||
npm clean-install --no-fund --production
|
||||
|
||||
check-linters:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -104,13 +106,13 @@ jobs:
|
||||
id: node-modules-cache
|
||||
with:
|
||||
path: node_modules
|
||||
key: node-modules-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
|
||||
key: node-modules-${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }}
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
|
||||
with:
|
||||
node-version: 20
|
||||
- run: npm install
|
||||
- run: npm clean-install --no-fund
|
||||
- run: npm run lint:prod
|
||||
|
||||
e2e-test:
|
||||
@@ -129,13 +131,13 @@ jobs:
|
||||
id: node-modules-cache
|
||||
with:
|
||||
path: node_modules
|
||||
key: node-modules-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
|
||||
key: node-modules-${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
|
||||
with:
|
||||
node-version: 22
|
||||
- run: npm install
|
||||
- run: npm clean-install --no-fund
|
||||
|
||||
- name: Rebuild native modules for ARM64
|
||||
run: npm rebuild @louislam/sqlite3
|
||||
|
||||
@@ -2,10 +2,22 @@ const { MonitorType } = require("./monitor-type");
|
||||
const { log, UP } = require("../../src/util");
|
||||
const mqtt = require("mqtt");
|
||||
const jsonata = require("jsonata");
|
||||
const { ConditionVariable } = require("../monitor-conditions/variables");
|
||||
const { defaultStringOperators, defaultNumberOperators } = require("../monitor-conditions/operators");
|
||||
const { ConditionExpressionGroup } = require("../monitor-conditions/expression");
|
||||
const { evaluateExpressionGroup } = require("../monitor-conditions/evaluator");
|
||||
|
||||
class MqttMonitorType extends MonitorType {
|
||||
name = "mqtt";
|
||||
|
||||
supportsConditions = true;
|
||||
|
||||
conditionVariables = [
|
||||
new ConditionVariable("topic", defaultStringOperators),
|
||||
new ConditionVariable("message", defaultStringOperators),
|
||||
new ConditionVariable("json_value", defaultStringOperators.concat(defaultNumberOperators)),
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@@ -19,32 +31,98 @@ class MqttMonitorType extends MonitorType {
|
||||
});
|
||||
|
||||
if (monitor.mqttCheckType == null || monitor.mqttCheckType === "") {
|
||||
// use old default
|
||||
monitor.mqttCheckType = "keyword";
|
||||
}
|
||||
|
||||
if (monitor.mqttCheckType === "keyword") {
|
||||
if (receivedMessage != null && receivedMessage.includes(monitor.mqttSuccessMessage)) {
|
||||
heartbeat.msg = `Topic: ${messageTopic}; Message: ${receivedMessage}`;
|
||||
heartbeat.status = UP;
|
||||
} else {
|
||||
throw Error(`Message Mismatch - Topic: ${monitor.mqttTopic}; Message: ${receivedMessage}`);
|
||||
}
|
||||
// Check if conditions are defined
|
||||
const conditions = monitor.conditions ? ConditionExpressionGroup.fromMonitor(monitor) : null;
|
||||
const hasConditions = conditions && conditions.children && conditions.children.length > 0;
|
||||
|
||||
if (hasConditions) {
|
||||
await this.checkConditions(monitor, heartbeat, messageTopic, receivedMessage, conditions);
|
||||
} else if (monitor.mqttCheckType === "keyword") {
|
||||
this.checkKeyword(monitor, heartbeat, messageTopic, receivedMessage);
|
||||
} else if (monitor.mqttCheckType === "json-query") {
|
||||
const parsedMessage = JSON.parse(receivedMessage);
|
||||
|
||||
let expression = jsonata(monitor.jsonPath);
|
||||
|
||||
let result = await expression.evaluate(parsedMessage);
|
||||
|
||||
if (result?.toString() === monitor.expectedValue) {
|
||||
heartbeat.msg = "Message received, expected value is found";
|
||||
heartbeat.status = UP;
|
||||
} else {
|
||||
throw new Error("Message received but value is not equal to expected value, value was: [" + result + "]");
|
||||
}
|
||||
await this.checkJsonQuery(monitor, heartbeat, receivedMessage);
|
||||
} else {
|
||||
throw Error("Unknown MQTT Check Type");
|
||||
throw new Error("Unknown MQTT Check Type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check using keyword matching
|
||||
* @param {object} monitor Monitor object
|
||||
* @param {object} heartbeat Heartbeat object
|
||||
* @param {string} messageTopic Received MQTT topic
|
||||
* @param {string} receivedMessage Received MQTT message
|
||||
* @returns {void}
|
||||
* @throws {Error} If keyword is not found in message
|
||||
*/
|
||||
checkKeyword(monitor, heartbeat, messageTopic, receivedMessage) {
|
||||
if (receivedMessage != null && receivedMessage.includes(monitor.mqttSuccessMessage)) {
|
||||
heartbeat.msg = `Topic: ${messageTopic}; Message: ${receivedMessage}`;
|
||||
heartbeat.status = UP;
|
||||
} else {
|
||||
throw new Error(`Message Mismatch - Topic: ${monitor.mqttTopic}; Message: ${receivedMessage}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check using JSONata query
|
||||
* @param {object} monitor Monitor object
|
||||
* @param {object} heartbeat Heartbeat object
|
||||
* @param {string} receivedMessage Received MQTT message
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async checkJsonQuery(monitor, heartbeat, receivedMessage) {
|
||||
const parsedMessage = JSON.parse(receivedMessage);
|
||||
const expression = jsonata(monitor.jsonPath);
|
||||
const result = await expression.evaluate(parsedMessage);
|
||||
|
||||
if (result?.toString() === monitor.expectedValue) {
|
||||
heartbeat.msg = "Message received, expected value is found";
|
||||
heartbeat.status = UP;
|
||||
} else {
|
||||
throw new Error("Message received but value is not equal to expected value, value was: [" + result + "]");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check using conditions system
|
||||
* @param {object} monitor Monitor object
|
||||
* @param {object} heartbeat Heartbeat object
|
||||
* @param {string} messageTopic Received MQTT topic
|
||||
* @param {string} receivedMessage Received MQTT message
|
||||
* @param {ConditionExpressionGroup} conditions Parsed conditions
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async checkConditions(monitor, heartbeat, messageTopic, receivedMessage, conditions) {
|
||||
let jsonValue = null;
|
||||
|
||||
// Parse JSON and extract value if jsonPath is defined
|
||||
if (monitor.jsonPath) {
|
||||
try {
|
||||
const parsedMessage = JSON.parse(receivedMessage);
|
||||
const expression = jsonata(monitor.jsonPath);
|
||||
jsonValue = await expression.evaluate(parsedMessage);
|
||||
} catch (e) {
|
||||
// JSON parsing failed, jsonValue remains null
|
||||
}
|
||||
}
|
||||
|
||||
const conditionData = {
|
||||
topic: messageTopic,
|
||||
message: receivedMessage,
|
||||
json_value: jsonValue?.toString() ?? "",
|
||||
};
|
||||
|
||||
const conditionsResult = evaluateExpressionGroup(conditions, conditionData);
|
||||
|
||||
if (conditionsResult) {
|
||||
heartbeat.msg = `Topic: ${messageTopic}; Message: ${receivedMessage}`;
|
||||
heartbeat.status = UP;
|
||||
} else {
|
||||
throw new Error(`Conditions not met - Topic: ${messageTopic}; Message: ${receivedMessage}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<h5 class="modal-title">
|
||||
{{ $t("Add API Key") }}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="$t('Close')" />
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Name -->
|
||||
@@ -67,7 +67,7 @@
|
||||
<h5 class="modal-title">
|
||||
{{ $t("Key Added") }}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="$t('Close')" />
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<h5 class="modal-title">
|
||||
{{ $t("Badge Generator", [monitor.name]) }}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="$t('Close')" />
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
<h5 id="exampleModalLabel" class="modal-title">
|
||||
{{ title || $t("Confirm") }}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="$t('Close')" />
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<slot />
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn" :class="btnStyle" data-bs-dismiss="modal" @click="yes">
|
||||
{{ yesText }}
|
||||
{{ yesText || $t("Yes") }}
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" @click="no">
|
||||
{{ noText }}
|
||||
{{ noText || $t("No") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -37,12 +37,12 @@ export default {
|
||||
/** Text to use as yes */
|
||||
yesText: {
|
||||
type: String,
|
||||
default: "Yes", // TODO: No idea what to translate this
|
||||
default: null,
|
||||
},
|
||||
/** Text to use as no */
|
||||
noText: {
|
||||
type: String,
|
||||
default: "No",
|
||||
default: null,
|
||||
},
|
||||
/** Title to show on modal. Defaults to translated version of "Config" */
|
||||
title: {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<h5 class="modal-title">
|
||||
{{ $t("New Group") }}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="$t('Close')" />
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form @submit.prevent="confirm">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<h5 id="exampleModalLabel" class="modal-title">
|
||||
{{ $t("Setup Docker Host") }}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="$t('Close')" />
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<h5 class="modal-title">
|
||||
{{ $t("Monitor Setting", [monitor.name]) }}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="$t('Close')" />
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="my-3 form-check">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<h5 id="exampleModalLabel" class="modal-title">
|
||||
{{ $t("Setup Notification") }}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="$t('Close')" />
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<h5 id="exampleModalLabel" class="modal-title">
|
||||
{{ $t("Setup Proxy") }}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="$t('Close')" />
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<h5 id="exampleModalLabel" class="modal-title">
|
||||
{{ $t("Add a Remote Browser") }}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="$t('Close')" />
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
<h5 class="modal-title">
|
||||
{{ $t("Browser Screenshot") }}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="$t('Close')" />
|
||||
</div>
|
||||
<div class="modal-body"></div>
|
||||
<img :src="imageURL" alt="screenshot of the website">
|
||||
<img :src="imageURL" :alt="$t('screenshot of the website')">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<h5 id="exampleModalLabel" class="modal-title">
|
||||
{{ $t("Edit Tag") }}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="$t('Close')" />
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<span v-if="twoFAStatus == true" class="badge bg-primary">{{ $t("Active") }}</span>
|
||||
<span v-if="twoFAStatus == false" class="badge bg-primary">{{ $t("Inactive") }}</span>
|
||||
</h5>
|
||||
<button :disabled="processing" type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" />
|
||||
<button :disabled="processing" type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="$t('Close')" />
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
|
||||
@@ -85,12 +85,12 @@ export default {
|
||||
|
||||
title() {
|
||||
if (this.type === "1y") {
|
||||
return `1${this.$t("-year")}`;
|
||||
return `1 ${this.$tc("year", 1)}`;
|
||||
}
|
||||
if (this.type === "720") {
|
||||
return `30${this.$t("-day")}`;
|
||||
return `30 ${this.$tc("day", 30)}`;
|
||||
}
|
||||
return `24${this.$t("-hour")}`;
|
||||
return `24 ${this.$tc("hour", 24)}`;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<div
|
||||
class="btn-group"
|
||||
role="group"
|
||||
aria-label="Basic checkbox toggle button group"
|
||||
:aria-label="$t('Basic checkbox toggle button group')"
|
||||
>
|
||||
<input
|
||||
id="btncheck1"
|
||||
@@ -69,7 +69,7 @@
|
||||
<div
|
||||
class="btn-group"
|
||||
role="group"
|
||||
aria-label="Basic checkbox toggle button group"
|
||||
:aria-label="$t('Basic checkbox toggle button group')"
|
||||
>
|
||||
<input
|
||||
id="btncheck4"
|
||||
|
||||
@@ -52,10 +52,8 @@
|
||||
"now": "now",
|
||||
"time ago": "{0} ago",
|
||||
"day": "day | days",
|
||||
"-day": "-day",
|
||||
"hour": "hour",
|
||||
"-hour": "-hour",
|
||||
"-year": "-year",
|
||||
"hour": "hour | hours",
|
||||
"year": "year | years",
|
||||
"Response": "Response",
|
||||
"Ping": "Ping",
|
||||
"Monitor Type": "Monitor Type",
|
||||
@@ -1121,6 +1119,8 @@
|
||||
"less than or equal to": "less than or equal to",
|
||||
"greater than or equal to": "greater than or equal to",
|
||||
"record": "record",
|
||||
"message": "message",
|
||||
"json_value": "JSON value",
|
||||
"Notification Channel": "Notification Channel",
|
||||
"Sound": "Sound",
|
||||
"Alphanumerical string and hyphens only": "Alphanumerical string and hyphens only",
|
||||
@@ -1246,6 +1246,9 @@
|
||||
"minimumIntervalWarning": "Intervals below 20 seconds may result in poor performance.",
|
||||
"lowIntervalWarning": "Are you sure want to set the interval value below 20 seconds? Performance may be degraded, particularly if there are a large number of monitors.",
|
||||
"imageResetConfirmation": "Image reset to default",
|
||||
"screenshot of the website": "Screenshot of the website",
|
||||
"Basic checkbox toggle button group": "Basic checkbox toggle button group",
|
||||
"Basic radio toggle button group": "Basic radio toggle button group",
|
||||
"mtls-auth-server-cert-label": "Cert",
|
||||
"mtls-auth-server-cert-placeholder": "Cert body",
|
||||
"mtls-auth-server-key-label": "Key",
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
>
|
||||
<h4 class="col-4 col-sm-12">{{ pingTitle(true) }}</h4>
|
||||
<p class="col-4 col-sm-12 mb-0 mb-sm-2">
|
||||
(24{{ $t("-hour") }})
|
||||
({{ 24 }} {{ $tc("hour", 24) }})
|
||||
</p>
|
||||
<span class="col-4 col-sm-12 num">
|
||||
<CountUp :value="avgPing" />
|
||||
@@ -250,7 +250,7 @@
|
||||
>
|
||||
<h4 class="col-4 col-sm-12">{{ $t("Uptime") }}</h4>
|
||||
<p class="col-4 col-sm-12 mb-0 mb-sm-2">
|
||||
(24{{ $t("-hour") }})
|
||||
({{ 24 }} {{ $tc("hour", 24) }})
|
||||
</p>
|
||||
<span class="col-4 col-sm-12 num">
|
||||
<Uptime :monitor="monitor" type="24" />
|
||||
@@ -263,7 +263,7 @@
|
||||
>
|
||||
<h4 class="col-4 col-sm-12">{{ $t("Uptime") }}</h4>
|
||||
<p class="col-4 col-sm-12 mb-0 mb-sm-2">
|
||||
(30{{ $t("-day") }})
|
||||
({{ 30 }} {{ $tc("day", 30) }})
|
||||
</p>
|
||||
<span class="col-4 col-sm-12 num">
|
||||
<Uptime :monitor="monitor" type="720" />
|
||||
@@ -276,7 +276,7 @@
|
||||
>
|
||||
<h4 class="col-4 col-sm-12">{{ $t("Uptime") }}</h4>
|
||||
<p class="col-4 col-sm-12 mb-0 mb-sm-2">
|
||||
(1{{ $t("-year") }})
|
||||
({{ 1 }} {{ $tc("year", 1) }})
|
||||
</p>
|
||||
<span class="col-4 col-sm-12 num">
|
||||
<Uptime :monitor="monitor" type="1y" />
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
{{ $t("setupDatabaseChooseDatabase") }}
|
||||
</p>
|
||||
|
||||
<div class="btn-group" role="group" aria-label="Basic radio toggle button group">
|
||||
<div class="btn-group" role="group" :aria-label="$t('Basic radio toggle button group')">
|
||||
<template v-if="info.isEnabledEmbeddedMariaDB">
|
||||
<input id="btnradio3" v-model="dbConfig.type" type="radio" class="btn-check" autocomplete="off" value="embedded-mariadb">
|
||||
|
||||
|
||||
@@ -12,9 +12,10 @@ const { UP, PENDING } = require("../../../src/util");
|
||||
* @param {string} receivedMessage what message is received from the mqtt channel
|
||||
* @param {string} monitorTopic which MQTT topic is monitored (wildcards are allowed)
|
||||
* @param {string} publishTopic to which MQTT topic the message is sent
|
||||
* @param {string|null} conditions JSON string of conditions or null
|
||||
* @returns {Promise<Heartbeat>} the heartbeat produced by the check
|
||||
*/
|
||||
async function testMqtt(mqttSuccessMessage, mqttCheckType, receivedMessage, monitorTopic = "test", publishTopic = "test") {
|
||||
async function testMqtt(mqttSuccessMessage, mqttCheckType, receivedMessage, monitorTopic = "test", publishTopic = "test", conditions = null) {
|
||||
const hiveMQContainer = await new HiveMQContainer().start();
|
||||
const connectionString = hiveMQContainer.getConnectionString();
|
||||
const mqttMonitorType = new MqttMonitorType();
|
||||
@@ -30,6 +31,7 @@ async function testMqtt(mqttSuccessMessage, mqttCheckType, receivedMessage, moni
|
||||
mqttSuccessMessage: mqttSuccessMessage, // for keywords
|
||||
expectedValue: mqttSuccessMessage, // for json-query
|
||||
mqttCheckType: mqttCheckType,
|
||||
conditions: conditions, // for conditions system
|
||||
};
|
||||
const heartbeat = {
|
||||
msg: "",
|
||||
@@ -157,4 +159,67 @@ describe("MqttMonitorType", {
|
||||
new Error("Message received but value is not equal to expected value, value was: [present]")
|
||||
);
|
||||
});
|
||||
|
||||
// Conditions system tests
|
||||
test("check() sets status to UP when message condition matches (contains)", async () => {
|
||||
const conditions = JSON.stringify([
|
||||
{
|
||||
type: "expression",
|
||||
variable: "message",
|
||||
operator: "contains",
|
||||
value: "KEYWORD"
|
||||
}
|
||||
]);
|
||||
const heartbeat = await testMqtt("", null, "-> KEYWORD <-", "test", "test", conditions);
|
||||
assert.strictEqual(heartbeat.status, UP);
|
||||
assert.strictEqual(heartbeat.msg, "Topic: test; Message: -> KEYWORD <-");
|
||||
});
|
||||
|
||||
test("check() sets status to UP when topic condition matches (equals)", async () => {
|
||||
const conditions = JSON.stringify([
|
||||
{
|
||||
type: "expression",
|
||||
variable: "topic",
|
||||
operator: "equals",
|
||||
value: "sensors/temp"
|
||||
}
|
||||
]);
|
||||
const heartbeat = await testMqtt("", null, "any message", "sensors/temp", "sensors/temp", conditions);
|
||||
assert.strictEqual(heartbeat.status, UP);
|
||||
});
|
||||
|
||||
test("check() rejects when message condition does not match", async () => {
|
||||
const conditions = JSON.stringify([
|
||||
{
|
||||
type: "expression",
|
||||
variable: "message",
|
||||
operator: "contains",
|
||||
value: "EXPECTED"
|
||||
}
|
||||
]);
|
||||
await assert.rejects(
|
||||
testMqtt("", null, "actual message without keyword", "test", "test", conditions),
|
||||
new Error("Conditions not met - Topic: test; Message: actual message without keyword")
|
||||
);
|
||||
});
|
||||
|
||||
test("check() sets status to UP with multiple conditions (AND)", async () => {
|
||||
const conditions = JSON.stringify([
|
||||
{
|
||||
type: "expression",
|
||||
variable: "topic",
|
||||
operator: "equals",
|
||||
value: "test"
|
||||
},
|
||||
{
|
||||
type: "expression",
|
||||
variable: "message",
|
||||
operator: "contains",
|
||||
value: "success",
|
||||
andOr: "and"
|
||||
}
|
||||
]);
|
||||
const heartbeat = await testMqtt("", null, "operation success", "test", "test", conditions);
|
||||
assert.strictEqual(heartbeat.status, UP);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user