From cf08b577ed8c71ca962c5527299c47e52433686d Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Tue, 17 Mar 2026 17:10:03 +0100 Subject: [PATCH] test: gps_simple: wait for full position data before has_fix() has_fix() only checks that fix-mode is set (2d/3d), but altitude and other fields may not yet be populated in the operational datastore when gpsd is still processing its first NMEA cycles after boot. Calling verify_position() immediately after has_fix() passes can therefore race and fail with: KeyError: 'altitude' This manifests reliably on the second GPS receiver (gps1) after reboot, because it is initialized slightly later than gps0 and hits the window where fix-mode is set but altitude has not yet appeared. not ok 11 - Verify gps1 position is near the coordinates # Traceback (most recent call last): # File "test/case/hardware/gps_simple/test.py", line 29, in verify_position # alt = float(state["altitude"]) # ~~~~~^^^^^^^^^^^^ # KeyError: 'altitude' Add has_position() to infamy/gps.py, which gates on fix-mode AND all position fields (latitude, longitude, altitude, satellites-used) being present. Replace the has_fix() polls in both the pre- and post-reboot verify steps with has_position(). Signed-off-by: Joachim Wiberg --- test/case/hardware/gps_simple/test.adoc | 6 ++++-- test/case/hardware/gps_simple/test.py | 12 ++++++++++-- test/infamy/gps.py | 10 ++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/test/case/hardware/gps_simple/test.adoc b/test/case/hardware/gps_simple/test.adoc index ca7ed86a..2715ce0f 100644 --- a/test/case/hardware/gps_simple/test.adoc +++ b/test/case/hardware/gps_simple/test.adoc @@ -19,12 +19,14 @@ image::topology.svg[GPS receiver basic test topology, align=center, scaledwidth= . Set up topology and attach to target DUT . Configure GPS hardware components . Verify both GPS receivers are activated -. Verify both GPS receivers have a fix +. Verify both GPS receivers report full position data +. Verify both GPS receivers have a satellite fix . Verify gps0 position is near the coordinates . Verify gps1 position is near the coordinates . Save the configuration to startup configuration and reboot . Verify both GPS receivers are activated -. Verify both GPS receivers have a fix +. Verify both GPS receivers report full position data +. Verify both GPS receivers have a satellite fix . Verify gps0 position is near the coordinates . Verify gps1 position is near the coordinates diff --git a/test/case/hardware/gps_simple/test.py b/test/case/hardware/gps_simple/test.py index beb87267..28e2dd5f 100755 --- a/test/case/hardware/gps_simple/test.py +++ b/test/case/hardware/gps_simple/test.py @@ -84,7 +84,11 @@ with infamy.Test() as test: until(lambda: gps.is_activated(target, "gps0"), attempts=500) until(lambda: gps.is_activated(target, "gps1"), attempts=500) - with test.step("Verify both GPS receivers have a fix"): + with test.step("Verify both GPS receivers report full position data"): + until(lambda: gps.has_position(target, "gps0"), attempts=60) + until(lambda: gps.has_position(target, "gps1"), attempts=60) + + with test.step("Verify both GPS receivers have a satellite fix"): until(lambda: gps.has_fix(target, "gps0"), attempts=60) until(lambda: gps.has_fix(target, "gps1"), attempts=60) @@ -106,7 +110,11 @@ with infamy.Test() as test: until(lambda: gps.is_activated(target, "gps0"), attempts=500) until(lambda: gps.is_activated(target, "gps1"), attempts=500) - with test.step("Verify both GPS receivers have a fix"): + with test.step("Verify both GPS receivers report full position data"): + until(lambda: gps.has_position(target, "gps0"), attempts=60) + until(lambda: gps.has_position(target, "gps1"), attempts=60) + + with test.step("Verify both GPS receivers have a satellite fix"): until(lambda: gps.has_fix(target, "gps0"), attempts=60) until(lambda: gps.has_fix(target, "gps1"), attempts=60) diff --git a/test/infamy/gps.py b/test/infamy/gps.py index d3743a50..3ec9e31d 100644 --- a/test/infamy/gps.py +++ b/test/infamy/gps.py @@ -208,3 +208,13 @@ def has_fix(target, name="gps0"): if not state: return False return state.get("fix-mode") in ("2d", "3d") + + +def has_position(target, name="gps0"): + """Check if GPS has a fix and all position fields are populated.""" + state = get_gps_state(target, name) + if not state: + return False + if state.get("fix-mode") not in ("2d", "3d"): + return False + return all(k in state for k in ("latitude", "longitude", "altitude", "satellites-used"))