CAPTURE_PATH defaulted to index 0, which is a coin flip on a machine with one camera. A UVC camera exposes a second device node for its metadata stream -- /dev/video1 beside /dev/video0 -- and that node opens happily and never yields an image, so the lowest device number is wrong about as often as it is right. With neither CAMERA_ID nor CAPTURE_PATH set, the node now opens each /dev/video* in numeric order and keeps the first that actually delivers a frame. Reading one is the test, because opening is not evidence. Discovery finding nothing falls back to index 0 rather than raising, which keeps the failure in one place: the first read, where CI publishes a placeholder and a normal run raises with a message naming the device. CAMERA_ID is still worth preferring on a robot. Neither an index nor discovery order is stable across reboots or across which port a camera is in; a by-id name is.
This commit is contained in:
@@ -18,6 +18,51 @@ def frame() -> np.ndarray:
|
||||
return rng.integers(0, 255, (HEIGHT, WIDTH, 3), dtype=np.uint8)
|
||||
|
||||
|
||||
def test_discovery_skips_a_device_that_opens_but_never_yields_a_frame(monkeypatch):
|
||||
# A UVC camera exposes a metadata node beside the capture node; it opens
|
||||
# and reads nothing, so the lowest device number is the wrong one to take.
|
||||
monkeypatch.setattr(camera, "_devices", lambda: ["/dev/video0", "/dev/video1"])
|
||||
monkeypatch.setattr(camera, "_yields_frame", lambda path: path == "/dev/video1")
|
||||
|
||||
assert camera.discover() == "/dev/video1"
|
||||
|
||||
|
||||
def test_discovery_returns_none_when_nothing_captures(monkeypatch):
|
||||
monkeypatch.setattr(camera, "_devices", lambda: ["/dev/video0"])
|
||||
monkeypatch.setattr(camera, "_yields_frame", lambda path: False)
|
||||
|
||||
assert camera.discover() is None
|
||||
|
||||
|
||||
def test_devices_are_ordered_numerically(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
camera.glob, "glob",
|
||||
lambda pattern: ["/dev/video10", "/dev/video2", "/dev/video1"],
|
||||
)
|
||||
|
||||
assert camera._devices() == ["/dev/video1", "/dev/video2", "/dev/video10"]
|
||||
|
||||
|
||||
def test_an_unset_device_is_discovered(monkeypatch):
|
||||
monkeypatch.setattr(camera, "discover", lambda: "/dev/video3")
|
||||
|
||||
assert camera.resolve(None, None) == "/dev/video3"
|
||||
|
||||
|
||||
def test_an_unset_device_falls_back_when_nothing_is_found(monkeypatch):
|
||||
# Falling back rather than raising keeps the failure in one place: the
|
||||
# first read, which under CI publishes a placeholder instead of raising.
|
||||
monkeypatch.setattr(camera, "discover", lambda: None)
|
||||
|
||||
assert camera.resolve(None, None) == camera.FALLBACK
|
||||
|
||||
|
||||
def test_an_explicit_device_is_not_overridden_by_discovery(monkeypatch):
|
||||
monkeypatch.setattr(camera, "discover", lambda: "/dev/video9")
|
||||
|
||||
assert camera.resolve(None, "/dev/video4") == "/dev/video4"
|
||||
|
||||
|
||||
def test_a_numeric_capture_path_is_read_as_an_index():
|
||||
assert camera.resolve(None, "1") == 1
|
||||
|
||||
|
||||
Reference in New Issue
Block a user