fix(voice_mode): restore audio-env detection across clean/WSL/Termux scenarios
Some checks failed
Nix / nix (macos-latest) (pull_request) Waiting to run
Contributor Attribution Check / check-attribution (pull_request) Failing after 26s
Supply Chain Audit / Scan PR for critical supply chain risks (pull_request) Successful in 30s
Tests / e2e (pull_request) Successful in 1m48s
Nix / nix (ubuntu-latest) (pull_request) Failing after 9m42s
Tests / test (pull_request) Failing after 13m59s
Some checks failed
Nix / nix (macos-latest) (pull_request) Waiting to run
Contributor Attribution Check / check-attribution (pull_request) Failing after 26s
Supply Chain Audit / Scan PR for critical supply chain risks (pull_request) Successful in 30s
Tests / e2e (pull_request) Successful in 1m48s
Nix / nix (ubuntu-latest) (pull_request) Failing after 9m42s
Tests / test (pull_request) Failing after 13m59s
Commit 5e1197a4 swapped the inline `os.path.exists('/.dockerenv')` check in
`detect_audio_environment()` for the more thorough `is_container()` helper
in `hermes_constants` (also matches /run/.containerenv and /proc/1/cgroup
markers, with module-level caching). That helper correctly returns True on
CI runners that themselves run inside Docker, which silently appended a
"Running inside Docker container" warning to every detection scenario and
broke four tests whose contract is "should be available":
- test_clean_environment_is_available
- test_wsl_with_pulse_allows_voice
- test_wsl_device_query_fails_with_pulse_continues
- test_termux_api_microphone_allows_voice_without_sounddevice
The five "should be blocked" sibling tests passed only by coincidence —
the extra container warning still left `available=False`.
Fix:
- Hoist `is_container` to a module-level import in tools/voice_mode.py
so it's reachable as `tools.voice_mode.is_container` (matches the
monkeypatch convention used elsewhere in the test file for `shutil`,
`_import_audio`, `_termux_api_app_installed`, etc).
- Add an autouse fixture in `TestDetectAudioEnvironment` defaulting
`is_container` to False, so tests don't inherit the host runner's
container state. Per `feedback_no_such_thing_as_flakes`: the failures
were a real environmental coupling bug, not a flake.
- Add `test_docker_container_blocks_voice` to preserve and pin the
container-blocks-voice intent that the original inline check encoded.
Partial close hermes-agent#9.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1f8926cc96
commit
a4fc156c8d
@ -61,6 +61,16 @@ def mock_sd(monkeypatch):
|
||||
# ============================================================================
|
||||
|
||||
class TestDetectAudioEnvironment:
|
||||
@pytest.fixture(autouse=True)
|
||||
def _isolate_container_detection(self, monkeypatch):
|
||||
"""Default `is_container` to False so tests don't inherit the host
|
||||
runner's container state (e.g. CI itself runs inside Docker, where
|
||||
the production `is_container()` returns True via /.dockerenv or
|
||||
/proc/1/cgroup and silently appended a 'Running inside Docker'
|
||||
warning to every scenario). Individual tests opt in via setattr.
|
||||
"""
|
||||
monkeypatch.setattr("tools.voice_mode.is_container", lambda: False)
|
||||
|
||||
def test_clean_environment_is_available(self, monkeypatch):
|
||||
"""No SSH, Docker, or WSL — should be available."""
|
||||
monkeypatch.delenv("SSH_CLIENT", raising=False)
|
||||
@ -85,6 +95,20 @@ class TestDetectAudioEnvironment:
|
||||
assert result["available"] is False
|
||||
assert any("SSH" in w for w in result["warnings"])
|
||||
|
||||
def test_docker_container_blocks_voice(self, monkeypatch):
|
||||
"""Running inside a Docker/Podman container should block voice mode."""
|
||||
monkeypatch.delenv("SSH_CLIENT", raising=False)
|
||||
monkeypatch.delenv("SSH_TTY", raising=False)
|
||||
monkeypatch.delenv("SSH_CONNECTION", raising=False)
|
||||
monkeypatch.setattr("tools.voice_mode.is_container", lambda: True)
|
||||
monkeypatch.setattr("tools.voice_mode._import_audio",
|
||||
lambda: (MagicMock(), MagicMock()))
|
||||
|
||||
from tools.voice_mode import detect_audio_environment
|
||||
result = detect_audio_environment()
|
||||
assert result["available"] is False
|
||||
assert any("Docker container" in w for w in result["warnings"])
|
||||
|
||||
def test_wsl_without_pulse_blocks_voice(self, monkeypatch, tmp_path):
|
||||
"""WSL without PULSE_SERVER should block voice mode."""
|
||||
monkeypatch.delenv("SSH_CLIENT", raising=False)
|
||||
|
||||
@ -49,7 +49,7 @@ def _audio_available() -> bool:
|
||||
return False
|
||||
|
||||
|
||||
from hermes_constants import is_termux as _is_termux_environment
|
||||
from hermes_constants import is_container, is_termux as _is_termux_environment
|
||||
|
||||
|
||||
def _voice_capture_install_hint() -> str:
|
||||
@ -103,7 +103,6 @@ def detect_audio_environment() -> dict:
|
||||
warnings.append("Running over SSH -- no audio devices available")
|
||||
|
||||
# Docker/Podman container detection
|
||||
from hermes_constants import is_container
|
||||
if is_container():
|
||||
warnings.append("Running inside Docker container -- no audio devices")
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user