Merge remote-tracking branch 'origin/dev' into dev
# Conflicts: # .gitignore
This commit is contained in:
@@ -49,10 +49,8 @@ apps/web/dist/
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
/.stoneforge/.worktrees/
|
/.stoneforge/.worktrees/
|
||||||
|
|
||||||
# Pi / agent cache
|
# Pi / agent cache
|
||||||
.pi/
|
.pi/
|
||||||
.atl/
|
.atl/
|
||||||
.sisyphus/
|
.sisyphus/
|
||||||
.pi-lens/
|
.pi-lens/
|
||||||
|
|
||||||
|
|||||||
@@ -147,8 +147,9 @@ def get_container_id(instance_name: str) -> str | None:
|
|||||||
Returns:
|
Returns:
|
||||||
Container ID or None if not found
|
Container ID or None if not found
|
||||||
"""
|
"""
|
||||||
|
# Docker container names are lowercase internally; normalize to ensure match
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["docker", "ps", "-a", "-q", "--filter", f"name={instance_name}"],
|
["docker", "ps", "-a", "-q", "--filter", f"name={instance_name.lower()}"],
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
)
|
)
|
||||||
@@ -169,6 +170,7 @@ def get_container_name(instance_name: str) -> str | None:
|
|||||||
Returns:
|
Returns:
|
||||||
Container name or None if not found
|
Container name or None if not found
|
||||||
"""
|
"""
|
||||||
|
# Docker container names are lowercase internally; normalize to ensure match
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
[
|
[
|
||||||
"docker",
|
"docker",
|
||||||
@@ -177,7 +179,7 @@ def get_container_name(instance_name: str) -> str | None:
|
|||||||
"--format",
|
"--format",
|
||||||
"{{.Names}}",
|
"{{.Names}}",
|
||||||
"--filter",
|
"--filter",
|
||||||
f"name={instance_name}",
|
f"name={instance_name.lower()}",
|
||||||
],
|
],
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
@@ -403,6 +405,11 @@ def start_cloudflared_tunnel(
|
|||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
url = None
|
url = None
|
||||||
|
|
||||||
|
if proc.stdout is None:
|
||||||
|
proc.terminate()
|
||||||
|
proc.wait(timeout=5)
|
||||||
|
raise RuntimeError("Failed to capture cloudflared output")
|
||||||
|
|
||||||
while time.time() - start_time < timeout:
|
while time.time() - start_time < timeout:
|
||||||
# Read available output
|
# Read available output
|
||||||
import select
|
import select
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
"""Unit tests for docker service utilities."""
|
||||||
|
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
from src.services.docker import get_container_id, get_container_name
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetContainerId:
|
||||||
|
"""Tests for get_container_id."""
|
||||||
|
|
||||||
|
@patch("subprocess.run")
|
||||||
|
def test_lowercases_name_for_filter(self, mock_run) -> None:
|
||||||
|
"""Docker ps name filter is case-sensitive; we must lowercase."""
|
||||||
|
mock_run.return_value = MagicMock(returncode=0, stdout="abc123\n")
|
||||||
|
|
||||||
|
result = get_container_id("MyContainer-ABC")
|
||||||
|
|
||||||
|
assert result == "abc123"
|
||||||
|
call_args = mock_run.call_args[0][0]
|
||||||
|
# The filter must use lowercase
|
||||||
|
assert "name=mycontainer-abc" in call_args
|
||||||
|
|
||||||
|
@patch("subprocess.run")
|
||||||
|
def test_returns_none_when_not_found(self, mock_run) -> None:
|
||||||
|
mock_run.return_value = MagicMock(returncode=0, stdout="")
|
||||||
|
|
||||||
|
result = get_container_id("missing")
|
||||||
|
|
||||||
|
assert result is None
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetContainerName:
|
||||||
|
"""Tests for get_container_name."""
|
||||||
|
|
||||||
|
@patch("subprocess.run")
|
||||||
|
def test_lowercases_name_for_filter(self, mock_run) -> None:
|
||||||
|
"""Docker ps name filter is case-sensitive; we must lowercase."""
|
||||||
|
mock_run.return_value = MagicMock(returncode=0, stdout="mycontainer-abc\n")
|
||||||
|
|
||||||
|
result = get_container_name("MyContainer-ABC")
|
||||||
|
|
||||||
|
assert result == "mycontainer-abc"
|
||||||
|
call_args = mock_run.call_args[0][0]
|
||||||
|
assert "name=mycontainer-abc" in call_args
|
||||||
|
|
||||||
|
@patch("subprocess.run")
|
||||||
|
def test_returns_none_when_not_found(self, mock_run) -> None:
|
||||||
|
mock_run.return_value = MagicMock(returncode=0, stdout="")
|
||||||
|
|
||||||
|
result = get_container_name("missing")
|
||||||
|
|
||||||
|
assert result is None
|
||||||
Reference in New Issue
Block a user