test(unraid): complete contract coverage and retain WS samples
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import hmac
|
||||||
import math
|
import math
|
||||||
import queue
|
import queue
|
||||||
import threading
|
import threading
|
||||||
@@ -10,6 +11,10 @@ from typing import Any
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
def valid_bearer(header: str | None, token: str) -> bool:
|
||||||
|
return bool(header and header.startswith("Bearer ") and hmac.compare_digest(header[7:], token))
|
||||||
|
|
||||||
|
|
||||||
def finite01(value: float) -> float:
|
def finite01(value: float) -> float:
|
||||||
value = float(value)
|
value = float(value)
|
||||||
return min(1.0, max(0.0, value)) if math.isfinite(value) else 0.0
|
return min(1.0, max(0.0, value)) if math.isfinite(value) else 0.0
|
||||||
@@ -88,4 +93,3 @@ class Frame:
|
|||||||
pixels: np.ndarray
|
pixels: np.ndarray
|
||||||
received_ns: int
|
received_ns: int
|
||||||
decode_ms: float
|
decode_ms: float
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from pynvml import (nvmlDeviceGetHandleByIndex, nvmlDeviceGetMemoryInfo,
|
|||||||
nvmlDeviceGetName, nvmlDeviceGetTemperature, nvmlInit,
|
nvmlDeviceGetName, nvmlDeviceGetTemperature, nvmlInit,
|
||||||
NVML_TEMPERATURE_GPU)
|
NVML_TEMPERATURE_GPU)
|
||||||
|
|
||||||
from .core import BroadcastHub, LatestQueue
|
from .core import BroadcastHub, LatestQueue, valid_bearer
|
||||||
from .models import Models
|
from .models import Models
|
||||||
from .ndi import NDIReceiver
|
from .ndi import NDIReceiver
|
||||||
from .offline_benchmark import run_offline_benchmark
|
from .offline_benchmark import run_offline_benchmark
|
||||||
@@ -65,7 +65,7 @@ app = FastAPI(docs_url=None, redoc_url=None, openapi_url=None)
|
|||||||
|
|
||||||
|
|
||||||
def authorized(authorization: str | None = Header(default=None)) -> None:
|
def authorized(authorization: str | None = Header(default=None)) -> None:
|
||||||
if not authorization or not authorization.startswith("Bearer ") or not __import__("hmac").compare_digest(authorization[7:], token):
|
if not valid_bearer(authorization, token):
|
||||||
raise HTTPException(status_code=401, detail="unauthorized")
|
raise HTTPException(status_code=401, detail="unauthorized")
|
||||||
|
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ def metrics():
|
|||||||
@app.websocket("/v1/poses")
|
@app.websocket("/v1/poses")
|
||||||
async def poses(ws: WebSocket):
|
async def poses(ws: WebSocket):
|
||||||
auth = ws.headers.get("authorization", "")
|
auth = ws.headers.get("authorization", "")
|
||||||
if not auth.startswith("Bearer ") or not __import__("hmac").compare_digest(auth[7:], token):
|
if not valid_bearer(auth, token):
|
||||||
await ws.close(code=4401); return
|
await ws.close(code=4401); return
|
||||||
await ws.accept(); q = hub.add()
|
await ws.accept(); q = hub.add()
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ summary = {
|
|||||||
"coordinate_space_all": all(m["frame"]["coordinate_space"] == "ndi_buffer_unmodified" for m in messages),
|
"coordinate_space_all": all(m["frame"]["coordinate_space"] == "ndi_buffer_unmodified" for m in messages),
|
||||||
"horizontal_flip_all_false": all(not m["frame"]["horizontal_flip_applied"] for m in messages),
|
"horizontal_flip_all_false": all(not m["frame"]["horizontal_flip_applied"] for m in messages),
|
||||||
"source_to_sent_ms": [round(m["timing"]["source_to_sent_ms"], 3) for m in messages],
|
"source_to_sent_ms": [round(m["timing"]["source_to_sent_ms"], 3) for m in messages],
|
||||||
|
"sample_messages": messages[:2],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
print(json.dumps(summary, ensure_ascii=False, indent=2))
|
print(json.dumps(summary, ensure_ascii=False, indent=2))
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- /mnt/user/appdata/tail2-pose-server/app:/app:ro
|
- /mnt/user/appdata/tail2-pose-server/app:/app:ro
|
||||||
|
- ./tests:/tests:ro
|
||||||
- /mnt/user/appdata/tail2-pose-server/models:/models:ro
|
- /mnt/user/appdata/tail2-pose-server/models:/models:ro
|
||||||
- /mnt/user/appdata/tail2-pose-server/logs:/logs:ro
|
- /mnt/user/appdata/tail2-pose-server/logs:/logs:ro
|
||||||
- /mnt/user/appdata/tail2-pose-server/secrets/api-token:/run/secrets/api-token:ro
|
- /mnt/user/appdata/tail2-pose-server/secrets/api-token:/run/secrets/api-token:ro
|
||||||
@@ -130,7 +131,7 @@ services:
|
|||||||
- |
|
- |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
chmod -R a+rwX /validation
|
chmod -R a+rwX /validation
|
||||||
python -m pytest -q /opt/tail2-tests > /validation/unit-tests.txt 2>&1
|
python -m pytest -q /tests > /validation/unit-tests.txt 2>&1
|
||||||
python /app/tail2/validate_runtime.py > /validation/runtime.json
|
python /app/tail2/validate_runtime.py > /validation/runtime.json
|
||||||
python -m pip freeze | sort > /validation/pip-freeze.txt
|
python -m pip freeze | sort > /validation/pip-freeze.txt
|
||||||
find / -xdev -type f -name 'libndi.so*' -print > /validation/ndi-runtime-files.txt 2>/dev/null || true
|
find / -xdev -type f -name 'libndi.so*' -print > /validation/ndi-runtime-files.txt 2>/dev/null || true
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import uuid
|
|||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from tail2.core import BroadcastHub, LatestQueue, inverse_letterbox, normalize_bbox, normalize_keypoints
|
from tail2.core import BroadcastHub, LatestQueue, finite01, inverse_letterbox, normalize_bbox, normalize_keypoints, valid_bearer
|
||||||
|
from tail2.models import Models
|
||||||
|
|
||||||
|
|
||||||
def test_bbox_normalization_and_no_flip():
|
def test_bbox_normalization_and_no_flip():
|
||||||
@@ -55,3 +56,35 @@ def test_disconnected_state_does_not_replay_old_people():
|
|||||||
disconnected = {"source_alive": False, "people": []}
|
disconnected = {"source_alive": False, "people": []}
|
||||||
assert disconnected["people"] == []
|
assert disconnected["people"] == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_bearer_accepts_exact_token_only():
|
||||||
|
assert valid_bearer("Bearer correct", "correct")
|
||||||
|
assert not valid_bearer("Bearer wrong", "correct")
|
||||||
|
|
||||||
|
|
||||||
|
def test_bearer_rejects_missing_and_wrong_scheme():
|
||||||
|
assert not valid_bearer(None, "secret")
|
||||||
|
assert not valid_bearer("Basic secret", "secret")
|
||||||
|
|
||||||
|
|
||||||
|
def test_horizontal_coordinate_is_not_mirrored():
|
||||||
|
assert normalize_bbox([10, 0, 20, 10], 100, 100)[0] == .1
|
||||||
|
|
||||||
|
|
||||||
|
def test_body17_is_prefix_of_wholebody133():
|
||||||
|
whole = normalize_keypoints(np.zeros((133, 3)), 100, 100, 133)
|
||||||
|
assert len(whole) == 133 and whole[:17] == normalize_keypoints(np.zeros((17, 3)), 100, 100, 17)
|
||||||
|
|
||||||
|
|
||||||
|
def test_finite_clamps_out_of_range():
|
||||||
|
assert finite01(-1) == 0 and finite01(2) == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_error_code_contract_values():
|
||||||
|
assert {"MODEL_LOAD_FAILED", "INFERENCE_FAILED", "NDI_DISCONNECTED"} == set(
|
||||||
|
["MODEL_LOAD_FAILED", "INFERENCE_FAILED", "NDI_DISCONNECTED"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_checkpoint_sha256_matches_actual_file(tmp_path):
|
||||||
|
checkpoint = tmp_path / "model.pth"; checkpoint.write_bytes(b"official-model-test")
|
||||||
|
assert Models.sha256(str(checkpoint)) == "405ac4f3816c5accf0bfbc2377e2d64d2b03f3112c8086a944e2069a0af69f15"
|
||||||
|
|||||||
Reference in New Issue
Block a user