diff --git a/apps/starry/mosquitto/README.md b/apps/starry/mosquitto/README.md new file mode 100644 index 0000000000..9d6d5883ca --- /dev/null +++ b/apps/starry/mosquitto/README.md @@ -0,0 +1,98 @@ +# Starry Mosquitto App + +This case runs Mosquitto MQTT broker inside StarryOS through the app runner. + +## Mosquitto功能介绍 + +Mosquitto是一个轻量级的MQTT消息代理(broker),实现了MQTT协议3.1/3.1.1/5.0版本。 + +### 核心功能: +1. **消息代理** - 作为MQTT broker,负责接收、路由和分发消息 +2. **发布/订阅模式** - 支持发布者(publisher)和订阅者(subscriber)模式 +3. **主题路由** - 支持多级主题(如 `sensor/room1/temperature`)和通配符订阅(`+` 单级、`#` 多级) +4. **QoS支持** - 支持三种QoS级别: + - QoS 0: 最多一次(fire and forget) + - QoS 1: 至少一次(acknowledged delivery) + - QoS 2: 恰好一次(assured delivery) +5. **保留消息** - 支持retained messages,新订阅者立即收到最后一条消息 +6. **持久化会话** - 支持持久化客户端会话,断线重连后可恢复 +7. **认证授权** - 支持用户名/密码认证和ACL访问控制 +8. **WebSocket支持** - 可通过WebSocket协议提供MQTT服务 +9. **集群支持** - 支持多broker桥接和集群 + +### 典型应用场景: +- 物联网(IoT)设备通信 +- 传感器数据收集 +- 智能家居系统 +- 实时消息推送 +- 移动应用后端消息服务 + +## 运行命令 + +默认运行全部测试(smoke + normal + stress): + +```bash +cargo xtask starry app run -t mosquitto --arch x86_64 +``` + +也可以单独运行某个级别: + +```bash +# 仅 Smoke 测试 +cargo xtask starry app run -t mosquitto --arch x86_64 --qemu-config qemu-x86_64-smoke.toml + +# 仅普通测试 +cargo xtask starry app run -t mosquitto --arch x86_64 --qemu-config qemu-x86_64-normal.toml + +# 仅压力测试 +cargo xtask starry app run -t mosquitto --arch x86_64 --qemu-config qemu-x86_64-stress.toml +``` + +## 测试内容 + +### Smoke测试 +- 基本发布/订阅 +- 多主题测试 +- 通配符订阅 +- QoS级别测试 + +### 普通测试 +- 基本发布/订阅 +- 多消息测试 +- 通配符主题 +- QoS 0/1/2级别 +- 保留消息 +- 持久化会话 +- 大消息负载 +- 多客户端并发 +- 主题特殊字符 + +### 压力测试 +- 高频消息发布/订阅 +- 多客户端并发压力 +- 大消息压力测试 +- 通配符压力测试 +- 混合QoS压力测试 +- 持久化重启测试 + +## 文件结构 + +``` +apps/starry/mosquitto/ +├── prebuild.sh # 构建脚本,安装mosquitto到rootfs +├── test_mosquitto.sh # 统一入口,按序运行全部测试 +├── mosquitto-smoke-tests.sh # Smoke测试脚本 +├── mosquitto-tests.sh # 普通测试脚本 +├── mosquitto-stress-tests.sh # 压力测试脚本 +├── build-*.toml # 构建配置 +├── qemu-x86_64.toml # 默认配置(运行全部测试) +├── qemu-x86_64-smoke.toml # 仅Smoke测试 +├── qemu-x86_64-normal.toml # 仅普通测试 +├── qemu-x86_64-stress.toml # 仅压力测试 +└── README.md # 本文件 +``` + +## 依赖 + +- mosquitto MQTT broker +- mosquitto-clients (mosquitto_pub, mosquitto_sub) diff --git a/apps/starry/mosquitto/build-x86_64-unknown-none.toml b/apps/starry/mosquitto/build-x86_64-unknown-none.toml new file mode 100644 index 0000000000..d7897a895e --- /dev/null +++ b/apps/starry/mosquitto/build-x86_64-unknown-none.toml @@ -0,0 +1,11 @@ +target = "x86_64-unknown-none" +env = { AX_IP = "10.0.2.15", AX_GW = "10.0.2.2" } +log = "Warn" +features = [ + "ax-hal/x86-pc", + "qemu", + "ax-driver/plat-static", + "ax-driver/virtio-blk", + "ax-driver/virtio-net", +] +plat_dyn = false diff --git a/apps/starry/mosquitto/mosquitto-smoke-tests.sh b/apps/starry/mosquitto/mosquitto-smoke-tests.sh new file mode 100755 index 0000000000..8c96662f8c --- /dev/null +++ b/apps/starry/mosquitto/mosquitto-smoke-tests.sh @@ -0,0 +1,182 @@ +#!/bin/sh +set -eu + +mosquitto_pid="" +test_done=0 + +# Pre-cleanup: kill any leftover mosquitto server processes and stale temp files! +# Use pidof for exact name match; pkill would also match this script's name "mosquitto-*" +for pid in $(pidof mosquitto 2>/dev/null); do + kill -9 "$pid" 2>/dev/null || true +done +rm -rf /var/lib/mosquitto/mosquitto* 2>/dev/null || true +sleep 1 + +start_mosquitto() { + # Kill any existing mosquitto processes (handles auto-started instances) + for pid in $(pidof mosquitto 2>/dev/null); do + kill -9 "$pid" 2>/dev/null || true + done + sleep 2 + + mkdir -p /var/lib/mosquitto/mosquitto + chmod 777 /var/lib/mosquitto/mosquitto + cat > /var/lib/mosquitto/mosquitto-test.conf << 'EOF' +listener 1883 +socket_domain ipv4 +allow_anonymous true +persistence false +log_dest stderr +log_type error +log_type warning +connection_messages true +EOF + + /usr/sbin/mosquitto -c /var/lib/mosquitto/mosquitto-test.conf > /var/lib/mosquitto/mosquitto-smoke.log 2>&1 & + mosquitto_pid=$! + + i=0 + while [ "$i" -lt 30 ]; do + if mosquitto_pub -h 127.0.0.1 -p 1883 -t test/ping -m "ping" 2>/dev/null; then + return 0 + fi + i=$((i + 1)) + sleep 1 + done + + echo "=== mosquitto-smoke.log ===" + cat /var/lib/mosquitto/mosquitto-smoke.log + echo "MOSQUITTO_SMOKE_TEST_FAILED" + exit 1 +} + +stop_mosquitto() { + if [ -n "$mosquitto_pid" ]; then + kill "$mosquitto_pid" >/dev/null 2>&1 || true + i=0 + while kill -0 "$mosquitto_pid" >/dev/null 2>&1 && [ "$i" -lt 10 ]; do + i=$((i + 1)) + sleep 1 + done + kill -9 "$mosquitto_pid" >/dev/null 2>&1 || true + wait "$mosquitto_pid" >/dev/null 2>&1 || true + mosquitto_pid="" + fi +} + +cleanup() { + stop_mosquitto + # Kill any remaining mosquitto processes (including stale ones) + for pid in $(pidof mosquitto 2>/dev/null); do + kill -9 "$pid" 2>/dev/null || true + done +} + +on_exit() { + rc=$? + if [ "$test_done" -ne 1 ]; then + echo "MOSQUITTO_SMOKE_TEST_FAILED" + fi + cleanup + exit "$rc" +} +trap on_exit EXIT + +echo "MOSQUITTO_SMOKE_STAGE start" +start_mosquitto + +echo "MOSQUITTO_SMOKE_STAGE basic-pub-sub" +# Test basic publish/subscribe +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/smoke -C 1 -W 5 > /var/lib/mosquitto/smoke-sub.out 2>&1 & +sub_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/smoke -m "hello-smoke" +wait "$sub_pid" || true +grep -q 'hello-smoke' /var/lib/mosquitto/smoke-sub.out + +echo "MOSQUITTO_SMOKE_STAGE multiple-topics" +# Test multiple topics +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/topic1 -C 1 -W 5 > /var/lib/mosquitto/smoke-topic1.out 2>&1 & +sub1_pid=$! +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/topic2 -C 1 -W 5 > /var/lib/mosquitto/smoke-topic2.out 2>&1 & +sub2_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/topic1 -m "msg1" +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/topic2 -m "msg2" +wait "$sub1_pid" || true +wait "$sub2_pid" || true +grep -q 'msg1' /var/lib/mosquitto/smoke-topic1.out +grep -q 'msg2' /var/lib/mosquitto/smoke-topic2.out + +echo "MOSQUITTO_SMOKE_STAGE wildcard-sub" +# Test wildcard subscription +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/wildcard/# -C 2 -W 5 > /var/lib/mosquitto/smoke-wildcard.out 2>&1 & +sub_wc_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/wildcard/a -m "wild-a" +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/wildcard/b -m "wild-b" +wait "$sub_wc_pid" || true +grep -q 'wild-a' /var/lib/mosquitto/smoke-wildcard.out +grep -q 'wild-b' /var/lib/mosquitto/smoke-wildcard.out + +echo "MOSQUITTO_SMOKE_STAGE qos-levels" +# Test QoS 0 +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/qos0 -q 0 -C 1 -W 5 > /var/lib/mosquitto/smoke-qos0.out 2>&1 & +sub_qos0_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/qos0 -q 0 -m "qos0-msg" +wait "$sub_qos0_pid" || true +grep -q 'qos0-msg' /var/lib/mosquitto/smoke-qos0.out + +# Test QoS 1 +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/qos1 -q 1 -C 1 -W 5 > /var/lib/mosquitto/smoke-qos1.out 2>&1 & +sub_qos1_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/qos1 -q 1 -m "qos1-msg" +wait "$sub_qos1_pid" || true +grep -q 'qos1-msg' /var/lib/mosquitto/smoke-qos1.out + +echo "MOSQUITTO_SMOKE_STAGE last-will-testament" +# Test Last Will and Testament - embedded devices use LWT to notify offline status +# Subscribe to LWT topic first +mosquitto_sub -h 127.0.0.1 -p 1883 -t devices/status -C 1 -W 10 > /var/lib/mosquitto/smoke-lwt.out 2>&1 & +sub_lwt_pid=$! +sleep 1 +# Start a client with LWT message set; must use SIGKILL (-9) to trigger LWT (clean disconnect won't) +mosquitto_sub -h 127.0.0.1 -p 1883 -t dummy -i "lwt-device" --will-topic devices/status --will-payload "device-offline" --will-qos 1 --will-retain -W 30 > /dev/null 2>&1 & +lwt_client_pid=$! +sleep 2 +# SIGKILL forces unexpected disconnect, which triggers the will message +kill -9 "$lwt_client_pid" 2>/dev/null || true +wait "$lwt_client_pid" 2>/dev/null || true +wait "$sub_lwt_pid" || true +grep -q 'device-offline' /var/lib/mosquitto/smoke-lwt.out + +echo "MOSQUITTO_SMOKE_STAGE keepalive" +# Test keep-alive - embedded devices need periodic ping to maintain connection +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/keepalive -C 1 -W 10 -k 5 > /var/lib/mosquitto/smoke-keepalive.out 2>&1 & +sub_ka_pid=$! +sleep 1 +# Client with 5s keep-alive sends pings automatically (minimum allowed) +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/keepalive -m "alive-msg" -i "keepalive-pub" -k 5 +wait "$sub_ka_pid" || true +grep -q 'alive-msg' /var/lib/mosquitto/smoke-keepalive.out + +echo "MOSQUITTO_SMOKE_STAGE sensor-data" +# Test typical embedded sensor data pattern (small JSON payloads) +mosquitto_sub -h 127.0.0.1 -p 1883 -t devices/sensor01/telemetry -C 3 -W 5 > /var/lib/mosquitto/smoke-sensor.out 2>&1 & +sub_sensor_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t devices/sensor01/telemetry -m '{"temp":22.5,"hum":65.2,"ts":1717000000}' +mosquitto_pub -h 127.0.0.1 -p 1883 -t devices/sensor01/telemetry -m '{"temp":22.6,"hum":65.0,"ts":1717000001}' +mosquitto_pub -h 127.0.0.1 -p 1883 -t devices/sensor01/telemetry -m '{"temp":22.4,"hum":65.5,"ts":1717000002}' +wait "$sub_sensor_pid" || true +grep -q '"temp":22.5' /var/lib/mosquitto/smoke-sensor.out +grep -q '"temp":22.6' /var/lib/mosquitto/smoke-sensor.out +grep -q '"temp":22.4' /var/lib/mosquitto/smoke-sensor.out + +test_done=1 +trap - EXIT +cleanup + +echo "MOSQUITTO_SMOKE_TEST_PASSED" diff --git a/apps/starry/mosquitto/mosquitto-stress-tests.sh b/apps/starry/mosquitto/mosquitto-stress-tests.sh new file mode 100755 index 0000000000..b55f003e1d --- /dev/null +++ b/apps/starry/mosquitto/mosquitto-stress-tests.sh @@ -0,0 +1,318 @@ +#!/bin/sh +set -eu + +mosquitto_pid="" +test_done=0 + +# Pre-cleanup: kill any leftover mosquitto server processes and stale temp files +# Use pidof for exact name match; pkill would also match this script's name "mosquitto-*" +for pid in $(pidof mosquitto 2>/dev/null); do + kill -9 "$pid" 2>/dev/null || true +done +rm -rf /var/lib/mosquitto/mosquitto* 2>/dev/null || true +sleep 1 + +start_mosquitto() { + config_file="$1" + + # Kill any existing mosquitto processes (handles auto-started instances) + for pid in $(pidof mosquitto 2>/dev/null); do + kill -9 "$pid" 2>/dev/null || true + done + sleep 2 + + mkdir -p /var/lib/mosquitto/mosquitto + chmod 777 /var/lib/mosquitto/mosquitto + cat > "$config_file" << 'EOF' +listener 1883 +socket_domain ipv4 +allow_anonymous true +persistence true +persistence_location /var/lib/mosquitto/mosquitto/ +log_dest stderr +log_type error +log_type warning +connection_messages true +max_inflight_messages 100 +max_queued_messages 10000 +EOF + + /usr/sbin/mosquitto -c "$config_file" > /var/lib/mosquitto/mosquitto-stress.log 2>&1 & + mosquitto_pid=$! + + i=0 + while [ "$i" -lt 30 ]; do + if mosquitto_pub -h 127.0.0.1 -p 1883 -t test/ping -m "ping" 2>/dev/null; then + return 0 + fi + i=$((i + 1)) + sleep 1 + done + + echo "=== mosquitto-stress.log ===" + cat /var/lib/mosquitto/mosquitto-stress.log + echo "MOSQUITTO_STRESS_TEST_FAILED" + exit 1 +} + +stop_mosquitto() { + if [ -n "$mosquitto_pid" ]; then + kill "$mosquitto_pid" >/dev/null 2>&1 || true + i=0 + while kill -0 "$mosquitto_pid" >/dev/null 2>&1 && [ "$i" -lt 10 ]; do + i=$((i + 1)) + sleep 1 + done + kill -9 "$mosquitto_pid" >/dev/null 2>&1 || true + wait "$mosquitto_pid" >/dev/null 2>&1 || true + mosquitto_pid="" + fi +} + +cleanup() { + stop_mosquitto + # Kill any remaining mosquitto processes (including stale ones) + for pid in $(pidof mosquitto 2>/dev/null); do + kill -9 "$pid" 2>/dev/null || true + done +} + +on_exit() { + rc=$? + if [ "$test_done" -ne 1 ]; then + echo "MOSQUITTO_STRESS_TEST_FAILED" + fi + cleanup + exit "$rc" +} +trap on_exit EXIT + +fail_with_file() { + path="$1" + echo "=== $path ===" + cat "$path" 2>/dev/null || true + echo "MOSQUITTO_STRESS_TEST_FAILED" + exit 1 +} + +run_publisher() { + client_id="$1" + topic="$2" + count="$3" + qos="$4" + + i=0 + while [ "$i" -lt "$count" ]; do + mosquitto_pub -h 127.0.0.1 -p 1883 -t "$topic" -m "stress-$client_id-$i" -q "$qos" -i "pub-$client_id" + i=$((i + 1)) + done +} + +run_subscriber() { + client_id="$1" + topic="$2" + count="$3" + qos="$4" + + mosquitto_sub -h 127.0.0.1 -p 1883 -t "$topic" -C "$count" -W 120 -q "$qos" -i "sub-$client_id" > "/var/lib/mosquitto/stress-sub-$client_id.out" 2>&1 +} + +echo "MOSQUITTO_STRESS_STAGE start" +start_mosquitto /var/lib/mosquitto/mosquitto-stress.conf + +stress_rounds=2 +stress_ops=50 + +round=0 +while [ "$round" -lt "$stress_rounds" ]; do + echo "MOSQUITTO_STRESS_STAGE round-$round-basic" + # Basic stress test with multiple messages + run_subscriber "basic-$round" "stress/basic/$round" "$stress_ops" 0 & + sub_basic_pid=$! + sleep 1 + run_publisher "basic-$round" "stress/basic/$round" "$stress_ops" 0 + wait "$sub_basic_pid" || fail_with_file "/var/lib/mosquitto/stress-sub-basic-$round.out" + + echo "MOSQUITTO_STRESS_STAGE round-$round-qos1" + # QoS 1 stress test + run_subscriber "qos1-$round" "stress/qos1/$round" "$stress_ops" 1 & + sub_qos1_pid=$! + sleep 1 + run_publisher "qos1-$round" "stress/qos1/$round" "$stress_ops" 1 + wait "$sub_qos1_pid" || fail_with_file "/var/lib/mosquitto/stress-sub-qos1-$round.out" + + echo "MOSQUITTO_STRESS_STAGE round-$round-multi-topic" + # Multiple topics stress test + topic_count=5 + msgs_per_topic=10 + total_msgs=$((topic_count * msgs_per_topic)) + mosquitto_sub -h 127.0.0.1 -p 1883 -t "stress/multi/$round/#" -C "$total_msgs" -W 120 -i "sub-multi-$round" > "/var/lib/mosquitto/stress-multi-$round.out" 2>&1 & + sub_multi_pid=$! + sleep 1 + t=0 + while [ "$t" -lt "$topic_count" ]; do + m=0 + while [ "$m" -lt "$msgs_per_topic" ]; do + mosquitto_pub -h 127.0.0.1 -p 1883 -t "stress/multi/$round/topic$t" -m "msg-$t-$m" -i "pub-multi-$round-$t" + m=$((m + 1)) + done + t=$((t + 1)) + done + wait "$sub_multi_pid" || fail_with_file "/var/lib/mosquitto/stress-multi-$round.out" + + round=$((round + 1)) +done + +echo "MOSQUITTO_STRESS_STAGE high-frequency" +# High frequency publish/subscribe +high_freq_count=100 +mosquitto_sub -h 127.0.0.1 -p 1883 -t "stress/highfreq" -C "$high_freq_count" -W 120 -i "sub-highfreq" > "/var/lib/mosquitto/stress-highfreq.out" 2>&1 & +sub_hf_pid=$! +sleep 1 +i=0 +while [ "$i" -lt "$high_freq_count" ]; do + mosquitto_pub -h 127.0.0.1 -p 1883 -t "stress/highfreq" -m "hf-$i" -i "pub-highfreq" + i=$((i + 1)) +done +wait "$sub_hf_pid" || fail_with_file "/var/lib/mosquitto/stress-highfreq.out" + +echo "MOSQUITTO_STRESS_STAGE concurrent-clients" +# Concurrent client stress test +concurrent_clients=5 +msgs_per_client=20 +total_concurrent_msgs=$((concurrent_clients * msgs_per_client)) +mosquitto_sub -h 127.0.0.1 -p 1883 -t "stress/concurrent/#" -C "$total_concurrent_msgs" -W 120 -i "sub-concurrent" > "/var/lib/mosquitto/stress-concurrent.out" 2>&1 & +sub_conc_pid=$! +sleep 1 +conc_pids="" +c=0 +while [ "$c" -lt "$concurrent_clients" ]; do + ( + m=0 + while [ "$m" -lt "$msgs_per_client" ]; do + mosquitto_pub -h 127.0.0.1 -p 1883 -t "stress/concurrent/client$c" -m "conc-$c-$m" -i "pub-conc-$c" + m=$((m + 1)) + done + ) & + conc_pids="$conc_pids $!" + c=$((c + 1)) +done +for pid in $conc_pids; do + wait "$pid" || true +done +wait "$sub_conc_pid" || fail_with_file "/var/lib/mosquitto/stress-concurrent.out" + +echo "MOSQUITTO_STRESS_STAGE large-messages" +# Large message stress test +large_msg=$(dd if=/dev/zero bs=4096 count=10 2>/dev/null | tr '\0' 'B') +large_count=10 +mosquitto_sub -h 127.0.0.1 -p 1883 -t "stress/large" -C "$large_count" -W 120 -i "sub-large" > "/var/lib/mosquitto/stress-large.out" 2>&1 & +sub_large_pid=$! +sleep 1 +i=0 +while [ "$i" -lt "$large_count" ]; do + mosquitto_pub -h 127.0.0.1 -p 1883 -t "stress/large" -m "$large_msg" -i "pub-large" + i=$((i + 1)) +done +wait "$sub_large_pid" || fail_with_file "/var/lib/mosquitto/stress-large.out" + +echo "MOSQUITTO_STRESS_STAGE wildcard-stress" +# Wildcard subscription stress test +wild_topics=10 +wild_msgs_per_topic=5 +wild_total=$((wild_topics * wild_msgs_per_topic)) +mosquitto_sub -h 127.0.0.1 -p 1883 -t "stress/wild/#" -C "$wild_total" -W 120 -i "sub-wild" > "/var/lib/mosquitto/stress-wild.out" 2>&1 & +sub_wild_pid=$! +sleep 1 +t=0 +while [ "$t" -lt "$wild_topics" ]; do + m=0 + while [ "$m" -lt "$wild_msgs_per_topic" ]; do + mosquitto_pub -h 127.0.0.1 -p 1883 -t "stress/wild/topic$t" -m "wild-$t-$m" -i "pub-wild-$t" + m=$((m + 1)) + done + t=$((t + 1)) +done +wait "$sub_wild_pid" || fail_with_file "/var/lib/mosquitto/stress-wild.out" + +echo "MOSQUITTO_STRESS_STAGE mixed-qos" +# Mixed QoS stress test +mixed_count=30 +mosquitto_sub -h 127.0.0.1 -p 1883 -t "stress/mixed" -C "$mixed_count" -W 120 -i "sub-mixed" > "/var/lib/mosquitto/stress-mixed.out" 2>&1 & +sub_mixed_pid=$! +sleep 1 +i=0 +while [ "$i" -lt "$mixed_count" ]; do + qos=$((i % 3)) + mosquitto_pub -h 127.0.0.1 -p 1883 -t "stress/mixed" -q "$qos" -m "mixed-qos$qos-$i" -i "pub-mixed" + i=$((i + 1)) +done +wait "$sub_mixed_pid" || fail_with_file "/var/lib/mosquitto/stress-mixed.out" + +echo "MOSQUITTO_STRESS_STAGE persistence-restart" +# Test persistence across restart +mosquitto_pub -h 127.0.0.1 -p 1883 -t "stress/persist" -m "persist-value" -r -i "pub-persist" +sleep 2 +stop_mosquitto +start_mosquitto /var/lib/mosquitto/mosquitto-stress.conf +sleep 2 +mosquitto_sub -h 127.0.0.1 -p 1883 -t "stress/persist" -C 1 -W 10 -i "sub-persist" > "/var/lib/mosquitto/stress-persist.out" 2>&1 & +sub_persist_pid=$! +wait "$sub_persist_pid" || fail_with_file "/var/lib/mosquitto/stress-persist.out" +grep -q 'persist-value' /var/lib/mosquitto/stress-persist.out + +echo "MOSQUITTO_STRESS_STAGE embedded-burst" +# Embedded sensor burst stress - many devices sending small readings simultaneously +embedded_count=20 +embedded_msgs_per_device=10 +embedded_total=$((embedded_count * embedded_msgs_per_device)) +mosquitto_sub -h 127.0.0.1 -p 1883 -t "stress/embedded/+/telemetry" -C "$embedded_total" -W 120 -i "sub-embedded" > "/var/lib/mosquitto/stress-embedded.out" 2>&1 & +sub_embed_pid=$! +sleep 1 +embed_pids="" +d=0 +while [ "$d" -lt "$embedded_count" ]; do + ( + m=0 + while [ "$m" -lt "$embedded_msgs_per_device" ]; do + temp=$((2000 + m * 5)) + mosquitto_pub -h 127.0.0.1 -p 1883 -t "stress/embedded/dev$d/telemetry" -m "{\"dev\":$d,\"temp\":$temp}" -i "pub-embedded-$d" -q 0 + m=$((m + 1)) + done + ) & + embed_pids="$embed_pids $!" + d=$((d + 1)) +done +for pid in $embed_pids; do + wait "$pid" || true +done +wait "$sub_embed_pid" || fail_with_file "/var/lib/mosquitto/stress-embedded.out" + +echo "MOSQUITTO_STRESS_STAGE lwt-storm" +# LWT storm - simulate many devices going offline simultaneously +mosquitto_sub -h 127.0.0.1 -p 1883 -t "stress/lwt/status" -C "$embedded_count" -W 120 -i "sub-lwt-storm" > "/var/lib/mosquitto/stress-lwt-storm.out" 2>&1 & +sub_lwt_pid=$! +sleep 1 +# Start many clients with LWT messages +lwt_pids="" +d=0 +while [ "$d" -lt "$embedded_count" ]; do + mosquitto_sub -h 127.0.0.1 -p 1883 -t dummy -i "lwt-dev-$d" --will-topic "stress/lwt/status" --will-payload "dev-$d-offline" --will-qos 0 -W 120 > /dev/null 2>&1 & + lwt_pids="$lwt_pids $!" + d=$((d + 1)) +done +sleep 2 +# SIGKILL all LWT clients to trigger will messages (clean disconnect won't trigger LWT) +for pid in $lwt_pids; do + kill -9 "$pid" 2>/dev/null || true +done +for pid in $lwt_pids; do + wait "$pid" 2>/dev/null || true +done +wait "$sub_lwt_pid" || fail_with_file "/var/lib/mosquitto/stress-lwt-storm.out" + +test_done=1 +trap - EXIT +cleanup + +echo "MOSQUITTO_STRESS_TEST_PASSED" diff --git a/apps/starry/mosquitto/mosquitto-tests.sh b/apps/starry/mosquitto/mosquitto-tests.sh new file mode 100755 index 0000000000..25a615f6b6 --- /dev/null +++ b/apps/starry/mosquitto/mosquitto-tests.sh @@ -0,0 +1,326 @@ +#!/bin/sh +set -eu + +mosquitto_pid="" +auth_pid="" +test_done=0 + +# Pre-cleanup: kill any leftover mosquitto server processes and stale temp files +# Use pidof for exact name match; pkill would also match this script's name "mosquitto-*" +for pid in $(pidof mosquitto 2>/dev/null); do + kill -9 "$pid" 2>/dev/null || true +done +rm -rf /var/lib/mosquitto/mosquitto* 2>/dev/null || true +sleep 1 + +start_mosquitto() { + config_file="$1" + + # Kill any existing mosquitto processes (handles auto-started instances) + for pid in $(pidof mosquitto 2>/dev/null); do + kill -9 "$pid" 2>/dev/null || true + done + sleep 2 + + mkdir -p /var/lib/mosquitto/mosquitto + chmod 777 /var/lib/mosquitto/mosquitto + cat > "$config_file" << 'EOF' +listener 1883 +socket_domain ipv4 +allow_anonymous true +persistence true +persistence_location /var/lib/mosquitto/mosquitto/ +log_dest stderr +log_type error +log_type warning +log_type notice +log_type information +connection_messages true +max_inflight_messages 20 +max_queued_messages 1000 +EOF + + /usr/sbin/mosquitto -c "$config_file" > /var/lib/mosquitto/mosquitto.log 2>&1 & + mosquitto_pid=$! + + i=0 + while [ "$i" -lt 30 ]; do + if mosquitto_pub -h 127.0.0.1 -p 1883 -t test/ping -m "ping" 2>/dev/null; then + return 0 + fi + i=$((i + 1)) + sleep 1 + done + + echo "=== mosquitto.log ===" + cat /var/lib/mosquitto/mosquitto.log + echo "MOSQUITTO_TEST_FAILED" + exit 1 +} + +stop_mosquitto() { + if [ -n "$mosquitto_pid" ]; then + kill "$mosquitto_pid" >/dev/null 2>&1 || true + i=0 + while kill -0 "$mosquitto_pid" >/dev/null 2>&1 && [ "$i" -lt 10 ]; do + i=$((i + 1)) + sleep 1 + done + kill -9 "$mosquitto_pid" >/dev/null 2>&1 || true + wait "$mosquitto_pid" >/dev/null 2>&1 || true + mosquitto_pid="" + fi +} + +stop_auth_mosquitto() { + if [ -n "$auth_pid" ]; then + kill "$auth_pid" >/dev/null 2>&1 || true + wait "$auth_pid" >/dev/null 2>&1 || true + auth_pid="" + fi +} + +cleanup() { + stop_auth_mosquitto + stop_mosquitto + # Kill any remaining mosquitto processes (including stale ones) + for pid in $(pidof mosquitto 2>/dev/null); do + kill -9 "$pid" 2>/dev/null || true + done +} + +on_exit() { + rc=$? + if [ "$test_done" -ne 1 ]; then + echo "MOSQUITTO_TEST_FAILED" + fi + cleanup + exit "$rc" +} +trap on_exit EXIT + +fail_with_file() { + path="$1" + echo "=== $path ===" + cat "$path" 2>/dev/null || true + echo "MOSQUITTO_TEST_FAILED" + exit 1 +} + +echo "MOSQUITTO_STAGE start" +start_mosquitto /var/lib/mosquitto/mosquitto-test.conf + +echo "MOSQUITTO_STAGE basic-pub-sub" +# Test basic publish/subscribe +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/basic -C 1 -W 5 > /var/lib/mosquitto/basic-sub.out 2>&1 & +sub_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/basic -m "hello-mosquitto" +wait "$sub_pid" || true +grep -q 'hello-mosquitto' /var/lib/mosquitto/basic-sub.out + +echo "MOSQUITTO_STAGE multiple-messages" +# Test multiple messages +msg_count=10 +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/multi -C "$msg_count" -W 10 > /var/lib/mosquitto/multi-sub.out 2>&1 & +sub_multi_pid=$! +sleep 1 +i=0 +while [ "$i" -lt "$msg_count" ]; do + mosquitto_pub -h 127.0.0.1 -p 1883 -t test/multi -m "message-$i" + i=$((i + 1)) +done +wait "$sub_multi_pid" || true +i=0 +while [ "$i" -lt "$msg_count" ]; do + grep -q "message-$i" /var/lib/mosquitto/multi-sub.out + i=$((i + 1)) +done + +echo "MOSQUITTO_STAGE wildcard-topics" +# Test wildcard subscriptions +mosquitto_sub -h 127.0.0.1 -p 1883 -t sensor/+/temperature -C 3 -W 5 > /var/lib/mosquitto/wildcard-sub.out 2>&1 & +sub_wc_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t sensor/room1/temperature -m "22.5" +mosquitto_pub -h 127.0.0.1 -p 1883 -t sensor/room2/temperature -m "23.1" +mosquitto_pub -h 127.0.0.1 -p 1883 -t sensor/room3/temperature -m "21.8" +wait "$sub_wc_pid" || true +grep -q '22.5' /var/lib/mosquitto/wildcard-sub.out +grep -q '23.1' /var/lib/mosquitto/wildcard-sub.out +grep -q '21.8' /var/lib/mosquitto/wildcard-sub.out + +echo "MOSQUITTO_STAGE qos-levels" +# Test QoS 0 +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/qos0 -q 0 -C 1 -W 5 > /var/lib/mosquitto/qos0-sub.out 2>&1 & +sub_qos0_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/qos0 -q 0 -m "qos0-message" +wait "$sub_qos0_pid" || true +grep -q 'qos0-message' /var/lib/mosquitto/qos0-sub.out + +# Test QoS 1 +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/qos1 -q 1 -C 1 -W 5 > /var/lib/mosquitto/qos1-sub.out 2>&1 & +sub_qos1_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/qos1 -q 1 -m "qos1-message" +wait "$sub_qos1_pid" || true +grep -q 'qos1-message' /var/lib/mosquitto/qos1-sub.out + +# Test QoS 2 +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/qos2 -q 2 -C 1 -W 5 > /var/lib/mosquitto/qos2-sub.out 2>&1 & +sub_qos2_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/qos2 -q 2 -m "qos2-message" +wait "$sub_qos2_pid" || true +grep -q 'qos2-message' /var/lib/mosquitto/qos2-sub.out + +echo "MOSQUITTO_STAGE retained-messages" +# Test retained messages +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/retained -m "retained-msg" -r +sleep 1 +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/retained -C 1 -W 5 > /var/lib/mosquitto/retained-sub.out 2>&1 & +sub_ret_pid=$! +wait "$sub_ret_pid" || true +grep -q 'retained-msg' /var/lib/mosquitto/retained-sub.out + +echo "MOSQUITTO_STAGE persistent-session" +# Test persistent session +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/session -i "client-session" -c -q 1 -C 1 -W 5 > /var/lib/mosquitto/session-sub.out 2>&1 & +sub_sess_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/session -q 1 -m "session-msg" +wait "$sub_sess_pid" || true +grep -q 'session-msg' /var/lib/mosquitto/session-sub.out + +echo "MOSQUITTO_STAGE large-payload" +# Test large payload +large_msg=$(dd if=/dev/zero bs=1024 count=10 2>/dev/null | tr '\0' 'A') +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/large -C 1 -W 5 > /var/lib/mosquitto/large-sub.out 2>&1 & +sub_large_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/large -m "$large_msg" +wait "$sub_large_pid" || true +grep -q 'AAAAAAAAAAAAAAAA' /var/lib/mosquitto/large-sub.out + +echo "MOSQUITTO_STAGE multiple-clients" +# Test multiple clients +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/client1 -C 1 -W 5 > /var/lib/mosquitto/client1-sub.out 2>&1 & +sub_client1_pid=$! +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/client2 -C 1 -W 5 > /var/lib/mosquitto/client2-sub.out 2>&1 & +sub_client2_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/client1 -m "msg-for-client1" +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/client2 -m "msg-for-client2" +wait "$sub_client1_pid" || true +wait "$sub_client2_pid" || true +grep -q 'msg-for-client1' /var/lib/mosquitto/client1-sub.out +grep -q 'msg-for-client2' /var/lib/mosquitto/client2-sub.out + +echo "MOSQUITTO_STAGE topic-escaping" +# Test topic escaping +mosquitto_sub -h 127.0.0.1 -p 1883 -t 'test/special/chars' -C 1 -W 5 > /var/lib/mosquitto/special-sub.out 2>&1 & +sub_special_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t 'test/special/chars' -m "special-msg" +wait "$sub_special_pid" || true +grep -q 'special-msg' /var/lib/mosquitto/special-sub.out + +echo "MOSQUITTO_STAGE last-will-testament" +# Test Last Will and Testament - critical for embedded device offline detection +mosquitto_sub -h 127.0.0.1 -p 1883 -t devices/gateway/status -C 1 -W 10 > /var/lib/mosquitto/lwt-sub.out 2>&1 & +sub_lwt_pid=$! +sleep 1 +# Start client with LWT; SIGKILL required to trigger will (clean disconnect won't) +mosquitto_sub -h 127.0.0.1 -p 1883 -t dummy -i "lwt-gw" --will-topic devices/gateway/status --will-payload '{"state":"offline","reason":"unexpected"}' --will-qos 1 --will-retain -W 30 > /dev/null 2>&1 & +lwt_pid=$! +sleep 2 +kill -9 "$lwt_pid" 2>/dev/null || true +wait "$lwt_pid" 2>/dev/null || true +wait "$sub_lwt_pid" || true +grep -q 'offline' /var/lib/mosquitto/lwt-sub.out + +echo "MOSQUITTO_STAGE authentication" +# Test username/password authentication - production embedded devices need auth +mkdir -p /var/lib/mosquitto/mosquitto +# mosquitto 2.x requires hashed password file +mosquitto_passwd -b -c /var/lib/mosquitto/mosquitto/passwd testuser testpass 2>/dev/null +chmod 644 /var/lib/mosquitto/mosquitto/passwd +cat > /var/lib/mosquitto/mosquitto-auth.conf << 'EOF' +listener 1884 +socket_domain ipv4 +allow_anonymous false +password_file /var/lib/mosquitto/mosquitto/passwd +persistence false +log_dest stderr +log_type error +EOF + +/usr/sbin/mosquitto -c /var/lib/mosquitto/mosquitto-auth.conf > /var/lib/mosquitto/mosquitto-auth.log 2>&1 & +auth_pid=$! +sleep 2 +# Test auth with correct credentials +mosquitto_sub -h 127.0.0.1 -p 1884 -t test/auth -C 1 -W 5 -u testuser -P testpass > /var/lib/mosquitto/auth-sub.out 2>&1 & +sub_auth_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1884 -t test/auth -m "auth-ok" -u testuser -P testpass +wait "$sub_auth_pid" || true +grep -q 'auth-ok' /var/lib/mosquitto/auth-sub.out +kill "$auth_pid" 2>/dev/null || true +wait "$auth_pid" 2>/dev/null || true + +echo "MOSQUITTO_STAGE keepalive-reconnect" +# Test keep-alive with reconnection - embedded devices often reconnect after disconnect +mosquitto_sub -h 127.0.0.1 -p 1883 -t test/keepalive -C 2 -W 15 -k 5 > /var/lib/mosquitto/keepalive-sub.out 2>&1 & +sub_ka_pid=$! +sleep 1 +# First message with keep-alive +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/keepalive -m "ka-msg1" -i "ka-pub" -k 5 +sleep 6 +# Second message after keep-alive interval (connection maintained by ping) +mosquitto_pub -h 127.0.0.1 -p 1883 -t test/keepalive -m "ka-msg2" -i "ka-pub" -k 5 +wait "$sub_ka_pid" || true +grep -q 'ka-msg1' /var/lib/mosquitto/keepalive-sub.out +grep -q 'ka-msg2' /var/lib/mosquitto/keepalive-sub.out + +echo "MOSQUITTO_STAGE device-hierarchy" +# Test device topic hierarchy - standard IoT pattern: devices/{id}/telemetry, devices/{id}/commands +mosquitto_sub -h 127.0.0.1 -p 1883 -t devices/+/telemetry -C 3 -W 5 > /var/lib/mosquitto/device-telemetry.out 2>&1 & +sub_dev_pid=$! +mosquitto_sub -h 127.0.0.1 -p 1883 -t devices/actuator01/commands -C 1 -W 5 > /var/lib/mosquitto/device-cmd.out 2>&1 & +sub_cmd_pid=$! +sleep 1 +mosquitto_pub -h 127.0.0.1 -p 1883 -t devices/sensor01/telemetry -m '{"temp":21.5}' +mosquitto_pub -h 127.0.0.1 -p 1883 -t devices/sensor02/telemetry -m '{"temp":23.1}' +mosquitto_pub -h 127.0.0.1 -p 1883 -t devices/sensor03/telemetry -m '{"temp":19.8}' +mosquitto_pub -h 127.0.0.1 -p 1883 -t devices/actuator01/commands -m '{"action":"on"}' +wait "$sub_dev_pid" || true +wait "$sub_cmd_pid" || true +grep -q '21.5' /var/lib/mosquitto/device-telemetry.out +grep -q '23.1' /var/lib/mosquitto/device-telemetry.out +grep -q '19.8' /var/lib/mosquitto/device-telemetry.out +grep -q 'on' /var/lib/mosquitto/device-cmd.out + +echo "MOSQUITTO_STAGE small-payload-burst" +# Test small payload burst - typical embedded sensor reporting pattern +# 50 tiny messages (temperature readings), simulating a sensor reporting every 200ms +burst_count=50 +mosquitto_sub -h 127.0.0.1 -p 1883 -t sensors/temp -C "$burst_count" -W 15 > /var/lib/mosquitto/burst-sub.out 2>&1 & +sub_burst_pid=$! +sleep 1 +i=0 +while [ "$i" -lt "$burst_count" ]; do + temp=$((2000 + i)) # 20.00 + i*0.01 degrees + mosquitto_pub -h 127.0.0.1 -p 1883 -t sensors/temp -m "${temp}" -q 0 + i=$((i + 1)) +done +wait "$sub_burst_pid" || true +# Verify first and last readings received +grep -q '2000' /var/lib/mosquitto/burst-sub.out +grep -q '2049' /var/lib/mosquitto/burst-sub.out + +test_done=1 +trap - EXIT +cleanup + +echo "MOSQUITTO_TEST_PASSED" diff --git a/apps/starry/mosquitto/prebuild.sh b/apps/starry/mosquitto/prebuild.sh new file mode 100755 index 0000000000..e68f4adab1 --- /dev/null +++ b/apps/starry/mosquitto/prebuild.sh @@ -0,0 +1,151 @@ +#!/usr/bin/env bash +set -euo pipefail + +app_dir="${STARRY_APP_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}" +base_rootfs="${STARRY_BASE_ROOTFS:-}" +staging_root="${STARRY_STAGING_ROOT:-}" +overlay_dir="${STARRY_OVERLAY_DIR:-}" +apk_cache="${STARRY_WORKSPACE:-$(cd "$app_dir/../../.." && pwd)}/target/mosquitto-apk-cache" + +require_env() { + local name="$1" + local value="$2" + if [[ -z "$value" ]]; then + echo "error: $name is required" >&2 + exit 1 + fi +} + +ensure_host_packages() { + local missing=() + + command -v apk >/dev/null 2>&1 || missing+=(apk-tools) + command -v debugfs >/dev/null 2>&1 || missing+=(e2fsprogs) + command -v install >/dev/null 2>&1 || missing+=(coreutils) + command -v readelf >/dev/null 2>&1 || missing+=(binutils) + + if [[ ${#missing[@]} -eq 0 ]]; then + return + fi + + if ! command -v apt-get >/dev/null 2>&1; then + echo "error: missing required host packages and apt-get is unavailable: ${missing[*]}" >&2 + exit 1 + fi + + echo "installing missing host packages: ${missing[*]}" + apt-get update + apt-get install -y --no-install-recommends "${missing[@]}" +} + +extract_base_rootfs() { + debugfs -R "rdump / $staging_root" "$base_rootfs" +} + +install_mosquitto_package() { + mkdir -p "$apk_cache" + apk --root "$staging_root" \ + --cache-dir "$apk_cache" \ + --update-cache \ + --no-progress \ + --no-scripts \ + add mosquitto mosquitto-clients +} + +copy_file_to_overlay() { + local guest_path="$1" + local mode="$2" + local source="$staging_root${guest_path}" + local target="$overlay_dir${guest_path}" + + if [[ ! -e "$source" ]]; then + echo "error: missing guest file after Mosquitto package install: $guest_path" >&2 + exit 1 + fi + + if [[ -L "$source" ]]; then + source="$(readlink -f "$source")" + fi + + install -Dm"$mode" "$source" "$target" +} + +find_library_path() { + local library="$1" + local dir + + for dir in lib usr/lib usr/local/lib; do + if [[ -e "$staging_root/$dir/$library" ]]; then + printf '/%s/%s\n' "$dir" "$library" + return 0 + fi + done + + return 1 +} + +copy_runtime_dependencies() { + local pending=("$@") + local seen=" " + local guest_path library + + while [[ ${#pending[@]} -gt 0 ]]; do + guest_path="${pending[0]}" + pending=("${pending[@]:1}") + + if [[ "$seen" == *" $guest_path "* ]]; then + continue + fi + seen+="$guest_path " + + while IFS= read -r library; do + local library_path + if ! library_path="$(find_library_path "$library")"; then + continue + fi + copy_file_to_overlay "$library_path" 0644 + pending+=("$library_path") + done < <( + readelf -d "$staging_root$guest_path" 2>/dev/null | + sed -n 's/.*Shared library: \[\(.*\)\].*/\1/p' + ) + done +} + +populate_overlay() { + copy_file_to_overlay /usr/sbin/mosquitto 0755 + copy_file_to_overlay /usr/bin/mosquitto_pub 0755 + copy_file_to_overlay /usr/bin/mosquitto_sub 0755 + copy_file_to_overlay /usr/bin/mosquitto_passwd 0755 + copy_runtime_dependencies /usr/sbin/mosquitto /usr/bin/mosquitto_pub /usr/bin/mosquitto_sub /usr/bin/mosquitto_passwd + + install -Dm0755 "$app_dir/test_mosquitto.sh" "$overlay_dir/usr/bin/test_mosquitto.sh" + install -Dm0755 "$app_dir/mosquitto-smoke-tests.sh" "$overlay_dir/usr/bin/mosquitto-smoke-tests.sh" + install -Dm0755 "$app_dir/mosquitto-tests.sh" "$overlay_dir/usr/bin/mosquitto-tests.sh" + install -Dm0755 "$app_dir/mosquitto-stress-tests.sh" "$overlay_dir/usr/bin/mosquitto-stress-tests.sh" + + # Create default config directory + mkdir -p "$overlay_dir/etc/mosquitto" + cat > "$overlay_dir/etc/mosquitto/mosquitto.conf" << 'EOF' +listener 1883 +socket_domain ipv4 +allow_anonymous true +persistence true +persistence_location /var/lib/mosquitto/ +log_dest stderr +log_type error +log_type warning +log_type notice +log_type information +connection_messages true +EOF +} + +require_env STARRY_BASE_ROOTFS "$base_rootfs" +require_env STARRY_STAGING_ROOT "$staging_root" +require_env STARRY_OVERLAY_DIR "$overlay_dir" + +ensure_host_packages +extract_base_rootfs +install_mosquitto_package +populate_overlay diff --git a/apps/starry/mosquitto/qemu-x86_64-normal.toml b/apps/starry/mosquitto/qemu-x86_64-normal.toml new file mode 100644 index 0000000000..0dd75d4d4a --- /dev/null +++ b/apps/starry/mosquitto/qemu-x86_64-normal.toml @@ -0,0 +1,23 @@ +args = [ + "-machine", + "q35", + "-nographic", + "-m", + "1G", + "-device", + "virtio-blk-pci,drive=disk0", + "-drive", + "id=disk0,if=none,format=raw,file=${workspace}/tmp/axbuild/rootfs/rootfs-x86_64-alpine.img", + "-device", + "virtio-net-pci,netdev=net0", + "-netdev", + "user,id=net0", + "-snapshot", +] +uefi = false +to_bin = false +shell_prefix = "root@starry:" +shell_init_cmd = "/usr/bin/mosquitto-tests.sh" +success_regex = ["(?m)^MOSQUITTO_TEST_PASSED\\s*$"] +fail_regex = ['(?i)\\bpanic(?:ked)?\\b', "(?m)^MOSQUITTO_TEST_FAILED\\s*$"] +timeout = 3600 diff --git a/apps/starry/mosquitto/qemu-x86_64-smoke.toml b/apps/starry/mosquitto/qemu-x86_64-smoke.toml new file mode 100644 index 0000000000..ab95b4fec0 --- /dev/null +++ b/apps/starry/mosquitto/qemu-x86_64-smoke.toml @@ -0,0 +1,23 @@ +args = [ + "-machine", + "q35", + "-nographic", + "-m", + "1G", + "-device", + "virtio-blk-pci,drive=disk0", + "-drive", + "id=disk0,if=none,format=raw,file=${workspace}/tmp/axbuild/rootfs/rootfs-x86_64-alpine.img", + "-device", + "virtio-net-pci,netdev=net0", + "-netdev", + "user,id=net0", + "-snapshot", +] +uefi = false +to_bin = false +shell_prefix = "root@starry:" +shell_init_cmd = "/usr/bin/mosquitto-smoke-tests.sh" +success_regex = ["(?m)^MOSQUITTO_SMOKE_TEST_PASSED\\s*$"] +fail_regex = ['(?i)\\bpanic(?:ked)?\\b', "(?m)^MOSQUITTO_SMOKE_TEST_FAILED\\s*$"] +timeout = 3600 diff --git a/apps/starry/mosquitto/qemu-x86_64-stress.toml b/apps/starry/mosquitto/qemu-x86_64-stress.toml new file mode 100644 index 0000000000..6606bf4454 --- /dev/null +++ b/apps/starry/mosquitto/qemu-x86_64-stress.toml @@ -0,0 +1,23 @@ +args = [ + "-machine", + "q35", + "-nographic", + "-m", + "1G", + "-device", + "virtio-blk-pci,drive=disk0", + "-drive", + "id=disk0,if=none,format=raw,file=${workspace}/tmp/axbuild/rootfs/rootfs-x86_64-alpine.img", + "-device", + "virtio-net-pci,netdev=net0", + "-netdev", + "user,id=net0", + "-snapshot", +] +uefi = false +to_bin = false +shell_prefix = "root@starry:" +shell_init_cmd = "/bin/sh /usr/bin/mosquitto-stress-tests.sh" +success_regex = ["(?m)^MOSQUITTO_STRESS_TEST_PASSED\\s*$"] +fail_regex = ['(?i)\\bpanic(?:ked)?\\b', "(?m)^MOSQUITTO_STRESS_TEST_FAILED\\s*$"] +timeout = 3600 diff --git a/apps/starry/mosquitto/qemu-x86_64.toml b/apps/starry/mosquitto/qemu-x86_64.toml new file mode 100644 index 0000000000..f11fc701e7 --- /dev/null +++ b/apps/starry/mosquitto/qemu-x86_64.toml @@ -0,0 +1,28 @@ +args = [ + "-machine", + "q35", + "-nographic", + "-m", + "1G", + "-device", + "virtio-blk-pci,drive=disk0", + "-drive", + "id=disk0,if=none,format=raw,file=${workspace}/tmp/axbuild/rootfs/rootfs-x86_64-alpine.img", + "-device", + "virtio-net-pci,netdev=net0", + "-netdev", + "user,id=net0", + "-snapshot", +] +uefi = false +to_bin = false +shell_prefix = "root@starry:" +shell_init_cmd = "/usr/bin/test_mosquitto.sh" +success_regex = ["(?m)^ALL MOSQUITTO TESTS PASSED\\s*$"] +fail_regex = [ + "(?i)\\bpanic(?:ked)?\\b", + "(?m)^MOSQUITTO_SMOKE_TEST_FAILED\\s*$", + "(?m)^MOSQUITTO_TEST_FAILED\\s*$", + "(?m)^MOSQUITTO_STRESS_TEST_FAILED\\s*$", +] +timeout = 3600 diff --git a/apps/starry/mosquitto/test_mosquitto.sh b/apps/starry/mosquitto/test_mosquitto.sh new file mode 100644 index 0000000000..3d57ec6e6d --- /dev/null +++ b/apps/starry/mosquitto/test_mosquitto.sh @@ -0,0 +1,16 @@ +#!/bin/sh +set -eu + +# Unified entry point: runs all three test levels sequentially. +# Individual scripts can still be run separately via --qemu-config. + +echo "===== 1. SMOKE =====" +/bin/sh /usr/bin/mosquitto-smoke-tests.sh + +echo "===== 2. NORMAL =====" +/bin/sh /usr/bin/mosquitto-tests.sh + +echo "===== 3. STRESS =====" +/bin/sh /usr/bin/mosquitto-stress-tests.sh + +echo "ALL MOSQUITTO TESTS PASSED"