Back to Repositories

Testing Pigeond GPS Module Integration in openpilot

This test suite validates the functionality of the pigeond process in the openpilot system, focusing on GPS module initialization, message frequency, and hardware control. The tests ensure reliable GPS data handling and proper hardware management for the ublox module.

Test Coverage Overview

The test suite provides comprehensive coverage of pigeond functionality, including message frequency validation, startup performance, and hardware control verification.

  • Message frequency validation against service specifications
  • Startup time performance metrics
  • Hardware pin state verification for GPS module control
  • Edge case handling for various startup durations

Implementation Analysis

The testing approach utilizes pytest fixtures and process management helpers to ensure isolated and repeatable test execution. The implementation leverages cereal messaging system for communication verification and GPIO controls for hardware state validation.

  • Process isolation using @with_processes decorator
  • SubMaster usage for message monitoring
  • Timing validation with monotonic clock
  • Multiple iteration verification for consistency

Technical Details

  • pytest framework with custom markers (@pytest.mark.tici)
  • cereal messaging system for IPC
  • GPIO control interface for hardware management
  • Process management through managed_processes
  • Timing utilities for performance measurement

Best Practices Demonstrated

The test suite exemplifies several testing best practices, including proper test isolation, clear failure messages, and comprehensive error checking.

  • Proper teardown handling between tests
  • Explicit timing and performance requirements
  • Hardware state verification
  • Multiple iteration testing for reliability
  • Clear assertion messages for debugging

commaai/openpilot

system/ubloxd/tests/test_pigeond.py

            
import pytest
import time

import cereal.messaging as messaging
from cereal.services import SERVICE_LIST
from openpilot.common.gpio import gpio_read
from openpilot.selfdrive.test.helpers import with_processes
from openpilot.system.manager.process_config import managed_processes
from openpilot.system.hardware.tici.pins import GPIO


# TODO: test TTFF when we have good A-GNSS
@pytest.mark.tici
class TestPigeond:

  def teardown_method(self):
    managed_processes['pigeond'].stop()

  @with_processes(['pigeond'])
  def test_frequency(self):
    sm = messaging.SubMaster(['ubloxRaw'])

    # setup time
    for _ in range(int(5 * SERVICE_LIST['ubloxRaw'].frequency)):
      sm.update()

    for _ in range(int(10 * SERVICE_LIST['ubloxRaw'].frequency)):
      sm.update()
      assert sm.all_checks()

  def test_startup_time(self):
    for _ in range(5):
      sm = messaging.SubMaster(['ubloxRaw'])
      managed_processes['pigeond'].start()

      start_time = time.monotonic()
      for __ in range(10):
        sm.update(1 * 1000)
        if sm.updated['ubloxRaw']:
          break
      assert sm.recv_frame['ubloxRaw'] > 0, "pigeond didn't start outputting messages in time"

      et = time.monotonic() - start_time
      assert et < 5, f"pigeond took {et:.1f}s to start"
      managed_processes['pigeond'].stop()

  def test_turns_off_ublox(self):
    for s in (0.1, 0.5, 1, 5):
      managed_processes['pigeond'].start()
      time.sleep(s)
      managed_processes['pigeond'].stop()

      assert gpio_read(GPIO.UBLOX_RST_N) == 0
      assert gpio_read(GPIO.GNSS_PWR_EN) == 0