Retire review deploy and add live Actions
This commit is contained in:
@@ -15,9 +15,3 @@ def test_file_secret_env_vars_are_supported(tmp_path, monkeypatch):
|
||||
|
||||
assert settings.sab_api_key == "sab-secret"
|
||||
assert settings.auth_token == "auth-secret"
|
||||
|
||||
|
||||
def test_default_update_command_uses_installed_absolute_path(monkeypatch):
|
||||
monkeypatch.delenv("IMPORTARR_UPDATE_COMMAND", raising=False)
|
||||
|
||||
assert Settings.from_env().update_command == ["/bin/sh", "/opt/importarr/repo-upgrade.sh"]
|
||||
|
||||
@@ -18,7 +18,7 @@ def test_repo_upgrade_refuses_concurrent_run(tmp_path):
|
||||
with lock_path.open("w") as lock:
|
||||
fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
result = subprocess.run(
|
||||
["sh", str(script), "v1.2.3"],
|
||||
["sh", str(script)],
|
||||
env={
|
||||
**os.environ,
|
||||
"PATH": f"{bin_dir}:{os.environ['PATH']}",
|
||||
@@ -57,3 +57,17 @@ def test_repo_upgrade_forces_fresh_install_without_skipping_dependencies():
|
||||
|
||||
assert "pip\" install --upgrade --force-reinstall --no-cache-dir" in script
|
||||
assert "--no-deps" not in script
|
||||
|
||||
|
||||
def test_repo_upgrade_deploys_only_origin_main():
|
||||
script = (Path(__file__).parents[1] / "deploy/repo-upgrade.sh").read_text()
|
||||
|
||||
assert "git fetch --prune origin main" in script
|
||||
assert "git checkout -B main origin/main" in script
|
||||
assert "refs/tags" not in script
|
||||
|
||||
|
||||
def test_repo_upgrade_removes_obsolete_update_command():
|
||||
script = (Path(__file__).parents[1] / "deploy/repo-upgrade.sh").read_text()
|
||||
|
||||
assert "IMPORTARR_UPDATE_COMMAND=/d" in script
|
||||
|
||||
@@ -453,74 +453,6 @@ def test_worker_failure_stops_retrying_after_limit(tmp_path, monkeypatch):
|
||||
assert updated["attempt_count"] == main.MAX_RETRY_ATTEMPTS
|
||||
|
||||
|
||||
def test_control_update_schedules_configured_command_with_release_tag(tmp_path, monkeypatch):
|
||||
main, _download, _movies, _tv = configure_main(tmp_path, monkeypatch)
|
||||
main.settings.update_command = ["upgrade", "now"]
|
||||
monkeypatch.setattr(main, "check_update_available", lambda: {"status": "update_available", "current_version": "0.1.0", "latest_version": "0.2.0", "update_available": True, "release_url": None})
|
||||
|
||||
calls = []
|
||||
monkeypatch.setattr(main, "_schedule_update", calls.append)
|
||||
|
||||
result = main.update_service(expected_tag="0.2.0")
|
||||
|
||||
assert result["status"] == "update_scheduled"
|
||||
assert result["command"] == ["upgrade", "now", "0.2.0"]
|
||||
assert calls == [["upgrade", "now", "0.2.0"]]
|
||||
|
||||
|
||||
def test_control_update_skips_command_when_current(tmp_path, monkeypatch):
|
||||
main, _download, _movies, _tv = configure_main(tmp_path, monkeypatch)
|
||||
main.settings.update_command = ["upgrade", "now"]
|
||||
monkeypatch.setattr(main, "check_update_available", lambda: {"status": "current", "current_version": "0.2.0", "latest_version": "v0.2.0", "update_available": False, "release_url": None})
|
||||
|
||||
def fake_run(command, **kwargs):
|
||||
raise AssertionError("update command should not run without a newer release")
|
||||
|
||||
monkeypatch.setattr(main.subprocess, "run", fake_run)
|
||||
|
||||
result = main.update_service(expected_tag="v0.2.0")
|
||||
|
||||
assert result["status"] == "current"
|
||||
assert result["command"] == ["upgrade", "now"]
|
||||
assert result["update_available"] is False
|
||||
|
||||
|
||||
def test_update_check_compares_latest_release(tmp_path, monkeypatch):
|
||||
main, _download, _movies, _tv = configure_main(tmp_path, monkeypatch)
|
||||
monkeypatch.setenv("IMPORTARR_VERSION", "0.1.0")
|
||||
|
||||
class FakeResponse:
|
||||
def raise_for_status(self):
|
||||
return None
|
||||
|
||||
def json(self):
|
||||
return {"tag_name": "v0.2.0", "html_url": "https://example.test/releases/v0.2.0"}
|
||||
|
||||
class FakeClient:
|
||||
def __init__(self, timeout):
|
||||
self.timeout = timeout
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc, tb):
|
||||
return False
|
||||
|
||||
def get(self, url, headers):
|
||||
assert url == main.settings.update_release_url
|
||||
assert headers["Accept"] == "application/json"
|
||||
return FakeResponse()
|
||||
|
||||
monkeypatch.setattr(main.httpx, "Client", FakeClient)
|
||||
|
||||
result = main.check_update_available()
|
||||
|
||||
assert result["status"] == "update_available"
|
||||
assert result["current_version"] == "0.1.0"
|
||||
assert result["latest_version"] == "v0.2.0"
|
||||
assert result["update_available"] is True
|
||||
|
||||
|
||||
def test_control_restart_reports_command_failure(tmp_path, monkeypatch):
|
||||
main, _download, _movies, _tv = configure_main(tmp_path, monkeypatch)
|
||||
main.settings.restart_command = ["restart"]
|
||||
|
||||
+2
-75
@@ -69,7 +69,7 @@ def test_frontend_uses_required_stack_and_capabilities():
|
||||
assert "lucide-react" in package
|
||||
assert "@radix-ui/react-dialog" in package
|
||||
assert "tailwindcss" in package
|
||||
for endpoint in ("/api/jobs", "/api/settings", "/api/manual-batches", "/api/control/update", "/api/import/run-now"):
|
||||
for endpoint in ("/api/jobs", "/api/settings", "/api/manual-batches", "/api/import/run-now"):
|
||||
assert endpoint in app
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ def test_control_endpoints_require_configured_bearer_token(tmp_path, monkeypatch
|
||||
monkeypatch.setattr(main.settings, "auth_token", "test-token")
|
||||
client = TestClient(main.app)
|
||||
|
||||
for method, endpoint in (("get", "/api/control/update-check"), ("post", "/api/control/update"), ("post", "/api/control/restart")):
|
||||
for method, endpoint in (("post", "/api/control/restart"),):
|
||||
assert getattr(client, method)(endpoint).status_code == 401
|
||||
assert getattr(client, method)(endpoint, headers={"Authorization": "Bearer wrong"}).status_code == 401
|
||||
|
||||
@@ -178,76 +178,3 @@ def test_tokenless_local_development_remains_available(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(main.settings, "auth_token", None)
|
||||
monkeypatch.setattr(main.settings, "bind_host", "127.0.0.1")
|
||||
main.require_write_auth()
|
||||
|
||||
|
||||
def test_update_schedules_exact_latest_release_tag(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("IMPORTARR_STATE_PATH", str(tmp_path / "state.db"))
|
||||
import importarr.main as main
|
||||
|
||||
monkeypatch.setattr(main, "check_update_available", lambda: {"status": "update_available", "current_version": "v1.0.0", "latest_version": "v1.2.3", "update_available": True})
|
||||
monkeypatch.setattr(main.settings, "update_command", ["/opt/importarr/repo-upgrade.sh"])
|
||||
scheduled = []
|
||||
monkeypatch.setattr(main, "_schedule_update", scheduled.append)
|
||||
|
||||
response = main.update_service(expected_tag="v1.2.3")
|
||||
assert scheduled == [["/opt/importarr/repo-upgrade.sh", "v1.2.3"]]
|
||||
assert response["status"] == "update_scheduled"
|
||||
|
||||
|
||||
def test_update_is_scheduled_outside_service_cgroup(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("IMPORTARR_STATE_PATH", str(tmp_path / "state.db"))
|
||||
import importarr.main as main
|
||||
|
||||
calls = []
|
||||
|
||||
def fake_run(command, **kwargs):
|
||||
calls.append((command, kwargs))
|
||||
return main.subprocess.CompletedProcess(command, 0, stdout="Running as unit", stderr="")
|
||||
|
||||
monkeypatch.setattr(main.subprocess, "run", fake_run)
|
||||
main._schedule_update(["/bin/sh", "/opt/importarr/repo-upgrade.sh", "v1.2.3"])
|
||||
|
||||
assert calls[0][0] == [
|
||||
"systemd-run",
|
||||
"--unit=importarr-update",
|
||||
"--collect",
|
||||
"--no-block",
|
||||
"--on-active=2s",
|
||||
"--",
|
||||
"/bin/sh",
|
||||
"/opt/importarr/repo-upgrade.sh",
|
||||
"v1.2.3",
|
||||
]
|
||||
|
||||
|
||||
def test_update_endpoint_requires_expected_tag(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("IMPORTARR_STATE_PATH", str(tmp_path / "state.db"))
|
||||
import importarr.main as main
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
monkeypatch.setattr(main.settings, "auth_token", "test-token")
|
||||
monkeypatch.setattr(main, "check_update_available", lambda: pytest.fail("release lookup must not run"))
|
||||
|
||||
response = TestClient(main.app).post(
|
||||
"/api/control/update",
|
||||
headers={"Authorization": "Bearer test-token"},
|
||||
)
|
||||
|
||||
assert response.status_code == 422
|
||||
assert response.json()["detail"][0]["loc"] == ["query", "expected_tag"]
|
||||
|
||||
|
||||
def test_update_rejects_unexpected_latest_release(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("IMPORTARR_STATE_PATH", str(tmp_path / "state.db"))
|
||||
import importarr.main as main
|
||||
from fastapi import HTTPException
|
||||
|
||||
monkeypatch.setattr(main, "check_update_available", lambda: {"latest_version": "v1.2.4", "update_available": True})
|
||||
scheduled = []
|
||||
monkeypatch.setattr(main, "_schedule_update", scheduled.append)
|
||||
|
||||
with pytest.raises(HTTPException) as exc_info:
|
||||
main.update_service(expected_tag="v1.2.3")
|
||||
|
||||
assert exc_info.value.status_code == 409
|
||||
assert scheduled == []
|
||||
|
||||
Reference in New Issue
Block a user