fix(test): pi3 bme280 attach test sys.path + block-read race

Two small fixes after running the test inside the prod container for
the first time:

- The prod image lays out the backend at /app/app/, not /app/backend/app/
  (the Dockerfile.standalone COPYs only the inner package). Use /app
  as the sys.path root so `from app.pro.services import ...` resolves.
- The CHIP=0x60 and BLOCK= prints race against the socket drain. The
  test was treating "saw CHIP= but BLOCK= not in buffer yet" as a
  hard failure and exiting before the second I2C read finished.
  Gate the success path on both markers present and keep polling
  otherwise.

Verified end-to-end in the prod container:

    [proto] >>> ['I2C', '1', '76', 'RR', 'd0', '1']
    [proto] <<< I2C_DATA 1 76 60
    [proto] >>> ['I2C', '1', '76', 'RR', 'f7', '8']
    [proto] <<< I2C_DATA 1 76 530280155e607b50
    [test] OK — guest read chip ID = 0x60
    [test] OK — block read BLOCK=530280155e607b50

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
davidmonterocrespo24 2026-05-18 20:39:12 +02:00
parent 33cca9f08a
commit ebace63ae5
1 changed files with 12 additions and 8 deletions

View File

@ -44,8 +44,10 @@ import threading
import time
from pathlib import Path
# Make `app.*` resolvable (mirrors conftest in pro/backend/tests).
sys.path.insert(0, '/app/backend')
# Make `app.*` resolvable. Inside the prod container the backend
# package lives at /app/app/ — the pro overlay is COPYed beside it
# at build time as /app/app/pro/.
sys.path.insert(0, '/app')
BOOT_IMAGES = Path('/var/cache/velxio/boot-images/raspberry-pi-3-virt')
KERNEL = BOOT_IMAGES / 'velxio-kernel-arm64'
@ -231,21 +233,23 @@ def run() -> int:
sock.sendall(cmd)
sent_test = True
if sent_test and b'CHIP=0x60' in buf:
if sent_test and b'CHIP=0x60' in buf and b'BLOCK=' in buf:
print('[test] OK — guest read chip ID = 0x60')
# Also check that BLOCK= came back as 16 hex chars (8 bytes)
txt = buf.decode('utf-8', 'replace')
for ln in txt.splitlines():
if ln.startswith('BLOCK='):
if len(ln) - len('BLOCK=') == 16:
# Allow trailing CR / ANSI from the shell echo
value = ln[len('BLOCK='):].strip().split()[0]
if len(value) == 16:
print(f'[test] OK — block read {ln}')
return 0
print(f'FAIL: block length wrong: {ln}',
print(f'FAIL: block length wrong ({len(value)}): {ln}',
file=sys.stderr)
return 1
print('FAIL: chip id OK but no block readback observed',
file=sys.stderr)
return 1
# Fall through: BLOCK= present but no parseable line yet,
# keep draining
continue
if sent_test and (b'Traceback' in buf or b'ModuleNotFoundError' in buf):
print('FAIL: guest python raised:', file=sys.stderr)