Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 40 additions & 9 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
# Copyright 2024-2026 Lager Data
# SPDX-License-Identifier: Apache-2.0
#
# CLI unit tests. These need no hardware and no box, so they run on a
# GitHub-hosted runner and are safe to gate pull requests (no self-hosted
# runner is exposed to fork PRs here).
# Non-hardware unit tests. They need no bench and no self-hosted runner, so
# they run on GitHub-hosted ubuntu-latest and gate pull requests.
#
# Each suite runs as its OWN matrix job because the suites cannot share a
# pytest process: test/unit/measurement/conftest.py stubs the `lager` package
# in sys.modules (to avoid heavy box deps), which breaks box-side collection.
# `--import-mode=importlib` avoids clashes between same-named test modules
# across suites, and `-c /dev/null` ignores any repo-level pytest config.
#
# test/unit/box/ is NOT in the matrix yet: on GitHub-hosted runners `import
# lager` resolves as a namespace package ("unknown location") and several
# files fail collection — not reproducible locally or in a plain
# python:3.11 container. Wiring it up is tracked as a follow-up.

name: Unit Tests

Expand All @@ -15,9 +25,29 @@ on:

jobs:
unit-tests:
name: CLI unit tests
name: unit (${{ matrix.name }})
runs-on: ubuntu-latest
timeout-minutes: 10
timeout-minutes: 15
env:
# Some suites import box-side code, and some tests spawn subprocesses
# that import `test.*`. Put repo root and box/ on PYTHONPATH so both
# resolve consistently — in-process AND in subprocesses — regardless
# of how pytest is invoked.
PYTHONPATH: ${{ github.workspace }}:${{ github.workspace }}/box
strategy:
fail-fast: false
matrix:
include:
- name: cli
path: test/unit/cli/
- name: measurement
path: test/unit/measurement/
- name: blufi
path: test/unit/blufi/
- name: mcp
path: test/mcp/unit/
- name: root
path: test/unit/test_*.py test/test_*.py

steps:
- name: Checkout repository
Expand All @@ -28,12 +58,13 @@ jobs:
with:
python-version: '3.11'

- name: Install lager CLI (editable) + pytest
- name: Install CLI + test deps
run: |
pip install -e cli/
pip install pytest
pip install pytest pytest-timeout
pip install -r test/requirements-unit.txt
shell: bash

- name: Run CLI unit tests
run: pytest test/unit/cli/ -v
- name: Run ${{ matrix.name }} unit tests
run: pytest ${{ matrix.path }} -v --import-mode=importlib -c /dev/null --timeout=60
shell: bash
25 changes: 25 additions & 0 deletions test/requirements-unit.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright 2024-2026 Lager Data
# SPDX-License-Identifier: Apache-2.0
#
# Runtime dependencies required to IMPORT the code under test so the
# non-hardware unit suites can run headless on a GitHub-hosted runner:
# test/unit/cli/ test/unit/measurement/ test/unit/blufi/ test/mcp/unit/
# test/unit/test_*.py test/test_*.py
#
# Hardware SDKs (joulescope, ppk2_api, yoctopuce, labjack-ljm, brainstem,
# uldaq, phidget22, pyftdi, ...) are intentionally NOT listed: the test
# conftests mock them, and the unit tests load individual modules by path to
# avoid importing them. Everything here is a pure-Python wheel.
numpy
simplejson
pyvisa
pyvisa-py
flask
pyserial
pyusb
cryptography
fastmcp
pexpect
Comment on lines +13 to +22

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The dependencies listed here are completely unpinned. To ensure reproducible CI runs and prevent unexpected breakages when new versions of these packages are released, it is highly recommended to pin these dependencies to specific versions (e.g., numpy==1.26.4) or at least define compatible version ranges (e.g., numpy>=1.24.0,<2.0.0).

# NB: pymupdf (PyMuPDF) is intentionally NOT listed — it is AGPL-3.0, which
# conflicts with this project's Apache-2.0 license. Without it,
# test/unit/test_pdf_pages.py skips (it importorskips fitz); that's acceptable.
Loading