跳转到内容

栈集成与测试

栈集成与测试

本节介绍如何将 IoT 技术栈的各组件集成在一起,并进行端到端测试验证。学习完成后,您将能够:

  • 理解各组件之间的数据流关系
  • 创建完整的集成测试方案
  • 验证端到端 IoT 数据管道的正确性
  • 向客户演示完整的技术栈
完整的 IoT 数据流:
┌─────────┐ ┌────────────┐ ┌──────────┐ ┌─────────┐
│ 模拟设备 │ ──→ │ Mosquitto │ ──→ │ Node-RED │ ──→ │ InfluxDB│
│ (MQTT) │ │ (Broker) │ │ (处理) │ │ (存储) │
└─────────┘ └────────────┘ └──────────┘ └─────────┘
│ │
│ ▼
│ ┌─────────┐
└──────────→ │ Grafana │
(数据源) │ (展示) │
└─────────┘
docker-compose.test.yml
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=0
FAIL=0
GREEN='\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++))
fi
done
# 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++))
fi
else
# 使用 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..."
# 发送模拟数据到 MQTT
SENSOR_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 individually
fi
# Summary
echo ""
echo "=================================="
echo " Test Summary"
echo " Passed: ${PASS}"
echo " Failed: ${FAIL}"
echo "=================================="

创建一个用于测试的 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"
}
]
Terminal window
# 终端 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}
Terminal window
# 查看 Node-RED 日志
docker logs -f nodered | grep -i "sensor"
# 通过 API 查看节点状态
curl http://localhost:1880/flows | python3 -m json.tool
Terminal window
# 查询最近数据
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()'
Terminal window
# 查看 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"
}]
}]
}
}'

症状: Node-RED 无法连接 Mosquitto 原因: 容器名解析错误 解决方案:

Terminal window
# 确保使用容器名称而非 localhost
# Node-RED MQTT Broker 配置: mosquitto:1883
# 而非 localhost:1883 或 127.0.0.1:1883
# 测试容器间通信
docker exec nodered ping mosquitto

症状: Node-RED 写入 InfluxDB 失败 解决方案:

Terminal window
# 在 Node-RED InfluxDB 节点配置中
# host: influxdb
# port: 8086
# org: iot-demo
# bucket: nodered
# token: <your-token>
# 验证 token
curl http://localhost:8086/api/v2/authorizations \
--header "Authorization: Token your-token"

解决方案:

Terminal window
# 使用正确的 InfluxDB URL
# Docker 内部: http://influxdb:8086
# 本地访问: http://localhost:8086
# 在 Grafana 数据源配置中 URL 应填:
# http://influxdb:8086 (从 Grafana 容器访问)
  1. 端到端测试验证整个 IoT 数据管道的完整性
  2. 测试脚本自动化验证所有组件状态
  3. Node-RED 是各组件间的数据枢纽
  4. 容器名解析是最常见的集成问题
  5. 完整的测试报告提升客户信心