Files
App/scripts/api-smoke.sh
2026-06-13 13:46:53 +07:00

201 lines
6.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# API smoke tests for lidar_manager_web — run against a live server instance.
set -euo pipefail
BASE="${1:-http://127.0.0.1:18080}"
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MISSION_ID="${TEST_MISSION_ID:-testmission00001}"
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
PASS=0
FAIL=0
log_pass() { echo -e "${GREEN}PASS${NC} $*"; PASS=$((PASS + 1)); }
log_fail() { echo -e "${RED}FAIL${NC} $*"; FAIL=$((FAIL + 1)); }
json_field() {
python3 - "$1" "$2" <<'PY'
import json, sys
doc = json.loads(open(sys.argv[1]).read())
path = sys.argv[2].split(".")
cur = doc
for p in path:
cur = cur[p]
print(cur)
PY
}
http_code() {
curl -s -o "$1" -w '%{http_code}' "${@:2}"
}
assert_code() {
local name="$1" expect="$2" file="$3"
shift 3
local code
code="$(http_code "$file" "$@")"
if [[ "$code" == "$expect" ]]; then
log_pass "$name (HTTP $code)"
else
log_fail "$name — expected HTTP $expect, got $code"
[[ -f "$file" ]] && head -c 400 "$file" >&2 || true
echo >&2
fi
}
assert_json_true() {
local name="$1" file="$2" expr="$3"
if python3 - "$file" "$expr" <<'PY'
import json, sys
doc = json.loads(open(sys.argv[1]).read())
env = {"doc": doc, "any": any, "all": all, "len": len, "list": list, "isinstance": isinstance}
ok = eval(sys.argv[2], {"__builtins__": {}}, env)
sys.exit(0 if ok else 1)
PY
then
log_pass "$name"
else
log_fail "$name"
head -c 400 "$file" >&2 || true
echo >&2
fi
}
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
echo "API smoke tests → $BASE"
echo "Fixture mission id: $MISSION_ID"
echo
# --- Health & static ---
assert_code "GET /api/health" 200 "$TMP/health.json" -X GET "$BASE/api/health"
assert_json_true "health ok" "$TMP/health.json" 'doc.get("ok") is True'
assert_code "GET /" 200 "$TMP/index.html" -X GET "$BASE/"
assert_code "GET /missions.js" 200 "$TMP/missions.js" -X GET "$BASE/missions.js"
assert_code "GET /api/state" 200 "$TMP/state.json" -X GET "$BASE/api/state"
assert_code "GET /api/missions" 200 "$TMP/missions.json" -X GET "$BASE/api/missions"
assert_json_true "missions fixture present" "$TMP/missions.json" \
'any(m.get("id") == "'"$MISSION_ID"'" for m in doc.get("missions", []))'
# --- Queue pause/continue (chạy sớm, trước các test enqueue khác) ---
curl -s -X DELETE "$BASE/api/mission_queue" -o /dev/null || true
curl -s -X POST "$BASE/api/mission_queue" \
-H 'Content-Type: application/json' \
-d "{\"mission_id\":\"$MISSION_ID\"}" -o "$TMP/qpost.json"
for _ in $(seq 1 30); do
curl -s "$BASE/api/mission_queue" -o "$TMP/runner_poll.json"
RUNNER_STATE="$(python3 -c "import json; print(json.load(open('$TMP/runner_poll.json')).get('runner',{}).get('state',''))")"
if [[ "$RUNNER_STATE" == "running" ]]; then
break
fi
sleep 0.2
done
if [[ "$RUNNER_STATE" == "running" ]]; then
assert_code "POST /api/mission_queue/pause" 200 "$TMP/pause.json" \
-X POST "$BASE/api/mission_queue/pause"
assert_json_true "runner paused" "$TMP/pause.json" 'doc.get("state") == "paused"'
assert_code "POST /api/mission_queue/continue" 200 "$TMP/cont.json" \
-X POST "$BASE/api/mission_queue/continue"
assert_json_true "runner not paused" "$TMP/cont.json" 'doc.get("state") != "paused"'
else
log_fail "runner never reached running (pause test skipped)"
fi
# --- LiDAR CRUD ---
assert_code "POST /api/lidars" 201 "$TMP/lidar.json" \
-X POST "$BASE/api/lidars" \
-H 'Content-Type: application/json' \
-d '{"name":"smoke-lidar","ip":"192.168.99.1","port":2112}'
LIDAR_ID="$(json_field "$TMP/lidar.json" id 2>/dev/null || echo "")"
if [[ -n "$LIDAR_ID" ]]; then
log_pass "lidar created id=$LIDAR_ID"
PASS=$((PASS + 1))
assert_code "PUT /api/lidars" 200 "$TMP/lidar_put.json" \
-X PUT "$BASE/api/lidars/$LIDAR_ID" \
-H 'Content-Type: application/json' \
-d '{"name":"smoke-lidar","ip":"192.168.99.2","port":2112}'
assert_code "DELETE /api/lidars" 204 "$TMP/lidar_del.txt" \
-X DELETE "$BASE/api/lidars/$LIDAR_ID"
else
log_fail "lidar create — no id in response"
fi
# --- IMU CRUD ---
assert_code "POST /api/imus" 201 "$TMP/imu.json" \
-X POST "$BASE/api/imus" \
-H 'Content-Type: application/json' \
-d '{"name":"smoke-imu","frame_id":"imu_smoke","topic":"/imu/smoke","source":"external"}'
IMU_ID="$(json_field "$TMP/imu.json" id 2>/dev/null || echo "")"
if [[ -n "$IMU_ID" ]]; then
log_pass "imu created id=$IMU_ID"
PASS=$((PASS + 1))
assert_code "DELETE /api/imus" 204 "$TMP/imu_del.txt" -X DELETE "$BASE/api/imus/$IMU_ID"
else
log_fail "imu create — no id in response"
fi
# --- Clear queue ---
curl -s -X DELETE "$BASE/api/mission_queue" -o /dev/null || true
curl -s -X DELETE "$BASE/api/v2.0.0/mission_queue" -o /dev/null || true
# --- MiR v2 enqueue (Cách C REST) ---
assert_code "POST /api/v2.0.0/mission_queue" 201 "$TMP/v2q.json" \
-X POST "$BASE/api/v2.0.0/mission_queue" \
-H 'Content-Type: application/json' \
-d "{\"mission_id\":\"$MISSION_ID\",\"priority\":2,\"robot_id\":\"default\"}"
assert_json_true "v2 queue entry mission_id" "$TMP/v2q.json" \
'doc.get("mission_id") == "'"$MISSION_ID"'"'
assert_code "GET /api/v2.0.0/mission_queue" 200 "$TMP/v2list.json" -X GET "$BASE/api/v2.0.0/mission_queue"
assert_json_true "v2 queue non-empty" "$TMP/v2list.json" 'isinstance(doc, list) and len(doc) >= 1'
assert_code "GET /api/v2.0.0/status" 200 "$TMP/v2status.json" -X GET "$BASE/api/v2.0.0/status"
assert_json_true "v2 status has state_text" "$TMP/v2status.json" '"state_text" in doc'
# --- Modbus trigger (Cách C) ---
assert_code "POST /api/triggers" 201 "$TMP/trig.json" \
-X POST "$BASE/api/triggers" \
-H 'Content-Type: application/json' \
-d "{\"name\":\"smoke-trigger\",\"coil_id\":1001,\"mission_id\":\"$MISSION_ID\"}"
TRIG_ID="$(json_field "$TMP/trig.json" id 2>/dev/null || echo "")"
if [[ -n "$TRIG_ID" ]]; then
log_pass "trigger created id=$TRIG_ID"
PASS=$((PASS + 1))
assert_code "POST modbus fire coil" 200 "$TMP/fire.json" \
-X POST "$BASE/api/modbus/coils/1001/trigger"
assert_code "DELETE /api/triggers" 204 "$TMP/trig_del.txt" \
-X DELETE "$BASE/api/triggers/$TRIG_ID"
else
log_fail "trigger create — no id"
fi
# --- Fleet schedule ---
assert_code "POST /api/fleet/schedules" 201 "$TMP/sched.json" \
-X POST "$BASE/api/fleet/schedules" \
-H 'Content-Type: application/json' \
-d "{\"name\":\"smoke-schedule\",\"mission_id\":\"$MISSION_ID\",\"start_mode\":\"asap\",\"priority\":1}"
SCHED_ID="$(json_field "$TMP/sched.json" id 2>/dev/null || echo "")"
if [[ -n "$SCHED_ID" ]]; then
log_pass "schedule created id=$SCHED_ID"
PASS=$((PASS + 1))
assert_code "DELETE /api/fleet/schedules" 204 "$TMP/sched_del.txt" \
-X DELETE "$BASE/api/fleet/schedules/$SCHED_ID"
else
log_fail "schedule create — no id"
fi
assert_code "GET /api/fleet/robots" 200 "$TMP/robots.json" -X GET "$BASE/api/fleet/robots"
assert_json_true "robots list" "$TMP/robots.json" 'isinstance(doc, list) and len(doc) >= 1'
echo
echo "Results: $PASS passed, $FAIL failed"
if [[ "$FAIL" -gt 0 ]]; then
exit 1
fi