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 <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2026-03-20 17:05:36 +01:00
parent 1c6c7724b9
commit cf08b577ed
3 changed files with 24 additions and 4 deletions
+4 -2
View File
@@ -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
+10 -2
View File
@@ -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)
+10
View File
@@ -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"))