Skip to content

Commit 0ed6f49

Browse files
committed
test: extend smoke tests for v0.4.0 features and missing API coverage
Add smoke test assertions for new gateway v0.4.0 features across all 3 demos (sensor, moveit, turtlebot3): - Linux introspection (procfs plugin data per entity) - Scripts API (list scripts, execute, poll completion) - Triggers CRUD (create, list, verify, delete) for moveit/turtlebot - Beacon discovery (sensor demo, conditional on BEACON_MODE) Fill gaps in pre-v0.4.0 API coverage: - Functions entity discovery (all demos) - Discovery relationships (areas -> components) - Operations endpoint (via medkit-fault-manager) - Data access and configurations (moveit, turtlebot) - Bulk data endpoint (all demos) - Faults listing (moveit, turtlebot) Add reusable helpers to smoke_lib.sh: - assert_procfs_introspection - assert_scripts_list / assert_script_execution - assert_triggers_crud Tested against sensor_diagnostics demo: 40/40 pass. Closes #45
1 parent c7b7495 commit 0ed6f49

4 files changed

Lines changed: 320 additions & 0 deletions

File tree

tests/smoke_lib.sh

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,178 @@ test_entity_discovery() {
162162
fi
163163
}
164164

165+
# Test that procfs introspection data is available for an app
166+
# Usage: assert_procfs_introspection "lidar-sim"
167+
assert_procfs_introspection() {
168+
local app_id="$1"
169+
local endpoint="/apps/${app_id}/x-medkit-procfs"
170+
if api_get "$endpoint"; then
171+
if echo "$RESPONSE" | jq -e '.pid' > /dev/null 2>&1; then
172+
pass "GET ${endpoint} returns procfs data with pid"
173+
else
174+
fail "GET ${endpoint} returns procfs data with pid" "pid field missing"
175+
fi
176+
else
177+
fail "GET ${endpoint} returns 200" "unexpected status code"
178+
fi
179+
}
180+
181+
# Test that scripts are listed for a component
182+
# Usage: assert_scripts_list "compute-unit" "run-diagnostics"
183+
assert_scripts_list() {
184+
local component_id="$1"
185+
local expected_script="$2"
186+
local endpoint="/components/${component_id}/scripts"
187+
if api_get "$endpoint"; then
188+
if echo "$RESPONSE" | jq -e '.items | length > 0' > /dev/null 2>&1; then
189+
pass "GET ${endpoint} returns non-empty items"
190+
else
191+
fail "GET ${endpoint} returns non-empty items" "items is empty"
192+
fi
193+
if echo "$RESPONSE" | jq -e --arg s "$expected_script" '.items[] | select(.id == $s)' > /dev/null 2>&1; then
194+
pass "scripts contains '${expected_script}'"
195+
else
196+
fail "scripts contains '${expected_script}'" "not found in response"
197+
fi
198+
else
199+
fail "GET ${endpoint} returns 200" "unexpected status code"
200+
fi
201+
}
202+
203+
# Execute a script and verify it completes
204+
# Usage: assert_script_execution "compute-unit" "run-diagnostics" [max_wait]
205+
assert_script_execution() {
206+
local component_id="$1"
207+
local script_id="$2"
208+
local max_wait="${3:-30}"
209+
local exec_endpoint="/components/${component_id}/scripts/${script_id}/executions"
210+
211+
# Start execution
212+
local exec_response
213+
exec_response=$(curl -s -w "\n%{http_code}" -X POST "${API_BASE}${exec_endpoint}" \
214+
-H "Content-Type: application/json" \
215+
-d '{"execution_type": "now"}' 2>/dev/null) || true
216+
local exec_http
217+
exec_http=$(echo "$exec_response" | tail -1)
218+
local exec_body
219+
exec_body=$(echo "$exec_response" | sed '$d')
220+
221+
if [ "$exec_http" != "201" ] && [ "$exec_http" != "200" ] && [ "$exec_http" != "202" ]; then
222+
fail "POST ${exec_endpoint} starts execution" "got HTTP ${exec_http}"
223+
return
224+
fi
225+
pass "POST ${exec_endpoint} starts execution"
226+
227+
local exec_id
228+
exec_id=$(echo "$exec_body" | jq -r '.id')
229+
if [ -z "$exec_id" ] || [ "$exec_id" = "null" ]; then
230+
fail "script execution returns valid id" "id is null or empty"
231+
return
232+
fi
233+
pass "script execution returns valid id"
234+
235+
# Poll until completed
236+
echo " Waiting for script '${script_id}' to complete (max ${max_wait}s)..."
237+
local elapsed=0
238+
while [ $elapsed -lt "$max_wait" ]; do
239+
if api_get "${exec_endpoint}/${exec_id}"; then
240+
local status
241+
status=$(echo "$RESPONSE" | jq -r '.status')
242+
case "$status" in
243+
completed)
244+
pass "script '${script_id}' completed successfully"
245+
return
246+
;;
247+
failed|terminated)
248+
fail "script '${script_id}' completed successfully" "status: ${status}"
249+
return
250+
;;
251+
esac
252+
fi
253+
sleep 1
254+
elapsed=$((elapsed + 1))
255+
done
256+
fail "script '${script_id}' completed successfully" "timed out after ${max_wait}s"
257+
}
258+
259+
# Test trigger CRUD lifecycle on an entity
260+
# Usage: assert_triggers_crud "apps" "diagnostic-bridge" "/api/v1/apps/diagnostic-bridge/faults"
261+
assert_triggers_crud() {
262+
local entity_type="$1"
263+
local entity_id="$2"
264+
local resource_uri="$3"
265+
local triggers_endpoint="/${entity_type}/${entity_id}/triggers"
266+
267+
# Create trigger
268+
echo " Creating OnChange trigger on ${entity_type}/${entity_id}..."
269+
local create_response
270+
create_response=$(curl -s -w "\n%{http_code}" -X POST "${API_BASE}${triggers_endpoint}" \
271+
-H "Content-Type: application/json" \
272+
-d "{\"resource\":\"${resource_uri}\",\"trigger_condition\":{\"condition_type\":\"OnChange\"},\"multishot\":true,\"lifetime\":60}" 2>/dev/null) || true
273+
274+
local create_http
275+
create_http=$(echo "$create_response" | tail -1)
276+
local create_body
277+
create_body=$(echo "$create_response" | sed '$d')
278+
279+
if [ "$create_http" = "201" ]; then
280+
pass "POST ${triggers_endpoint} returns 201"
281+
else
282+
fail "POST ${triggers_endpoint} returns 201" "got HTTP ${create_http}"
283+
return
284+
fi
285+
286+
local trigger_id
287+
trigger_id=$(echo "$create_body" | jq -r '.id')
288+
if [ -n "$trigger_id" ] && [ "$trigger_id" != "null" ]; then
289+
pass "trigger response contains valid id"
290+
else
291+
fail "trigger response contains valid id" "id is null or empty"
292+
return
293+
fi
294+
295+
local trigger_status
296+
trigger_status=$(echo "$create_body" | jq -r '.status')
297+
if [ "$trigger_status" = "active" ]; then
298+
pass "trigger status is 'active'"
299+
else
300+
fail "trigger status is 'active'" "got '${trigger_status}'"
301+
fi
302+
303+
# List triggers - verify it appears
304+
if api_get "${triggers_endpoint}"; then
305+
if echo "$RESPONSE" | jq -e --arg id "$trigger_id" '.items[] | select(.id == $id)' > /dev/null 2>&1; then
306+
pass "GET ${triggers_endpoint} lists created trigger"
307+
else
308+
fail "GET ${triggers_endpoint} lists created trigger" "trigger ${trigger_id} not found"
309+
fi
310+
else
311+
fail "GET ${triggers_endpoint} returns 200" "unexpected status code"
312+
fi
313+
314+
# Delete trigger
315+
local delete_status
316+
delete_status=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE \
317+
"${API_BASE}${triggers_endpoint}/${trigger_id}" 2>/dev/null) || true
318+
319+
if [ "$delete_status" = "204" ]; then
320+
pass "DELETE trigger ${trigger_id} returns 204"
321+
else
322+
fail "DELETE trigger ${trigger_id} returns 204" "got HTTP ${delete_status}"
323+
fi
324+
325+
# Verify trigger is gone
326+
if api_get "${triggers_endpoint}"; then
327+
if ! echo "$RESPONSE" | jq -e --arg id "$trigger_id" '.items[] | select(.id == $id)' > /dev/null 2>&1; then
328+
pass "trigger no longer listed after deletion"
329+
else
330+
fail "trigger no longer listed after deletion" "still found in list"
331+
fi
332+
else
333+
fail "GET ${triggers_endpoint} returns 200 after delete" "unexpected status code"
334+
fi
335+
}
336+
165337
# Print test summary and exit with appropriate code
166338
print_summary() {
167339
echo ""

tests/smoke_test.sh

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ fi
3434
test_entity_discovery "areas" sensors processing diagnostics
3535
test_entity_discovery "components" lidar-unit imu-unit gps-unit camera-unit
3636
test_entity_discovery "apps" lidar-sim imu-sim gps-sim camera-sim anomaly-detector
37+
test_entity_discovery "functions" sensor-monitoring anomaly-detection fault-management
38+
39+
section "Discovery Relationships"
40+
41+
assert_non_empty_items "/areas/sensors/components"
42+
43+
section "Linux Introspection"
44+
45+
assert_procfs_introspection "lidar-sim"
3746

3847
section "Data Access"
3948

@@ -49,6 +58,24 @@ else
4958
fail "configurations contains 'noise_stddev' parameter" "not found in response"
5059
fi
5160

61+
section "Operations"
62+
63+
assert_non_empty_items "/apps/medkit-fault-manager/operations"
64+
65+
section "Scripts"
66+
67+
assert_scripts_list "compute-unit" "run-diagnostics"
68+
assert_script_execution "compute-unit" "run-diagnostics" 30
69+
70+
section "Bulk Data"
71+
72+
# Bulk data endpoint should return 200 with categories list (may be empty without faults)
73+
if api_get "/apps/diagnostic-bridge/bulk-data"; then
74+
pass "GET /apps/diagnostic-bridge/bulk-data returns 200"
75+
else
76+
fail "GET /apps/diagnostic-bridge/bulk-data returns 200" "unexpected status code"
77+
fi
78+
5279
section "Logs"
5380

5481
assert_non_empty_items "/apps/medkit-gateway/logs"
@@ -177,6 +204,35 @@ else
177204
fail "GET /apps/diagnostic-bridge/triggers returns 200 after delete" "unexpected status code"
178205
fi
179206

207+
section "Beacon Discovery"
208+
209+
# Beacon data is exposed at vendor extension endpoints:
210+
# /apps/{id}/x-medkit-topic-beacon (BEACON_MODE=topic)
211+
# /apps/{id}/x-medkit-param-beacon (BEACON_MODE=param)
212+
# When BEACON_MODE=none (CI default), these endpoints return 404.
213+
beacon_found=false
214+
for beacon_type in topic-beacon param-beacon; do
215+
if api_get "/apps/lidar-sim/x-medkit-${beacon_type}"; then
216+
beacon_found=true
217+
pass "GET /apps/lidar-sim/x-medkit-${beacon_type} returns 200"
218+
if echo "$RESPONSE" | jq -e '.status' > /dev/null 2>&1; then
219+
pass "beacon response contains 'status' field"
220+
else
221+
fail "beacon response contains 'status' field" "field missing"
222+
fi
223+
if echo "$RESPONSE" | jq -e '.entity_id' > /dev/null 2>&1; then
224+
pass "beacon response contains 'entity_id' field"
225+
else
226+
fail "beacon response contains 'entity_id' field" "field missing"
227+
fi
228+
break
229+
fi
230+
done
231+
if [ "$beacon_found" = false ]; then
232+
# Not a failure - beacons are optional depending on BEACON_MODE
233+
echo -e " ${BLUE}SKIP${NC} beacon not active (BEACON_MODE=none or plugin not loaded)"
234+
fi
235+
180236
# --- Summary ---
181237

182238
print_summary

tests/smoke_test_moveit.sh

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,57 @@ fi
3535
test_entity_discovery "areas" manipulation planning diagnostics bridge
3636
test_entity_discovery "components" panda-arm panda-gripper moveit-planning pick-place-loop gateway fault-manager diagnostic-bridge
3737
test_entity_discovery "apps" joint-state-broadcaster panda-arm-controller panda-hand-controller robot-state-publisher move-group pick-place-node medkit-gateway medkit-fault-manager diagnostic-bridge-app manipulation-monitor
38+
test_entity_discovery "functions" pick-and-place motion-planning gripper-control fault-management
39+
40+
section "Discovery Relationships"
41+
42+
assert_non_empty_items "/areas/manipulation/components"
43+
44+
section "Linux Introspection"
45+
46+
assert_procfs_introspection "medkit-gateway"
47+
48+
section "Data Access"
49+
50+
assert_non_empty_items "/apps/medkit-gateway/data"
51+
52+
section "Operations"
53+
54+
assert_non_empty_items "/apps/medkit-fault-manager/operations"
55+
56+
section "Configurations"
57+
58+
assert_non_empty_items "/apps/medkit-gateway/configurations"
59+
60+
section "Scripts"
61+
62+
assert_scripts_list "moveit-planning" "arm-self-test"
63+
assert_script_execution "moveit-planning" "arm-self-test" 30
64+
65+
section "Bulk Data"
66+
67+
if api_get "/apps/diagnostic-bridge-app/bulk-data"; then
68+
pass "GET /apps/diagnostic-bridge-app/bulk-data returns 200"
69+
else
70+
fail "GET /apps/diagnostic-bridge-app/bulk-data returns 200" "unexpected status code"
71+
fi
72+
73+
section "Faults"
74+
75+
if api_get "/faults"; then
76+
pass "GET /faults returns 200"
77+
else
78+
fail "GET /faults returns 200" "unexpected status code"
79+
fi
3880

3981
section "Logs"
4082

4183
assert_non_empty_items "/apps/medkit-gateway/logs"
4284

85+
section "Triggers"
86+
87+
assert_triggers_crud "apps" "diagnostic-bridge-app" "/api/v1/apps/diagnostic-bridge-app/faults"
88+
4389
# --- Summary ---
4490

4591
print_summary

tests/smoke_test_turtlebot3.sh

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,57 @@ fi
3636
test_entity_discovery "areas" robot navigation diagnostics bridge
3737
test_entity_discovery "components" turtlebot3-base lidar-sensor nav2-stack gateway fault-manager diagnostic-bridge-unit
3838
test_entity_discovery "apps" turtlebot3-node robot-state-publisher amcl bt-navigator controller-server planner-server velocity-smoother medkit-gateway medkit-fault-manager diagnostic-bridge anomaly-detector
39+
test_entity_discovery "functions" autonomous-navigation robot-control fault-management
40+
41+
section "Discovery Relationships"
42+
43+
assert_non_empty_items "/areas/robot/components"
44+
45+
section "Linux Introspection"
46+
47+
assert_procfs_introspection "medkit-gateway"
48+
49+
section "Data Access"
50+
51+
assert_non_empty_items "/apps/medkit-gateway/data"
52+
53+
section "Operations"
54+
55+
assert_non_empty_items "/apps/medkit-fault-manager/operations"
56+
57+
section "Configurations"
58+
59+
assert_non_empty_items "/apps/medkit-gateway/configurations"
60+
61+
section "Scripts"
62+
63+
assert_scripts_list "nav2-stack" "nav-health-check"
64+
assert_script_execution "nav2-stack" "nav-health-check" 30
65+
66+
section "Bulk Data"
67+
68+
if api_get "/apps/diagnostic-bridge/bulk-data"; then
69+
pass "GET /apps/diagnostic-bridge/bulk-data returns 200"
70+
else
71+
fail "GET /apps/diagnostic-bridge/bulk-data returns 200" "unexpected status code"
72+
fi
73+
74+
section "Faults"
75+
76+
if api_get "/faults"; then
77+
pass "GET /faults returns 200"
78+
else
79+
fail "GET /faults returns 200" "unexpected status code"
80+
fi
3981

4082
section "Logs"
4183

4284
assert_non_empty_items "/apps/medkit-gateway/logs"
4385

86+
section "Triggers"
87+
88+
assert_triggers_crud "apps" "diagnostic-bridge" "/api/v1/apps/diagnostic-bridge/faults"
89+
4490
# --- Summary ---
4591

4692
print_summary

0 commit comments

Comments
 (0)