From c9bacb64c81686b021b704908d6131b5b7a09564 Mon Sep 17 00:00:00 2001 From: Rene De Ren Date: Thu, 12 Mar 2026 10:32:09 +0100 Subject: [PATCH] Add monster coverage and stack validation --- jest.config.js | 1 + nodes/monster | 2 +- test/e2e/flows.json | 119 ++++++++++++++++++++++++++++++++++++++++++++ test/e2e/run-e2e.sh | 52 +++++++++++++++---- 4 files changed, 162 insertions(+), 12 deletions(-) diff --git a/jest.config.js b/jest.config.js index a759f52..de73d8c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -4,6 +4,7 @@ module.exports = { testMatch: [ '/nodes/generalFunctions/src/coolprop-node/test/**/*.test.js', '/nodes/generalFunctions/test/**/*.test.js', + '/nodes/monster/test/**/*.test.js', '/nodes/pumpingStation/test/**/*.test.js', '/nodes/reactor/test/**/*.test.js', '/nodes/settler/test/**/*.test.js', diff --git a/nodes/monster b/nodes/monster index ae30f04..5f80941 160000 --- a/nodes/monster +++ b/nodes/monster @@ -1 +1 @@ -Subproject commit ae30f0449cd05f5110d28964b3e9c0a6f94ffac6 +Subproject commit 5f80941268a17ac0874d955c6dc09c199430b89c diff --git a/test/e2e/flows.json b/test/e2e/flows.json index e8e7088..e203880 100644 --- a/test/e2e/flows.json +++ b/test/e2e/flows.json @@ -181,5 +181,124 @@ "x": 600, "y": 200, "wires": [] + }, + { + "id": "inject-monster-prediction", + "type": "inject", + "z": "e2e-flow-tab", + "name": "Monster prediction", + "props": [ + { "p": "payload" }, + { "p": "topic", "vt": "str" } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "4", + "topic": "model_prediction", + "payload": "120", + "payloadType": "num", + "x": 150, + "y": 320, + "wires": [["evolv-monster"]] + }, + { + "id": "inject-monster-flow", + "type": "inject", + "z": "e2e-flow-tab", + "name": "Monster flow", + "props": [ + { "p": "payload" }, + { "p": "topic", "vt": "str" } + ], + "repeat": "3", + "crontab": "", + "once": true, + "onceDelay": "5", + "topic": "i_flow", + "payload": "3600", + "payloadType": "num", + "x": 140, + "y": 360, + "wires": [["evolv-monster"]] + }, + { + "id": "inject-monster-start", + "type": "inject", + "z": "e2e-flow-tab", + "name": "Monster start", + "props": [ + { "p": "payload" }, + { "p": "topic", "vt": "str" } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "6", + "topic": "start", + "payload": "", + "payloadType": "date", + "x": 140, + "y": 400, + "wires": [["evolv-monster"]] + }, + { + "id": "evolv-monster", + "type": "monster", + "z": "e2e-flow-tab", + "name": "E2E-Monster", + "samplingtime": 1, + "minvolume": 5, + "maxweight": 23, + "emptyWeightBucket": 3, + "aquon_sample_name": "112100", + "supplier": "e2e-test", + "subType": "samplingCabinet", + "model": "e2e-virtual", + "unit": "m3/h", + "enableLog": false, + "logLevel": "error", + "x": 390, + "y": 360, + "wires": [ + ["debug-monster-process"], + ["debug-monster-dbase"], + [], + [] + ] + }, + { + "id": "debug-monster-process", + "type": "debug", + "z": "e2e-flow-tab", + "name": "Monster Process Output", + "active": true, + "tosidebar": true, + "console": true, + "tostatus": true, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 660, + "y": 340, + "wires": [] + }, + { + "id": "debug-monster-dbase", + "type": "debug", + "z": "e2e-flow-tab", + "name": "Monster Database Output", + "active": true, + "tosidebar": true, + "console": true, + "tostatus": true, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 670, + "y": 380, + "wires": [] } ] diff --git a/test/e2e/run-e2e.sh b/test/e2e/run-e2e.sh index de2035a..cfc9757 100755 --- a/test/e2e/run-e2e.sh +++ b/test/e2e/run-e2e.sh @@ -13,6 +13,8 @@ COMPOSE_FILE="$PROJECT_ROOT/docker-compose.e2e.yml" NODERED_URL="http://localhost:1880" MAX_WAIT=120 # seconds to wait for Node-RED to become healthy +GRAFANA_URL="http://localhost:3000/api/health" +MAX_GRAFANA_WAIT=60 # EVOLV node types that must appear in the palette (from package.json node-red.nodes) EXPECTED_NODES=( @@ -38,10 +40,10 @@ log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } log_error() { echo -e "${RED}[ERROR]${NC} $*"; } # Determine docker compose command (handle permission via sg docker if needed) -DOCKER_COMPOSE="docker compose" +USE_SG_DOCKER=false if ! docker info >/dev/null 2>&1; then if sg docker -c "docker info" >/dev/null 2>&1; then - DOCKER_COMPOSE="sg docker -c 'docker compose'" + USE_SG_DOCKER=true log_info "Using sg docker for Docker access" else log_error "Docker is not accessible. Please ensure Docker is running and you have permissions." @@ -49,9 +51,22 @@ if ! docker info >/dev/null 2>&1; then fi fi +run_compose() { + if [ "$USE_SG_DOCKER" = true ]; then + local cmd="docker compose -f $(printf '%q' "$COMPOSE_FILE")" + local arg + for arg in "$@"; do + cmd+=" $(printf '%q' "$arg")" + done + sg docker -c "$cmd" + else + docker compose -f "$COMPOSE_FILE" "$@" + fi +} + cleanup() { log_info "Tearing down E2E stack..." - eval $DOCKER_COMPOSE -f "$COMPOSE_FILE" down --volumes --remove-orphans 2>/dev/null || true + run_compose down --volumes --remove-orphans 2>/dev/null || true } # Always clean up on exit @@ -59,7 +74,7 @@ trap cleanup EXIT # --- Step 1: Build and start the stack --- log_info "Building and starting E2E stack..." -eval $DOCKER_COMPOSE -f "$COMPOSE_FILE" up -d --build +run_compose up -d --build # --- Step 2: Wait for Node-RED to be healthy --- log_info "Waiting for Node-RED to become healthy (max ${MAX_WAIT}s)..." @@ -76,7 +91,7 @@ done if [ $elapsed -ge $MAX_WAIT ]; then log_error "Node-RED did not become healthy within ${MAX_WAIT}s" log_error "Container logs:" - eval $DOCKER_COMPOSE -f "$COMPOSE_FILE" logs nodered + run_compose logs nodered exit 1 fi @@ -129,12 +144,15 @@ fi # --- Step 5b: Verify Grafana is reachable --- log_info "Checking Grafana health..." -GRAFANA_HEALTH=$(curl -sf "http://localhost:3000/api/health" 2>&1) || { - log_error "Failed to reach Grafana health endpoint" - FAILURES=$((FAILURES + 1)) -} +GRAFANA_HEALTH="" +elapsed=0 +while [ $elapsed -lt $MAX_GRAFANA_WAIT ]; do + GRAFANA_HEALTH=$(curl -sf "$GRAFANA_URL" 2>&1) && break + sleep 2 + elapsed=$((elapsed + 2)) +done -if echo "$GRAFANA_HEALTH" | grep -q '"database":"ok"'; then +if echo "$GRAFANA_HEALTH" | grep -Eq '"database"[[:space:]]*:[[:space:]]*"ok"'; then log_info " [PASS] Grafana is healthy" else log_error " [FAIL] Grafana health check failed" @@ -143,7 +161,7 @@ fi # --- Step 5c: Verify EVOLV measurement node produced output --- log_info "Checking EVOLV measurement node output in container logs..." -NODERED_LOGS=$(eval $DOCKER_COMPOSE -f "$COMPOSE_FILE" logs nodered 2>&1) +NODERED_LOGS=$(run_compose logs nodered 2>&1) if echo "$NODERED_LOGS" | grep -q "Database Output"; then log_info " [PASS] EVOLV measurement node produced database output" @@ -157,6 +175,18 @@ else log_warn " [WARN] EVOLV measurement process output not detected in logs" fi +if echo "$NODERED_LOGS" | grep -q "Monster Process Output"; then + log_info " [PASS] EVOLV monster node produced process output" +else + log_warn " [WARN] EVOLV monster process output not detected in logs" +fi + +if echo "$NODERED_LOGS" | grep -q "Monster Database Output"; then + log_info " [PASS] EVOLV monster node produced database output" +else + log_warn " [WARN] EVOLV monster database output not detected in logs" +fi + # --- Step 6: Summary --- echo "" if [ $FAILURES -eq 0 ]; then