Files
Unraid-AppOps-Gateway-Public/backend/tests/test_portainer_restart_timeout.py

142 lines
4.3 KiB
Python

from types import SimpleNamespace
import pytest
from backend.app.connectors.portainer import PortainerConnector
from backend.app.core.config import settings
CONTROLLER_OWNED_CI_NAMES = (
"itworx-ci-checks",
"itworx-ci-backend",
"itworx-ci-frontend",
"itworx-ci-security",
"itworx-ci-browser",
"itworx-ci-build",
"itworx-security-runner",
"itworx-validation-runner-2",
"itworx-validation-runner-3",
"itworx-docker-runner",
"itworx-browser-runner",
"itworx-validation-runner-burst-1",
"gitea-runner-dind",
)
def _connector_with_containers(monkeypatch, containers):
monkeypatch.setitem(settings.apis, "PORTAINER_URL", "https://portainer.example.test")
monkeypatch.setitem(settings.apis, "PORTAINER_API_KEY", "test-key")
monkeypatch.setitem(settings.apis, "PORTAINER_ENDPOINT_ID", "9")
connector = PortainerConnector()
monkeypatch.setattr(
connector,
"list_containers",
lambda: {"status": "ok", "containers": containers},
)
calls = []
def request(method: str, path: str, **kwargs):
calls.append((method, path, kwargs))
return SimpleNamespace(status_code=204)
monkeypatch.setattr(connector, "_request", request)
return connector, calls
def test_restart_request_allows_docker_grace_period_without_shortening_container_timeout(monkeypatch):
previous = dict(settings.apis)
settings.apis.update({
"PORTAINER_URL": "https://portainer.example.test",
"PORTAINER_API_KEY": "test-key",
"PORTAINER_ENDPOINT_ID": "9",
})
connector = PortainerConnector()
monkeypatch.setattr(
connector,
"list_containers",
lambda: {
"status": "ok",
"containers": [{"id": "user-container-id", "name": "jellyfin", "appId": "jellyfin"}],
},
)
calls: list[tuple[str, str, dict]] = []
def request(method: str, path: str, **kwargs):
calls.append((method, path, kwargs))
return SimpleNamespace(status_code=204)
monkeypatch.setattr(connector, "_request", request)
try:
result = connector.restart_container("jellyfin")
finally:
settings.apis.clear()
settings.apis.update(previous)
assert result["status"] == "ok"
assert calls == [(
"POST",
"/api/endpoints/9/docker/containers/user-container-id/restart",
{"timeout": 30.0},
)]
@pytest.mark.parametrize("container_name", CONTROLLER_OWNED_CI_NAMES)
def test_restart_blocks_fixed_controller_owned_ci_containers_by_name(monkeypatch, container_name):
connector, calls = _connector_with_containers(
monkeypatch,
[{"id": "0123456789abcdef0123456789abcdef", "name": container_name, "appId": "ci-stack"}],
)
result = connector.restart_container(container_name)
assert result == {"status": "blocked", "reason": "controller_owned_ci_lifecycle"}
assert calls == []
@pytest.mark.parametrize(
"target",
(
"itworx-ci-backend",
"0123456789abcdef0123456789abcdef",
"01234567",
"backend-ci-stack",
),
)
def test_restart_blocks_controller_owned_container_selected_by_alias(monkeypatch, target):
connector, calls = _connector_with_containers(
monkeypatch,
[{
"id": "0123456789abcdef0123456789abcdef",
"name": "itworx-ci-backend",
"appId": "backend-ci-stack",
}],
)
result = connector.restart_container(target)
assert result == {"status": "blocked", "reason": "controller_owned_ci_lifecycle"}
assert calls == []
@pytest.mark.parametrize("container_name", ("itworx-unraid-deploy", "jellyfin"))
def test_restart_still_allows_unrelated_deploy_and_user_containers(monkeypatch, container_name):
container_id = f"id-{container_name}"
connector, calls = _connector_with_containers(
monkeypatch,
[{"id": container_id, "name": container_name, "appId": container_name}],
)
result = connector.restart_container(container_name)
assert result == {
"status": "ok",
"container": container_id,
"target": container_name,
"action": "container.restart",
}
assert calls == [(
"POST",
f"/api/endpoints/9/docker/containers/{container_id}/restart",
{"timeout": 30.0},
)]