231 lines
7.5 KiB
Bash
Executable File
231 lines
7.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# API smoke tests — chạy trên server đang lắng nghe.
|
|
set -euo pipefail
|
|
|
|
# shellcheck source=../lib/common.sh
|
|
source "$(dirname "$0")/../lib/common.sh"
|
|
|
|
BASE="${1:-http://127.0.0.1:${LM_TEST_PORT}}"
|
|
MISSION_ID="${TEST_MISSION_ID:-}"
|
|
|
|
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
|
|
|
|
# --- 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"
|
|
|
|
if [[ -z "$MISSION_ID" ]]; then
|
|
MISSION_ID="$(python3 -c "
|
|
import json
|
|
doc = json.load(open('$TMP/missions.json'))
|
|
missions = doc.get('missions', [])
|
|
preferred = 'testmission00001'
|
|
ids = [m.get('id') for m in missions if isinstance(m, dict)]
|
|
if preferred in ids:
|
|
print(preferred)
|
|
elif ids:
|
|
print(ids[0])
|
|
")"
|
|
fi
|
|
|
|
if [[ -z "$MISSION_ID" ]]; then
|
|
log_fail "no mission available for queue tests"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Mission id: $MISSION_ID"
|
|
echo
|
|
|
|
assert_json_true "missions available" "$TMP/missions.json" 'len(doc.get("missions", [])) >= 1'
|
|
|
|
# --- 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"
|
|
for _ in $(seq 1 15); do
|
|
curl -s "$BASE/api/v2.0.0/mission_queue" -o "$TMP/v2list.json"
|
|
if python3 -c "import json; d=json.load(open('$TMP/v2list.json')); exit(0 if isinstance(d,list) and len(d)>=1 else 1)" 2>/dev/null; then
|
|
break
|
|
fi
|
|
sleep 0.2
|
|
done
|
|
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
|