|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +# wolfMQTT Broker test |
| 4 | +# Tests the wolfMQTT broker with pub/sub, retained messages, LWT, QoS 1, |
| 5 | +# client ID takeover, and multi-client pairs. |
| 6 | + |
| 7 | +name="MQTT Broker" |
| 8 | +broker_bin="src/mqtt_broker" |
| 9 | +pub_bin="examples/pub-sub/mqtt-pub" |
| 10 | +sub_bin="examples/pub-sub/mqtt-sub" |
| 11 | +no_pid=-1 |
| 12 | +broker_pid=$no_pid |
| 13 | + |
| 14 | +do_cleanup() { |
| 15 | + if [ $broker_pid != $no_pid ]; then |
| 16 | + kill -9 $broker_pid 2>/dev/null |
| 17 | + echo "Killed broker PID $broker_pid" |
| 18 | + broker_pid=$no_pid |
| 19 | + fi |
| 20 | + # Kill any lingering test processes |
| 21 | + for pid in "${TEST_PIDS[@]:-}"; do |
| 22 | + kill "$pid" 2>/dev/null || true |
| 23 | + done |
| 24 | + wait 2>/dev/null || true |
| 25 | + if [ -n "${TMP_DIR:-}" ] && [ -d "${TMP_DIR}" ]; then |
| 26 | + if [ "${KEEP_LOGS:-0}" = "1" ]; then |
| 27 | + echo "Logs preserved in ${TMP_DIR}" |
| 28 | + else |
| 29 | + rm -rf "${TMP_DIR}" |
| 30 | + fi |
| 31 | + fi |
| 32 | + if [ $1 -ne 0 ]; then |
| 33 | + exit 1 |
| 34 | + fi |
| 35 | +} |
| 36 | + |
| 37 | +# Check for broker binary |
| 38 | +[ ! -x ./$broker_bin ] && echo -e "\n\n$broker_bin doesn't exist" && exit 1 |
| 39 | + |
| 40 | +# Check for pub/sub binaries (needed for multi-client test) |
| 41 | +has_pubsub=no |
| 42 | +if [ -x ./$pub_bin ] && [ -x ./$sub_bin ]; then |
| 43 | + has_pubsub=yes |
| 44 | +fi |
| 45 | + |
| 46 | +# Generate a random port |
| 47 | +generate_port() { |
| 48 | + if [[ "$OSTYPE" == "linux"* ]]; then |
| 49 | + port=$(($(od -An -N2 /dev/urandom) % (65535-49152) + 49152)) |
| 50 | + elif [[ "$OSTYPE" == "darwin"* ]]; then |
| 51 | + port=$(($(od -An -N2 /dev/random) % (65535-49152) + 49152)) |
| 52 | + else |
| 53 | + port=11883 |
| 54 | + fi |
| 55 | + echo "Using port $port" |
| 56 | +} |
| 57 | + |
| 58 | +check_broker() { |
| 59 | + timeout 10 sh -c 'until nc -v -z $0 $1; do sleep 1; done' localhost $port |
| 60 | +} |
| 61 | + |
| 62 | +generate_port |
| 63 | + |
| 64 | +TEST_PIDS=() |
| 65 | +TMP_DIR="$(mktemp -d)" |
| 66 | +FAIL=0 |
| 67 | + |
| 68 | +echo "=== wolfMQTT Broker Test Suite ===" |
| 69 | + |
| 70 | +# Start broker |
| 71 | +./$broker_bin -p $port & |
| 72 | +broker_pid=$! |
| 73 | +echo "Broker PID is $broker_pid" |
| 74 | +check_broker |
| 75 | + |
| 76 | +# --- Test 1: Basic pub/sub with mosquitto_pub/mosquitto_sub --- |
| 77 | +echo "" |
| 78 | +echo "--- Test 1: Basic pub/sub ---" |
| 79 | +if command -v mosquitto_sub >/dev/null 2>&1 && command -v mosquitto_pub >/dev/null 2>&1; then |
| 80 | + mosquitto_sub -h 127.0.0.1 -p $port -t "test/hello" -C 1 -W 5 >"${TMP_DIR}/t1_sub.log" 2>&1 & |
| 81 | + T1_PID=$! |
| 82 | + sleep 1 |
| 83 | + mosquitto_pub -h 127.0.0.1 -p $port -t "test/hello" -m "world" |
| 84 | + wait $T1_PID 2>/dev/null |
| 85 | + if grep -q "world" "${TMP_DIR}/t1_sub.log" 2>/dev/null; then |
| 86 | + echo "PASS: Basic pub/sub" |
| 87 | + else |
| 88 | + echo "FAIL: Basic pub/sub" |
| 89 | + FAIL=1 |
| 90 | + fi |
| 91 | +else |
| 92 | + echo "SKIP: mosquitto_pub/mosquitto_sub not found" |
| 93 | +fi |
| 94 | + |
| 95 | +# --- Test 2: Retained messages --- |
| 96 | +echo "" |
| 97 | +echo "--- Test 2: Retained messages ---" |
| 98 | +if command -v mosquitto_sub >/dev/null 2>&1 && command -v mosquitto_pub >/dev/null 2>&1; then |
| 99 | + mosquitto_pub -h 127.0.0.1 -p $port -t "test/retained" -m "stored_msg" -r |
| 100 | + sleep 1 |
| 101 | + mosquitto_sub -h 127.0.0.1 -p $port -t "test/retained" -C 1 -W 5 >"${TMP_DIR}/t2_sub.log" 2>&1 |
| 102 | + if grep -q "stored_msg" "${TMP_DIR}/t2_sub.log" 2>/dev/null; then |
| 103 | + echo "PASS: Retained message delivered on subscribe" |
| 104 | + else |
| 105 | + echo "FAIL: Retained message not delivered" |
| 106 | + FAIL=1 |
| 107 | + fi |
| 108 | +else |
| 109 | + echo "SKIP: mosquitto_pub/mosquitto_sub not found" |
| 110 | +fi |
| 111 | + |
| 112 | +# --- Test 3: QoS 1 forwarding --- |
| 113 | +echo "" |
| 114 | +echo "--- Test 3: QoS 1 forwarding ---" |
| 115 | +if command -v mosquitto_sub >/dev/null 2>&1 && command -v mosquitto_pub >/dev/null 2>&1; then |
| 116 | + mosquitto_sub -h 127.0.0.1 -p $port -t "test/qos1" -q 1 -C 1 -W 5 >"${TMP_DIR}/t3_sub.log" 2>&1 & |
| 117 | + T3_PID=$! |
| 118 | + sleep 1 |
| 119 | + mosquitto_pub -h 127.0.0.1 -p $port -t "test/qos1" -m "qos1_msg" -q 1 |
| 120 | + wait $T3_PID 2>/dev/null |
| 121 | + if grep -q "qos1_msg" "${TMP_DIR}/t3_sub.log" 2>/dev/null; then |
| 122 | + echo "PASS: QoS 1 forwarding" |
| 123 | + else |
| 124 | + echo "FAIL: QoS 1 forwarding" |
| 125 | + FAIL=1 |
| 126 | + fi |
| 127 | +else |
| 128 | + echo "SKIP: mosquitto_pub/mosquitto_sub not found" |
| 129 | +fi |
| 130 | + |
| 131 | +# --- Test 4: Last Will and Testament --- |
| 132 | +echo "" |
| 133 | +echo "--- Test 4: Last Will and Testament ---" |
| 134 | +if command -v mosquitto_sub >/dev/null 2>&1; then |
| 135 | + mosquitto_sub -h 127.0.0.1 -p $port -t "test/will" -C 1 -W 10 >"${TMP_DIR}/t4_sub.log" 2>&1 & |
| 136 | + T4_SUB_PID=$! |
| 137 | + sleep 1 |
| 138 | + # Connect a client with a will, then kill it abruptly |
| 139 | + mosquitto_sub -h 127.0.0.1 -p $port -t "test/nothing" \ |
| 140 | + --will-topic "test/will" --will-payload "client_died" -W 3 >"${TMP_DIR}/t4_will.log" 2>&1 & |
| 141 | + T4_WILL_PID=$! |
| 142 | + sleep 1 |
| 143 | + kill -9 $T4_WILL_PID 2>/dev/null |
| 144 | + wait $T4_WILL_PID 2>/dev/null || true |
| 145 | + wait $T4_SUB_PID 2>/dev/null || true |
| 146 | + if grep -q "client_died" "${TMP_DIR}/t4_sub.log" 2>/dev/null; then |
| 147 | + echo "PASS: LWT delivered on abnormal disconnect" |
| 148 | + else |
| 149 | + echo "FAIL: LWT not delivered" |
| 150 | + FAIL=1 |
| 151 | + fi |
| 152 | +else |
| 153 | + echo "SKIP: mosquitto_sub not found" |
| 154 | +fi |
| 155 | + |
| 156 | +# --- Test 5: Client ID takeover --- |
| 157 | +echo "" |
| 158 | +echo "--- Test 5: Client ID takeover ---" |
| 159 | +if command -v mosquitto_sub >/dev/null 2>&1 && command -v mosquitto_pub >/dev/null 2>&1; then |
| 160 | + mosquitto_sub -h 127.0.0.1 -p $port -t "test/takeover" -i "takeoverClient" -W 5 >"${TMP_DIR}/t5_old.log" 2>&1 & |
| 161 | + T5_OLD_PID=$! |
| 162 | + sleep 1 |
| 163 | + # Connect second client with same ID - should disconnect old |
| 164 | + mosquitto_sub -h 127.0.0.1 -p $port -t "test/takeover" -i "takeoverClient" -C 1 -W 5 >"${TMP_DIR}/t5_new.log" 2>&1 & |
| 165 | + T5_NEW_PID=$! |
| 166 | + sleep 1 |
| 167 | + # Old client should have been disconnected |
| 168 | + wait $T5_OLD_PID 2>/dev/null |
| 169 | + T5_OLD_EXIT=$? |
| 170 | + # Send message to new client |
| 171 | + mosquitto_pub -h 127.0.0.1 -p $port -t "test/takeover" -m "after_takeover" |
| 172 | + wait $T5_NEW_PID 2>/dev/null || true |
| 173 | + if [ $T5_OLD_EXIT -ne 0 ]; then |
| 174 | + echo "PASS: Client ID takeover (old client disconnected)" |
| 175 | + else |
| 176 | + echo "FAIL: Old client was not disconnected" |
| 177 | + FAIL=1 |
| 178 | + fi |
| 179 | +else |
| 180 | + echo "SKIP: mosquitto_pub/mosquitto_sub not found" |
| 181 | +fi |
| 182 | + |
| 183 | +# --- Test 6: Multi-client paired pub/sub --- |
| 184 | +echo "" |
| 185 | +echo "--- Test 6: Multi-client paired pub/sub ---" |
| 186 | +if [ "$has_pubsub" = "yes" ]; then |
| 187 | + NUM_PAIRS=2 |
| 188 | + NUM_CLIENTS=$((NUM_PAIRS * 2)) |
| 189 | + SUB_LOGS=() |
| 190 | + |
| 191 | + start_sub() { |
| 192 | + local client_id="$1" |
| 193 | + local topic="$2" |
| 194 | + local log="$3" |
| 195 | + stdbuf -oL ./${sub_bin} -T -h localhost -p ${port} -i "${client_id}" \ |
| 196 | + -n "${topic}" -q 0 >"${log}" 2>&1 & |
| 197 | + TEST_PIDS+=("$!") |
| 198 | + SUB_LOGS+=("${log}") |
| 199 | + } |
| 200 | + |
| 201 | + run_pub() { |
| 202 | + local client_id="$1" |
| 203 | + local topic="$2" |
| 204 | + local msg="$3" |
| 205 | + ./${pub_bin} -T -h localhost -p ${port} -i "${client_id}" -n "${topic}" \ |
| 206 | + -m "${msg}" -q 0 >/dev/null 2>&1 |
| 207 | + } |
| 208 | + |
| 209 | + # Start subscribers |
| 210 | + for p in $(seq 0 $((NUM_PAIRS - 1))); do |
| 211 | + start_sub "sub_${p}_a" "pair/${p}/a" "${TMP_DIR}/sub_${p}_a.log" |
| 212 | + start_sub "sub_${p}_b" "pair/${p}/b" "${TMP_DIR}/sub_${p}_b.log" |
| 213 | + done |
| 214 | + |
| 215 | + # Wait for subscribers to be ready |
| 216 | + echo "Waiting for ${NUM_CLIENTS} subscribers to connect..." |
| 217 | + ELAPSED=0 |
| 218 | + while [ $ELAPSED -lt 15 ]; do |
| 219 | + READY=0 |
| 220 | + for log in "${SUB_LOGS[@]}"; do |
| 221 | + if grep -q "MQTT Waiting for message" "${log}" 2>/dev/null; then |
| 222 | + READY=$((READY + 1)) |
| 223 | + fi |
| 224 | + done |
| 225 | + if [ $READY -eq ${#SUB_LOGS[@]} ]; then |
| 226 | + echo "All subscribers ready after ${ELAPSED}s" |
| 227 | + break |
| 228 | + fi |
| 229 | + sleep 1 |
| 230 | + ELAPSED=$((ELAPSED + 1)) |
| 231 | + done |
| 232 | + |
| 233 | + # Publish messages |
| 234 | + for p in $(seq 0 $((NUM_PAIRS - 1))); do |
| 235 | + run_pub "pub_${p}_a" "pair/${p}/b" "hello_from_${p}_a" |
| 236 | + run_pub "pub_${p}_b" "pair/${p}/a" "hello_from_${p}_b" |
| 237 | + done |
| 238 | + |
| 239 | + # Wait for delivery |
| 240 | + sleep 3 |
| 241 | + |
| 242 | + # Check results |
| 243 | + T6_PASS=0 |
| 244 | + T6_FAIL=0 |
| 245 | + for p in $(seq 0 $((NUM_PAIRS - 1))); do |
| 246 | + if grep -q "hello_from_${p}_b" "${TMP_DIR}/sub_${p}_a.log" 2>/dev/null; then |
| 247 | + T6_PASS=$((T6_PASS + 1)) |
| 248 | + else |
| 249 | + T6_FAIL=$((T6_FAIL + 1)) |
| 250 | + fi |
| 251 | + if grep -q "hello_from_${p}_a" "${TMP_DIR}/sub_${p}_b.log" 2>/dev/null; then |
| 252 | + T6_PASS=$((T6_PASS + 1)) |
| 253 | + else |
| 254 | + T6_FAIL=$((T6_FAIL + 1)) |
| 255 | + fi |
| 256 | + done |
| 257 | + |
| 258 | + # Clean up subscriber processes |
| 259 | + for pid in "${TEST_PIDS[@]:-}"; do |
| 260 | + kill "$pid" 2>/dev/null || true |
| 261 | + wait "$pid" 2>/dev/null || true |
| 262 | + done |
| 263 | + TEST_PIDS=() |
| 264 | + |
| 265 | + if [ $T6_FAIL -eq 0 ]; then |
| 266 | + echo "PASS: Multi-client pub/sub (${T6_PASS}/${NUM_CLIENTS} messages delivered)" |
| 267 | + else |
| 268 | + echo "FAIL: Multi-client pub/sub (${T6_FAIL} messages missing)" |
| 269 | + FAIL=1 |
| 270 | + fi |
| 271 | +else |
| 272 | + echo "SKIP: mqtt-pub/mqtt-sub not built" |
| 273 | +fi |
| 274 | + |
| 275 | +# --- Summary --- |
| 276 | +echo "" |
| 277 | +if [ $FAIL -ne 0 ]; then |
| 278 | + KEEP_LOGS=1 |
| 279 | + echo "$name Tests FAILED" |
| 280 | + do_cleanup "-1" |
| 281 | +fi |
| 282 | + |
| 283 | +do_cleanup "0" |
| 284 | +echo "$name Tests Passed" |
| 285 | +exit 0 |
0 commit comments