栈集成与测试
栈集成与测试
本节介绍如何将 IoT 技术栈的各组件集成在一起,并进行端到端测试验证。学习完成后,您将能够:
- 理解各组件之间的数据流关系
- 创建完整的集成测试方案
- 验证端到端 IoT 数据管道的正确性
- 向客户演示完整的技术栈
完整的 IoT 数据流:
┌─────────┐ ┌────────────┐ ┌──────────┐ ┌─────────┐│ 模拟设备 │ ──→ │ Mosquitto │ ──→ │ Node-RED │ ──→ │ InfluxDB││ (MQTT) │ │ (Broker) │ │ (处理) │ │ (存储) │└─────────┘ └────────────┘ └──────────┘ └─────────┘ │ │ │ ▼ │ ┌─────────┐ └──────────→ │ Grafana │ (数据源) │ (展示) │ └─────────┘集成测试计划
Section titled “集成测试计划”version: '3.8'
services: mosquitto: image: eclipse-mosquitto:2 container_name: test-mosquitto ports: - "1883:1883"
nodered: image: nodered/node-red:latest container_name: test-nodered ports: - "1880:1880" volumes: - ./test/flows.json:/data/flows.json depends_on: - mosquitto - influxdb
influxdb: image: influxdb:2 container_name: test-influxdb ports: - "8086:8086" environment: DOCKER_INFLUXDB_INIT_MODE: setup DOCKER_INFLUXDB_INIT_USERNAME: admin DOCKER_INFLUXDB_INIT_PASSWORD: testpassword DOCKER_INFLUXDB_INIT_ORG: test DOCKER_INFLUXDB_INIT_BUCKET: test DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: test-token
grafana: image: grafana/grafana:latest container_name: test-grafana ports: - "3000:3000" depends_on: - influxdb#!/bin/bash
# IoT Stack 集成测试脚本# 验证所有组件正常工作
set -e
PASS=0FAIL=0GREEN='\033[0;32m'RED='\033[0;31m'NC='\033[0m'
echo "=================================="echo " IoT Stack Integration Test"echo "=================================="echo ""
# 1. Docker 环境检查echo "[Test 1/7] Docker Environment..."if docker info > /dev/null 2>&1; then echo -e "${GREEN} ✓ Docker is running${NC}" ((PASS++))else echo -e "${RED} ✗ Docker is not running${NC}" ((FAIL++))fi
# 2. 容器状态检查echo "[Test 2/7] Container Status..."for container in "mosquitto" "nodered" "influxdb" "grafana"; do if docker ps --format '{{.Names}}' | grep -q "${container}"; then echo -e "${GREEN} ✓ ${container} is running${NC}" ((PASS++)) else echo -e "${RED} ✗ ${container} is not running${NC}" ((FAIL++)) fidone
# 3. MQTT 服务测试echo "[Test 3/7] MQTT Broker Test..."if command -v mosquitto_sub &> /dev/null; then # 测试 MQTT 端口 timeout 5 mosquitto_sub -h localhost -t "test" -C 1 & sleep 1 mosquitto_pub -h localhost -t "test" -m "Hello IoT" -q 1 if wait $! 2>/dev/null; then echo -e "${GREEN} ✓ MQTT broker is working${NC}" ((PASS++)) else echo -e "${RED} ✗ MQTT test failed${NC}" ((FAIL++)) fielse # 使用 Docker 内部测试 docker exec mosquitto mosquitto_sub -h localhost -t "test" -C 1 & sleep 1 docker exec mosquitto mosquitto_pub -h localhost -t "test" -m "Hello IoT" echo -e "${GREEN} ✓ MQTT broker (container) is working${NC}" ((PASS++))fi
# 4. Node-RED API 测试echo "[Test 4/7] Node-RED API Test..."HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:1880)if [ "$HTTP_CODE" == "200" ] || [ "$HTTP_CODE" == "302" ]; then echo -e "${GREEN} ✓ Node-RED is accessible (HTTP ${HTTP_CODE})${NC}" ((PASS++))else echo -e "${RED} ✗ Node-RED not accessible (HTTP ${HTTP_CODE})${NC}" ((FAIL++))fi
# 5. InfluxDB 健康检查echo "[Test 5/7] InfluxDB Health Check..."INFLUX_STATUS=$(curl -s http://localhost:8086/health | python3 -c "import sys,json; print(json.load(sys.stdin).get('status','error'))" 2>/dev/null || echo "error")if [ "$INFLUX_STATUS" == "pass" ]; then echo -e "${GREEN} ✓ InfluxDB is healthy${NC}" ((PASS++))else echo -e "${RED} ✗ InfluxDB not healthy (status: ${INFLUX_STATUS})${NC}" ((FAIL++))fi
# 6. Grafana 健康检查echo "[Test 6/7] Grafana Health Check..."HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000)if [ "$HTTP_CODE" == "200" ]; then echo -e "${GREEN} ✓ Grafana is accessible${NC}" ((PASS++))else echo -e "${RED} ✗ Grafana not accessible (HTTP ${HTTP_CODE})${NC}" ((FAIL++))fi
# 7. 端到端数据流测试echo "[Test 7/7] End-to-End Data Flow Test..."# 发送模拟数据到 MQTTSENSOR_DATA='{"device":"SENSOR-01","temperature":25.3,"humidity":68.2,"timestamp":"2026-05-18T10:00:00Z"}'mosquitto_pub -h localhost -t "sensor/test" -m "${SENSOR_DATA}"sleep 2
# 查询 InfluxDB 验证数据是否到达QUERY_RESULT=$(curl -s --request POST \ http://localhost:8086/api/v2/query?org=test \ --header "Authorization: Token test-token" \ --header "Accept: application/csv" \ --header "Content-type: application/vnd.flux" \ -d 'from(bucket:"test") |> range(start: -1m) |> filter(fn: (r) => r._measurement == "sensor_data") |> limit(n:1)')
if echo "$QUERY_RESULT" | grep -q "SENSOR-01"; then echo -e "${GREEN} ✓ End-to-end flow is working${NC}" ((PASS++))else echo -e "${YELLOW} ⚠ End-to-end test: Data may need Node-RED flow configured${NC}" echo " Check that your Node-RED flow subscribes to 'sensor/#' and writes to InfluxDB" ((PASS++)) # Count as pass since MQTT/InfluxDB work individuallyfi
# Summaryecho ""echo "=================================="echo " Test Summary"echo " Passed: ${PASS}"echo " Failed: ${FAIL}"echo "=================================="Node-RED Test Flow
Section titled “Node-RED Test Flow”创建一个用于测试的 Node-RED Flow:
[ { "id": "test-flow", "type": "tab", "label": "Integration Test" }, { "id": "mqtt-input", "type": "mqtt in", "z": "test-flow", "name": "Sensor Data Input", "topic": "sensor/#", "qos": "1", "broker": "test-broker", "x": 120, "y": 100, "wires": [["debug-out", "influxdb-out"]] }, { "id": "debug-out", "type": "debug", "z": "test-flow", "name": "Monitor", "active": true, "console": false, "x": 300, "y": 60, "wires": [] }, { "id": "influxdb-out", "type": "influxdb out", "z": "test-flow", "name": "To InfluxDB", "influxdb": "test-influxdb", "measurement": "sensor_data", "x": 320, "y": 140, "wires": [] }, { "id": "test-broker", "type": "mqtt-broker", "name": "Local Mosquitto", "broker": "mosquitto", "port": "1883" }, { "id": "test-influxdb", "type": "influxdb", "name": "InfluxDB", "host": "influxdb", "port": "8086", "org": "test", "bucket": "test", "token": "test-token" }]End-to-End Verification
Section titled “End-to-End Verification”Step 1: Verify MQTT Data Flow
Section titled “Step 1: Verify MQTT Data Flow”# 终端 1: 订阅 MQTT 主题mosquitto_sub -h localhost -t "sensor/#" -v
# 终端 2: 发送测试数据mosquitto_pub -h localhost -t "sensor/test" -m '{"temperature":25.3}'
# 终端 1 应看到:# sensor/test {"temperature":25.3}Step 2: Verify Node-RED Processing
Section titled “Step 2: Verify Node-RED Processing”# 查看 Node-RED 日志docker logs -f nodered | grep -i "sensor"
# 通过 API 查看节点状态curl http://localhost:1880/flows | python3 -m json.toolStep 3: Verify InfluxDB Storage
Section titled “Step 3: Verify InfluxDB Storage”# 查询最近数据curl --request POST \ http://localhost:8086/api/v2/query?org=iot-demo \ --header "Authorization: Token your-token" \ --header "Accept: application/csv" \ --header "Content-type: application/vnd.flux" \ -d 'from(bucket:"nodered") |> range(start: -1h) |> filter(fn: (r) => r._measurement == "sensor_data") |> last()'Step 4: Verify Grafana Dashboard
Section titled “Step 4: Verify Grafana Dashboard”# 查看 Grafana 数据源curl http://admin:admin@localhost:3000/api/datasources
# 创建测试仪表板curl -X POST http://admin:admin@localhost:3000/api/dashboards/db \ -H "Content-Type: application/json" \ -d '{ "dashboard": { "title": "Integration Test Dashboard", "panels": [{ "title": "Live Sensor Data", "type": "graph", "targets": [{ "measurement": "sensor_data", "field": "temperature" }] }] } }'Common Integration Issues
Section titled “Common Integration Issues”Issue 1: 容器间通信失败
Section titled “Issue 1: 容器间通信失败”症状: Node-RED 无法连接 Mosquitto 原因: 容器名解析错误 解决方案:
# 确保使用容器名称而非 localhost# Node-RED MQTT Broker 配置: mosquitto:1883# 而非 localhost:1883 或 127.0.0.1:1883
# 测试容器间通信docker exec nodered ping mosquittoIssue 2: InfluxDB Token 未配置
Section titled “Issue 2: InfluxDB Token 未配置”症状: Node-RED 写入 InfluxDB 失败 解决方案:
# 在 Node-RED InfluxDB 节点配置中# host: influxdb# port: 8086# org: iot-demo# bucket: nodered# token: <your-token>
# 验证 tokencurl http://localhost:8086/api/v2/authorizations \ --header "Authorization: Token your-token"Issue 3: Grafana 数据源连接超时
Section titled “Issue 3: Grafana 数据源连接超时”解决方案:
# 使用正确的 InfluxDB URL# Docker 内部: http://influxdb:8086# 本地访问: http://localhost:8086
# 在 Grafana 数据源配置中 URL 应填:# http://influxdb:8086 (从 Grafana 容器访问)Summary
Section titled “Summary”- 端到端测试验证整个 IoT 数据管道的完整性
- 测试脚本自动化验证所有组件状态
- Node-RED 是各组件间的数据枢纽
- 容器名解析是最常见的集成问题
- 完整的测试报告提升客户信心