move_detect/tests/hardware/test_movenet_smoke.py
유창욱 6b6f29c447 feat: 납품 잔여 3건 해소 (Pi 번들 · MoveNet 폴백 · 자격증명 회전)
Pi 번들 — arm64 빌드 머신이 필요하다고 적어 둔 것은 과한 가정이었다.
--cross 모드에서 pip 이 태그로 aarch64/cp311 휠을 받으므로 네트워크만
있으면 된다. 휠 11개 전부 aarch64. "Pi 번들 미빌드"로 스킵되던 테스트가
이제 실제로 돈다.

MoveNet — P3-3 의 잔여였던 죽은 원본을 유효한 tf2onnx 변환본으로 교체하고
sha256+size 로 고정했다. 고정 전에 어댑터 계약과 대조했다: 입력
[1,192,192,3] int32 NHWC, 출력 [1,1,17,3]. 레이아웃이 다른 변환본은
onnxruntime 에 그냥 로드되고 좌표만 틀리는 실패라, 파일이 바뀌었는지가
아니라 계약이 맞는지를 테스트로 박았다.

자격증명 회전 — 손으로 적던 SQL 절차를 명령 하나로 바꿨다. DB 에 접속하지
않고 붙여넣을 SQL 만 낸다(운영자의 창구가 phpMyAdmin 이므로 접속 정보 없이
어느 머신에서나 돌아야 한다). 비밀번호는 STDIN 으로만 받는다 — 명령행은
ps 와 셸 히스토리에 남는다. 테스트가 잠그는 것은 서버 키와 Pi 키의 일치,
그리고 앱이 그 해시를 검증하는지 두 가지다. 회전 실행 자체는 운영 계정
조작이라 저장소에서 수행하지 않는다.

검증: phpunit 276 passed(스킵 0, 신규 7) · pytest 스킵 2(환경)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EBjuR7DW6PNNMows4KnbYU
2026-09-21 10:47:16 +09:00

47 lines
2.1 KiB
Python

"""Gated end-to-end smoke test for the real MoveNet ONNX model.
Skipped unless the model is bundled AND onnxruntime is installed, so the default
CI/dev suite (no model, no onnxruntime) stays green. On a build/pilot machine that
ran ``python -m edge.tools.fetch_movenet``, this exercises the full adapter path:
frame -> onnxruntime inference -> COCO-17 remap -> list[Person].
"""
import os
import numpy as np
import pytest
MODEL = os.path.join(os.path.dirname(__file__), "..", "..", "models", "movenet_lightning.onnx")
@pytest.mark.skipif(not os.path.exists(MODEL), reason="MoveNet model not bundled")
def test_real_movenet_runs():
pytest.importorskip("onnxruntime")
from edge.adapters.movenet_pose import MoveNetPoseAdapter
adapter = MoveNetPoseAdapter(MODEL)
persons = adapter.infer(np.full((480, 640, 3), 128, np.uint8))
# Runs end-to-end; a flat gray frame may yield 0 persons — the contract is
# only that it returns a list and, when non-empty, each Person has 17 keypoints.
assert isinstance(persons, list)
for person in persons:
assert len(person.keypoints) == 17
@pytest.mark.skipif(not os.path.exists(MODEL), reason="MoveNet model not bundled")
def test_model_signature_is_what_the_adapter_feeds_and_reads():
"""모델을 갈아끼웠을 때 조용히 틀리는 경우를 막는다.
레이아웃이 다른 변환본(NCHW·float32·[1,17,3])도 onnxruntime 에는 그냥 로드된다. 그러면
어댑터는 예외 없이 돌면서 엉뚱한 좌표를 내놓고, 낙상 판정은 "동작하는데 안 맞는" 상태가
된다. 파일이 바뀌었는지가 아니라 **계약이 맞는지**를 본다.
"""
ort = pytest.importorskip("onnxruntime")
session = ort.InferenceSession(MODEL, providers=["CPUExecutionProvider"])
inp = session.get_inputs()[0]
assert inp.shape == [1, 192, 192, 3], f"어댑터는 192x192 NHWC 를 넣는다: {inp.shape}"
assert inp.type == "tensor(int32)", f"어댑터는 int32 로 넣는다: {inp.type}"
out = session.get_outputs()[0]
assert out.shape == [1, 1, 17, 3], f"어댑터는 [1,1,17,3] (y,x,score) 를 읽는다: {out.shape}"