feat: make the docker binary path a hook
Where docker lives is device-specific; what to do with it is not. QNAP's Container Station installs docker under /share/<pool>/.qpkg/ and never puts it on PATH, so a QTS driver inheriting this class found no docker at all. Rather than reimplementing the Docker surface in the vendor driver, the path becomes a single overridable method and every call site goes through it. Per docs/ARCHITECTURE.md 4.4, generic logic belongs to the shared driver and only the device-specific mechanics belong to the vendor one. A test asserts that *every* docker call site uses the hook — a half converted set would let detection find the binary while the actual queries still missed it, which only shows up against real hardware.
This commit is contained in:
@@ -802,3 +802,54 @@ class TestRunDeviceActionDispatch:
|
||||
) as mock_action:
|
||||
driver.run_device_action("apt_update_upgrade")
|
||||
mock_action.assert_called_once()
|
||||
|
||||
|
||||
class TestDockerBinHook:
|
||||
"""Where the docker binary lives is device-specific; what to do with it is not.
|
||||
|
||||
QTS puts Container Station's docker under /share/<pool>/.qpkg/ and not on
|
||||
PATH. Rather than duplicating the whole Docker surface in the QNAP driver,
|
||||
the path is a one-method hook here and the logic stays generic. See
|
||||
docs/ARCHITECTURE.md §4.4, "Generisch vs. treiberspezifisch".
|
||||
"""
|
||||
|
||||
def test_defaults_to_docker_on_path(self, driver):
|
||||
assert driver._docker_bin() == "docker"
|
||||
|
||||
def test_detection_uses_the_hook(self, driver):
|
||||
"""A subclass pointing elsewhere must not be probed for a PATH docker."""
|
||||
sent = []
|
||||
|
||||
def _record(cmd, **kwargs):
|
||||
sent.append(cmd)
|
||||
return ""
|
||||
|
||||
with patch.object(driver, "_docker_bin", return_value="/opt/cs/docker"):
|
||||
with patch.object(driver, "_send", side_effect=_record):
|
||||
result = driver.get_docker_info()
|
||||
|
||||
assert result == {"available": False}
|
||||
assert any("/opt/cs/docker" in cmd for cmd in sent)
|
||||
assert not any("command -v docker " in cmd for cmd in sent)
|
||||
|
||||
def test_all_docker_subcommands_use_the_hook(self, driver):
|
||||
"""Half-converted call sites are the failure mode here: detection would
|
||||
find the binary and the actual queries would still miss it."""
|
||||
sent = []
|
||||
|
||||
def _record(cmd, **kwargs):
|
||||
sent.append(cmd)
|
||||
if "command -v" in cmd:
|
||||
return "/opt/cs/docker"
|
||||
if "---CONTAINERS---" in cmd:
|
||||
return "---CONTAINERS---\n---IMAGES---\n---VOLUMES---\n---NETWORKS---\n"
|
||||
return ""
|
||||
|
||||
with patch.object(driver, "_docker_bin", return_value="/opt/cs/docker"):
|
||||
with patch.object(driver, "_send", side_effect=_record):
|
||||
driver.get_docker_info()
|
||||
|
||||
docker_cmds = [c for c in sent if "docker" in c]
|
||||
assert docker_cmds
|
||||
for cmd in docker_cmds:
|
||||
assert "/opt/cs/docker" in cmd, f"unconverted call site: {cmd}"
|
||||
|
||||
Reference in New Issue
Block a user