chore: clean up superproject structure
Some checks failed
CI / lint-and-test (push) Has been cancelled
Some checks failed
CI / lint-and-test (push) Has been cancelled
Move content to correct locations: - AGENTS.md → .agents/AGENTS.md (with orchestrator reference update) - third_party/docs/ (8 reference docs) → wiki/concepts/ - manuals/ (12 Node-RED docs) → wiki/manuals/ Delete 23 unreferenced one-off scripts from scripts/ (keeping 5 active). Delete stale Dockerfile.e2e, docker-compose.e2e.yml, test/e2e/. Remove empty third_party/ directory. Root is now: README, CLAUDE.md, LICENSE, package.json, Makefile, Dockerfile, docker-compose.yml, docker/, scripts/ (5), nodes/, wiki/, plus dotfiles (.agents, .claude, .gitea). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,440 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": "e2e-flow-tab",
|
||||
"type": "tab",
|
||||
"label": "E2E Test Flow",
|
||||
"disabled": false,
|
||||
"info": "End-to-end test flow that verifies EVOLV nodes load, accept input, and produce output."
|
||||
},
|
||||
{
|
||||
"id": "inject-trigger",
|
||||
"type": "inject",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "Trigger once on start",
|
||||
"props": [
|
||||
{ "p": "payload" },
|
||||
{ "p": "topic", "vt": "str" }
|
||||
],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": true,
|
||||
"onceDelay": "3",
|
||||
"topic": "e2e-test",
|
||||
"payload": "",
|
||||
"payloadType": "date",
|
||||
"x": 160,
|
||||
"y": 80,
|
||||
"wires": [["build-measurement-msg"]]
|
||||
},
|
||||
{
|
||||
"id": "build-measurement-msg",
|
||||
"type": "function",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "Build measurement input",
|
||||
"func": "// Simulate an analog sensor reading sent to the measurement node.\n// The measurement node expects a numeric payload on topic 'analogInput'.\nmsg.payload = 4.2 + Math.random() * 15.8; // 4-20 mA range\nmsg.topic = 'analogInput';\nnode.status({ fill: 'green', shape: 'dot', text: 'sent ' + msg.payload.toFixed(2) });\nreturn msg;",
|
||||
"outputs": 1,
|
||||
"timeout": "",
|
||||
"noerr": 0,
|
||||
"initialize": "",
|
||||
"finalize": "",
|
||||
"libs": [],
|
||||
"x": 380,
|
||||
"y": 80,
|
||||
"wires": [["measurement-e2e-node"]]
|
||||
},
|
||||
{
|
||||
"id": "measurement-e2e-node",
|
||||
"type": "measurement",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "E2E-Level-Sensor",
|
||||
"scaling": true,
|
||||
"i_min": 4,
|
||||
"i_max": 20,
|
||||
"i_offset": 0,
|
||||
"o_min": 0,
|
||||
"o_max": 5,
|
||||
"simulator": false,
|
||||
"smooth_method": "",
|
||||
"count": "10",
|
||||
"uuid": "",
|
||||
"supplier": "e2e-test",
|
||||
"category": "level",
|
||||
"assetType": "sensor",
|
||||
"model": "e2e-virtual",
|
||||
"unit": "m",
|
||||
"enableLog": false,
|
||||
"logLevel": "error",
|
||||
"positionVsParent": "upstream",
|
||||
"positionIcon": "",
|
||||
"hasDistance": false,
|
||||
"distance": 0,
|
||||
"distanceUnit": "m",
|
||||
"distanceDescription": "",
|
||||
"x": 600,
|
||||
"y": 80,
|
||||
"wires": [
|
||||
["debug-process"],
|
||||
["debug-dbase"],
|
||||
["debug-parent"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "debug-process",
|
||||
"type": "debug",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "Process Output",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": true,
|
||||
"tostatus": true,
|
||||
"complete": "true",
|
||||
"targetType": "full",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 830,
|
||||
"y": 40,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "debug-dbase",
|
||||
"type": "debug",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "Database Output",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": true,
|
||||
"tostatus": true,
|
||||
"complete": "true",
|
||||
"targetType": "full",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 840,
|
||||
"y": 80,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "debug-parent",
|
||||
"type": "debug",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "Parent Output",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": true,
|
||||
"tostatus": true,
|
||||
"complete": "true",
|
||||
"targetType": "full",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 830,
|
||||
"y": 120,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "inject-periodic",
|
||||
"type": "inject",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "Periodic (5s)",
|
||||
"props": [
|
||||
{ "p": "payload" },
|
||||
{ "p": "topic", "vt": "str" }
|
||||
],
|
||||
"repeat": "5",
|
||||
"crontab": "",
|
||||
"once": true,
|
||||
"onceDelay": "6",
|
||||
"topic": "e2e-heartbeat",
|
||||
"payload": "",
|
||||
"payloadType": "date",
|
||||
"x": 160,
|
||||
"y": 200,
|
||||
"wires": [["heartbeat-func"]]
|
||||
},
|
||||
{
|
||||
"id": "heartbeat-func",
|
||||
"type": "function",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "Heartbeat check",
|
||||
"func": "// Verify the EVOLV measurement node is running by querying its presence\nmsg.payload = {\n check: 'heartbeat',\n timestamp: Date.now(),\n nodeCount: global.get('_e2e_msg_count') || 0\n};\n// Increment message counter\nlet count = global.get('_e2e_msg_count') || 0;\nglobal.set('_e2e_msg_count', count + 1);\nnode.status({ fill: 'blue', shape: 'ring', text: 'beat #' + (count+1) });\nreturn msg;",
|
||||
"outputs": 1,
|
||||
"timeout": "",
|
||||
"noerr": 0,
|
||||
"initialize": "",
|
||||
"finalize": "",
|
||||
"libs": [],
|
||||
"x": 380,
|
||||
"y": 200,
|
||||
"wires": [["debug-heartbeat"]]
|
||||
},
|
||||
{
|
||||
"id": "debug-heartbeat",
|
||||
"type": "debug",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "Heartbeat Debug",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": true,
|
||||
"tostatus": false,
|
||||
"complete": "payload",
|
||||
"targetType": "msg",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"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": []
|
||||
},
|
||||
{
|
||||
"id": "inject-dashboardapi-register",
|
||||
"type": "inject",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "DashboardAPI register child",
|
||||
"props": [
|
||||
{ "p": "payload" },
|
||||
{ "p": "topic", "vt": "str" }
|
||||
],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": true,
|
||||
"onceDelay": "12",
|
||||
"payload": "",
|
||||
"payloadType": "date",
|
||||
"x": 160,
|
||||
"y": 500,
|
||||
"wires": [["build-dashboardapi-msg"]]
|
||||
},
|
||||
{
|
||||
"id": "build-dashboardapi-msg",
|
||||
"type": "function",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "Build dashboardapi input",
|
||||
"func": "msg.topic = 'registerChild';\nmsg.payload = {\n config: {\n general: {\n name: 'E2E-Level-Sensor'\n },\n functionality: {\n softwareType: 'measurement'\n }\n }\n};\nreturn msg;",
|
||||
"outputs": 1,
|
||||
"timeout": "",
|
||||
"noerr": 0,
|
||||
"initialize": "",
|
||||
"finalize": "",
|
||||
"libs": [],
|
||||
"x": 400,
|
||||
"y": 500,
|
||||
"wires": [["dashboardapi-e2e"]]
|
||||
},
|
||||
{
|
||||
"id": "dashboardapi-e2e",
|
||||
"type": "dashboardapi",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "E2E-DashboardAPI",
|
||||
"logLevel": "error",
|
||||
"enableLog": false,
|
||||
"host": "grafana",
|
||||
"port": "3000",
|
||||
"bearerToken": "",
|
||||
"x": 660,
|
||||
"y": 500,
|
||||
"wires": [["debug-dashboardapi-output"]]
|
||||
},
|
||||
{
|
||||
"id": "debug-dashboardapi-output",
|
||||
"type": "debug",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "DashboardAPI Output",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": true,
|
||||
"tostatus": true,
|
||||
"complete": "true",
|
||||
"targetType": "full",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 920,
|
||||
"y": 500,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "inject-diffuser-flow",
|
||||
"type": "inject",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "Diffuser airflow",
|
||||
"props": [
|
||||
{ "p": "payload" },
|
||||
{ "p": "topic", "vt": "str" }
|
||||
],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": true,
|
||||
"onceDelay": "9",
|
||||
"topic": "air_flow",
|
||||
"payload": "24",
|
||||
"payloadType": "num",
|
||||
"x": 150,
|
||||
"y": 620,
|
||||
"wires": [["diffuser-e2e"]]
|
||||
},
|
||||
{
|
||||
"id": "diffuser-e2e",
|
||||
"type": "diffuser",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "E2E-Diffuser",
|
||||
"number": 1,
|
||||
"i_elements": 4,
|
||||
"i_diff_density": 2.4,
|
||||
"i_m_water": 4.5,
|
||||
"alfaf": 0.7,
|
||||
"enableLog": false,
|
||||
"logLevel": "error",
|
||||
"x": 390,
|
||||
"y": 620,
|
||||
"wires": [["debug-diffuser-process"], ["debug-diffuser-dbase"], []]
|
||||
},
|
||||
{
|
||||
"id": "debug-diffuser-process",
|
||||
"type": "debug",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "Diffuser Process Output",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": true,
|
||||
"tostatus": true,
|
||||
"complete": "true",
|
||||
"targetType": "full",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 670,
|
||||
"y": 600,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "debug-diffuser-dbase",
|
||||
"type": "debug",
|
||||
"z": "e2e-flow-tab",
|
||||
"name": "Diffuser Database Output",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": true,
|
||||
"tostatus": true,
|
||||
"complete": "true",
|
||||
"targetType": "full",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 680,
|
||||
"y": 640,
|
||||
"wires": []
|
||||
}
|
||||
]
|
||||
@@ -1,213 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# End-to-end test runner for EVOLV Node-RED stack.
|
||||
# Starts Node-RED + InfluxDB + Grafana via Docker Compose,
|
||||
# verifies that EVOLV nodes are registered in the palette,
|
||||
# and tears down the stack on exit.
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
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
|
||||
LOG_WAIT=20
|
||||
|
||||
# EVOLV node types that must appear in the palette (from package.json node-red.nodes)
|
||||
EXPECTED_NODES=(
|
||||
"dashboardapi"
|
||||
"diffuser"
|
||||
"machineGroupControl"
|
||||
"measurement"
|
||||
"monster"
|
||||
"pumpingstation"
|
||||
"reactor"
|
||||
"rotatingMachine"
|
||||
"settler"
|
||||
"valve"
|
||||
"valveGroupControl"
|
||||
)
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
log_info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
|
||||
|
||||
wait_for_log_pattern() {
|
||||
local pattern="$1"
|
||||
local description="$2"
|
||||
local required="${3:-false}"
|
||||
local elapsed=0
|
||||
local logs=""
|
||||
|
||||
while [ $elapsed -lt $LOG_WAIT ]; do
|
||||
logs=$(run_compose logs nodered 2>&1)
|
||||
if echo "$logs" | grep -q "$pattern"; then
|
||||
log_info " [PASS] $description"
|
||||
return 0
|
||||
fi
|
||||
sleep 2
|
||||
elapsed=$((elapsed + 2))
|
||||
done
|
||||
|
||||
if [ "$required" = true ]; then
|
||||
log_error " [FAIL] $description not detected in logs"
|
||||
FAILURES=$((FAILURES + 1))
|
||||
else
|
||||
log_warn " [WARN] $description not detected in logs"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Determine docker compose command (handle permission via sg docker if needed)
|
||||
USE_SG_DOCKER=false
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
if sg docker -c "docker info" >/dev/null 2>&1; then
|
||||
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."
|
||||
exit 1
|
||||
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..."
|
||||
run_compose down --volumes --remove-orphans 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Always clean up on exit
|
||||
trap cleanup EXIT
|
||||
|
||||
# --- Step 1: Build and start the stack ---
|
||||
log_info "Building and starting E2E stack..."
|
||||
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)..."
|
||||
elapsed=0
|
||||
while [ $elapsed -lt $MAX_WAIT ]; do
|
||||
if curl -sf "$NODERED_URL/" >/dev/null 2>&1; then
|
||||
log_info "Node-RED is up after ${elapsed}s"
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
elapsed=$((elapsed + 2))
|
||||
done
|
||||
|
||||
if [ $elapsed -ge $MAX_WAIT ]; then
|
||||
log_error "Node-RED did not become healthy within ${MAX_WAIT}s"
|
||||
log_error "Container logs:"
|
||||
run_compose logs nodered
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Give Node-RED a few extra seconds to finish loading all nodes and editor metadata
|
||||
sleep 8
|
||||
|
||||
# --- Step 3: Verify EVOLV nodes are registered in the palette ---
|
||||
log_info "Querying Node-RED for registered nodes..."
|
||||
NODES_RESPONSE=$(curl -sf "$NODERED_URL/nodes" 2>&1) || {
|
||||
log_error "Failed to query Node-RED /nodes endpoint"
|
||||
exit 1
|
||||
}
|
||||
|
||||
FAILURES=0
|
||||
PALETTE_MISSES=0
|
||||
for node_type in "${EXPECTED_NODES[@]}"; do
|
||||
if echo "$NODES_RESPONSE" | grep -qi "$node_type"; then
|
||||
log_info " [PASS] Node type '$node_type' found in palette"
|
||||
else
|
||||
log_warn " [WARN] Node type '$node_type' not found in /nodes response"
|
||||
PALETTE_MISSES=$((PALETTE_MISSES + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
# --- Step 4: Verify flows are deployed ---
|
||||
log_info "Checking deployed flows..."
|
||||
FLOWS_RESPONSE=$(curl -sf "$NODERED_URL/flows" 2>&1) || {
|
||||
log_error "Failed to query Node-RED /flows endpoint"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if echo "$FLOWS_RESPONSE" | grep -q "e2e-flow-tab"; then
|
||||
log_info " [PASS] E2E test flow is deployed"
|
||||
else
|
||||
log_warn " [WARN] E2E test flow not found in deployed flows (may need manual deploy)"
|
||||
fi
|
||||
|
||||
# --- Step 5: Verify InfluxDB is reachable ---
|
||||
log_info "Checking InfluxDB health..."
|
||||
INFLUX_HEALTH=$(curl -sf "http://localhost:8086/health" 2>&1) || {
|
||||
log_error "Failed to reach InfluxDB health endpoint"
|
||||
FAILURES=$((FAILURES + 1))
|
||||
}
|
||||
|
||||
if echo "$INFLUX_HEALTH" | grep -q '"status":"pass"'; then
|
||||
log_info " [PASS] InfluxDB is healthy"
|
||||
else
|
||||
log_error " [FAIL] InfluxDB health check failed"
|
||||
FAILURES=$((FAILURES + 1))
|
||||
fi
|
||||
|
||||
# --- Step 5b: Verify Grafana is reachable ---
|
||||
log_info "Checking Grafana health..."
|
||||
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 -Eq '"database"[[:space:]]*:[[:space:]]*"ok"'; then
|
||||
log_info " [PASS] Grafana is healthy"
|
||||
else
|
||||
log_error " [FAIL] Grafana health check failed"
|
||||
FAILURES=$((FAILURES + 1))
|
||||
fi
|
||||
|
||||
# --- Step 5c: Verify EVOLV measurement node produced output ---
|
||||
log_info "Checking EVOLV measurement node output in container logs..."
|
||||
wait_for_log_pattern "Database Output" "EVOLV measurement node produced database output" true || true
|
||||
wait_for_log_pattern "Process Output" "EVOLV measurement node produced process output" true || true
|
||||
wait_for_log_pattern "Monster Process Output" "EVOLV monster node produced process output" true || true
|
||||
wait_for_log_pattern "Monster Database Output" "EVOLV monster node produced database output" true || true
|
||||
wait_for_log_pattern "Diffuser Process Output" "EVOLV diffuser node produced process output" true || true
|
||||
wait_for_log_pattern "Diffuser Database Output" "EVOLV diffuser node produced database output" true || true
|
||||
wait_for_log_pattern "DashboardAPI Output" "EVOLV dashboardapi node produced create output" true || true
|
||||
|
||||
# --- Step 6: Summary ---
|
||||
echo ""
|
||||
if [ $FAILURES -eq 0 ]; then
|
||||
log_info "========================================="
|
||||
log_info " E2E tests PASSED - all checks green"
|
||||
log_info "========================================="
|
||||
exit 0
|
||||
else
|
||||
log_error "========================================="
|
||||
log_error " E2E tests FAILED - $FAILURES check(s) failed"
|
||||
log_error "========================================="
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user