267 lines
8.2 KiB
Bash
267 lines
8.2 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
BASE_URL="${BASE_URL:-http://127.0.0.1:8080}"
|
|
HEALTH_PATH="${HEALTH_PATH:-/actuator/health}"
|
|
|
|
AIRCRAFT_ID="${AIRCRAFT_ID:-SIM-AC-001}"
|
|
UNMANNED_ID="${UNMANNED_ID:-SIM-UV-001}"
|
|
SPECIAL_ID="${SPECIAL_ID:-SIM-SP-001}"
|
|
|
|
AIRCRAFT_ROUTE_TYPE="${AIRCRAFT_ROUTE_TYPE:-OUT}"
|
|
AIRCRAFT_IN_RUNWAY="${AIRCRAFT_IN_RUNWAY:-35}"
|
|
AIRCRAFT_OUT_RUNWAY="${AIRCRAFT_OUT_RUNWAY:-34}"
|
|
AIRCRAFT_CONTACT_CROSS="${AIRCRAFT_CONTACT_CROSS:-}"
|
|
AIRCRAFT_SEAT="${AIRCRAFT_SEAT:-165}"
|
|
AIRCRAFT_START_SEAT="${AIRCRAFT_START_SEAT:-165}"
|
|
|
|
UV_ROUTE_NAME="${UV_ROUTE_NAME:-SIM_UV_ROUTE_001}"
|
|
SP_ROUTE_NAME="${SP_ROUTE_NAME:-SIM_SP_ROUTE_001}"
|
|
|
|
AUTH_HEADER="${AUTH_HEADER:-}"
|
|
CONNECT_TIMEOUT="${CONNECT_TIMEOUT:-5}"
|
|
MAX_TIME="${MAX_TIME:-20}"
|
|
WORK_DIR="${WORK_DIR:-/tmp/qaup_collision_prepare_test}"
|
|
|
|
mkdir -p "$WORK_DIR"
|
|
|
|
log() {
|
|
printf '[%s] %s\n' "$(date '+%F %T')" "$*"
|
|
}
|
|
|
|
fail() {
|
|
log "FAIL: $*"
|
|
exit 1
|
|
}
|
|
|
|
have_jq() {
|
|
command -v jq >/dev/null 2>&1
|
|
}
|
|
|
|
json_get() {
|
|
local file="$1"
|
|
local expr="$2"
|
|
if have_jq; then
|
|
jq -r "$expr" "$file"
|
|
else
|
|
python3 - "$file" "$expr" <<'PY'
|
|
import json
|
|
import sys
|
|
|
|
path = sys.argv[2].strip().lstrip(".")
|
|
parts = [p for p in path.split(".") if p]
|
|
with open(sys.argv[1], "r", encoding="utf-8") as f:
|
|
data = json.load(f)
|
|
for part in parts:
|
|
if isinstance(data, list):
|
|
data = data[int(part)]
|
|
else:
|
|
data = data.get(part)
|
|
print("" if data is None else data)
|
|
PY
|
|
fi
|
|
}
|
|
|
|
json_contains_text() {
|
|
local file="$1"
|
|
local expected="$2"
|
|
grep -Fq "$expected" "$file"
|
|
}
|
|
|
|
curl_json() {
|
|
local method="$1"
|
|
local path="$2"
|
|
local body_file="${3:-}"
|
|
local response_file="$4"
|
|
|
|
local curl_args=(
|
|
--silent
|
|
--show-error
|
|
--connect-timeout "$CONNECT_TIMEOUT"
|
|
--max-time "$MAX_TIME"
|
|
--request "$method"
|
|
--header 'Content-Type: application/json'
|
|
--write-out '%{http_code}'
|
|
--output "$response_file"
|
|
)
|
|
|
|
if [[ -n "$AUTH_HEADER" ]]; then
|
|
curl_args+=(--header "Authorization: $AUTH_HEADER")
|
|
fi
|
|
|
|
if [[ -n "$body_file" ]]; then
|
|
curl_args+=(--data @"$body_file")
|
|
fi
|
|
|
|
curl "${curl_args[@]}" "${BASE_URL}${path}"
|
|
}
|
|
|
|
assert_http_ok() {
|
|
local code="$1"
|
|
local context="$2"
|
|
[[ "$code" == "200" ]] || fail "$context returned HTTP $code"
|
|
}
|
|
|
|
write_json() {
|
|
local file="$1"
|
|
shift
|
|
cat > "$file" <<EOF
|
|
$*
|
|
EOF
|
|
}
|
|
|
|
print_json() {
|
|
local file="$1"
|
|
if have_jq; then
|
|
jq . "$file"
|
|
else
|
|
cat "$file"
|
|
fi
|
|
}
|
|
|
|
run_health_check() {
|
|
log "Checking application health: ${BASE_URL}${HEALTH_PATH}"
|
|
local response_file="$WORK_DIR/health.json"
|
|
local code
|
|
code="$(curl --silent --show-error --connect-timeout "$CONNECT_TIMEOUT" --max-time "$MAX_TIME" --output "$response_file" --write-out '%{http_code}' "${BASE_URL}${HEALTH_PATH}")"
|
|
assert_http_ok "$code" "Health check"
|
|
log "Health check passed"
|
|
}
|
|
|
|
sync_registry() {
|
|
local body_file="$WORK_DIR/vehicle_registry.json"
|
|
local response_file="$WORK_DIR/vehicle_registry_response.json"
|
|
write_json "$body_file" "[
|
|
{\"vehicleID\":\"${UNMANNED_ID}\",\"vehicleType\":\"WUREN\"},
|
|
{\"vehicleID\":\"${SPECIAL_ID}\",\"vehicleType\":\"TEQIN\"},
|
|
{\"vehicleID\":\"${AIRCRAFT_ID}\",\"vehicleType\":\"HANGKONG\"}
|
|
]"
|
|
|
|
log "Registering simulated collision objects"
|
|
local code
|
|
code="$(curl_json POST /api/VehicleRegistry "$body_file" "$response_file")"
|
|
assert_http_ok "$code" "Vehicle registry"
|
|
[[ "$(json_get "$response_file" '.status')" == "success" ]] || fail "Vehicle registry response status is not success"
|
|
log "Registry synchronized"
|
|
}
|
|
|
|
query_preparation_status() {
|
|
local tag="$1"
|
|
local response_file="$WORK_DIR/preparation_status_${tag}.json"
|
|
local code
|
|
code="$(curl_json POST /api/collision/preparation/status "" "$response_file")"
|
|
assert_http_ok "$code" "Collision preparation status"
|
|
[[ "$(json_get "$response_file" '.status')" == "success" ]] || fail "Preparation status response status is not success"
|
|
print_json "$response_file"
|
|
}
|
|
|
|
assert_not_ready_before_binding() {
|
|
local response_file="$WORK_DIR/preparation_status_before.json"
|
|
local ready
|
|
ready="$(json_get "$response_file" '.ready')"
|
|
[[ "$ready" == "false" ]] || fail "Preparation status should be false before routes are bound"
|
|
json_contains_text "$response_file" "$AIRCRAFT_ID" || fail "Preparation status missing aircraft id before binding"
|
|
json_contains_text "$response_file" "$UNMANNED_ID" || fail "Preparation status missing unmanned id before binding"
|
|
json_contains_text "$response_file" "$SPECIAL_ID" || fail "Preparation status missing special vehicle id before binding"
|
|
log "Preparation status correctly reports missing route bindings"
|
|
}
|
|
|
|
bind_aircraft_route() {
|
|
local body_file="$WORK_DIR/aircraft_route_query.json"
|
|
local response_file="$WORK_DIR/aircraft_route_query_response.json"
|
|
|
|
if [[ "$AIRCRAFT_ROUTE_TYPE" == "OUT" ]]; then
|
|
write_json "$body_file" "{
|
|
\"objectId\": \"${AIRCRAFT_ID}\",
|
|
\"routeType\": \"OUT\",
|
|
\"outRunway\": \"${AIRCRAFT_OUT_RUNWAY}\",
|
|
\"inRunway\": \"${AIRCRAFT_IN_RUNWAY}\",
|
|
\"seat\": \"${AIRCRAFT_SEAT}\",
|
|
\"startSeat\": \"${AIRCRAFT_START_SEAT:-$AIRCRAFT_SEAT}\"
|
|
}"
|
|
else
|
|
write_json "$body_file" "{
|
|
\"objectId\": \"${AIRCRAFT_ID}\",
|
|
\"routeType\": \"IN\",
|
|
\"inRunway\": \"${AIRCRAFT_IN_RUNWAY}\",
|
|
\"outRunway\": \"${AIRCRAFT_OUT_RUNWAY}\",
|
|
\"contactCross\": \"${AIRCRAFT_CONTACT_CROSS}\",
|
|
\"seat\": \"${AIRCRAFT_SEAT}\"
|
|
}"
|
|
fi
|
|
|
|
log "Querying and binding aircraft route"
|
|
local code
|
|
code="$(curl_json POST /api/aircraft-routes/query "$body_file" "$response_file")"
|
|
assert_http_ok "$code" "Aircraft route query"
|
|
[[ "$(json_get "$response_file" '.code')" == "200" ]] || fail "Aircraft route query code is not 200"
|
|
[[ "$(json_get "$response_file" '.data.bindingObjectId')" == "$AIRCRAFT_ID" ]] || fail "Aircraft route bindingObjectId mismatch"
|
|
[[ "$(json_get "$response_file" '.data.routeBound')" == "true" ]] || fail "Aircraft route was not bound"
|
|
log "Aircraft route bound successfully"
|
|
}
|
|
|
|
bind_vehicle_route() {
|
|
local vehicle_id="$1"
|
|
local vehicle_type="$2"
|
|
local route_name="$3"
|
|
local point_a_lon="$4"
|
|
local point_a_lat="$5"
|
|
local point_b_lon="$6"
|
|
local point_b_lat="$7"
|
|
local response_tag="$8"
|
|
|
|
local body_file="$WORK_DIR/${response_tag}_route_assignment.json"
|
|
local response_file="$WORK_DIR/${response_tag}_route_assignment_response.json"
|
|
|
|
write_json "$body_file" "{
|
|
\"vehicleID\": \"${vehicle_id}\",
|
|
\"vehicleType\": \"${vehicle_type}\",
|
|
\"routeName\": \"${route_name}\",
|
|
\"route\": {
|
|
\"points\": [
|
|
{\"lon\": ${point_a_lon}, \"lat\": ${point_a_lat}},
|
|
{\"lon\": ${point_b_lon}, \"lat\": ${point_b_lat}}
|
|
]
|
|
}
|
|
}"
|
|
|
|
log "Binding route for ${vehicle_type} ${vehicle_id}"
|
|
local code
|
|
code="$(curl_json POST /api/vehicle-route/assignment "$body_file" "$response_file")"
|
|
assert_http_ok "$code" "Vehicle route assignment for ${vehicle_id}"
|
|
[[ "$(json_get "$response_file" '.status')" == "success" ]] || fail "Route assignment failed for ${vehicle_id}"
|
|
[[ "$(json_get "$response_file" '.objectId')" == "$vehicle_id" ]] || fail "Route assignment objectId mismatch for ${vehicle_id}"
|
|
log "Route bound for ${vehicle_id}"
|
|
}
|
|
|
|
assert_ready_after_binding() {
|
|
local response_file="$WORK_DIR/preparation_status_after.json"
|
|
[[ "$(json_get "$response_file" '.ready')" == "true" ]] || fail "Preparation status should be true after routes are bound"
|
|
[[ "$(json_get "$response_file" '.summary.registeredCount')" == "3" ]] || fail "Expected 3 registered collision objects"
|
|
[[ "$(json_get "$response_file" '.summary.missingRouteCount')" == "0" ]] || fail "Expected 0 missing routes after binding"
|
|
log "Preparation status confirms all registered objects are ready"
|
|
}
|
|
|
|
main() {
|
|
log "Starting collision preparation interface test"
|
|
log "BASE_URL=${BASE_URL}"
|
|
log "AIRCRAFT_ID=${AIRCRAFT_ID}, UNMANNED_ID=${UNMANNED_ID}, SPECIAL_ID=${SPECIAL_ID}"
|
|
|
|
run_health_check
|
|
sync_registry
|
|
query_preparation_status before
|
|
assert_not_ready_before_binding
|
|
|
|
bind_aircraft_route
|
|
bind_vehicle_route "$UNMANNED_ID" "WUREN" "$UV_ROUTE_NAME" 120.1000 36.1000 120.2000 36.2000 "uv"
|
|
bind_vehicle_route "$SPECIAL_ID" "TEQIN" "$SP_ROUTE_NAME" 120.1000 36.2000 120.2000 36.1000 "sp"
|
|
|
|
query_preparation_status after
|
|
assert_ready_after_binding
|
|
|
|
log "PASS: collision preparation interface flow is ready for deployment testing"
|
|
}
|
|
|
|
main "$@"
|