diff --git a/.gitignore b/.gitignore index 42dff4fd..94f2e3b2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ result* /pkgs/clan-cli/clan_cli/nixpkgs /pkgs/clan-cli/clan_cli/webui/assets /machines +nixos.qcow2 # python __pycache__ diff --git a/pkgs/clan-cli/clan_cli/webui/routers/vms.py b/pkgs/clan-cli/clan_cli/webui/routers/vms.py index 4f785be8..394eb8a6 100644 --- a/pkgs/clan-cli/clan_cli/webui/routers/vms.py +++ b/pkgs/clan-cli/clan_cli/webui/routers/vms.py @@ -115,13 +115,15 @@ command output: @router.get("/api/vms/{uuid}/status") -async def get_status(uuid: UUID) -> VmStatusResponse: +async def vm_status(uuid: UUID) -> VmStatusResponse: task = get_task(uuid) - return VmStatusResponse(running=not task.finished, status=0) + status: list[int | None] = list(map(lambda x: x.returncode, task.procs)) + log.debug(msg=f"returncodes: {status}. task.finished: {task.finished}") + return VmStatusResponse(running=not task.finished, returncode=status) @router.get("/api/vms/{uuid}/logs") -async def get_logs(uuid: UUID) -> StreamingResponse: +async def get_vm_logs(uuid: UUID) -> StreamingResponse: # Generator function that yields log lines as they are available def stream_logs() -> Iterator[str]: task = get_task(uuid) diff --git a/pkgs/clan-cli/clan_cli/webui/schemas.py b/pkgs/clan-cli/clan_cli/webui/schemas.py index 874e18ab..5cb7c9d4 100644 --- a/pkgs/clan-cli/clan_cli/webui/schemas.py +++ b/pkgs/clan-cli/clan_cli/webui/schemas.py @@ -45,7 +45,7 @@ class VmConfig(BaseModel): class VmStatusResponse(BaseModel): - status: int + returncode: list[int | None] running: bool diff --git a/pkgs/clan-cli/tests/test_vms_api.py b/pkgs/clan-cli/tests/test_vms_api.py index 2939bc59..5bbc3c6d 100644 --- a/pkgs/clan-cli/tests/test_vms_api.py +++ b/pkgs/clan-cli/tests/test_vms_api.py @@ -1,25 +1,58 @@ +import os from pathlib import Path import pytest from api import TestClient from httpx import SyncByteStream -# @pytest.mark.impure -# def test_inspect(api: TestClient, test_flake_with_core: Path) -> None: -# response = api.post( -# "/api/vms/inspect", -# json=dict(flake_url=str(test_flake_with_core), flake_attr="vm1"), -# ) -# assert response.status_code == 200, "Failed to inspect vm" -# config = response.json()["config"] -# assert config.get("flake_attr") == "vm1" -# assert config.get("cores") == 1 -# assert config.get("memory_size") == 1024 -# assert config.get("graphics") is True + +def is_running_in_ci() -> bool: + # Check if pytest is running in GitHub Actions + if os.getenv("GITHUB_ACTIONS") == "true": + print("Running on GitHub Actions") + return True + + # Check if pytest is running in Travis CI + if os.getenv("TRAVIS") == "true": + print("Running on Travis CI") + return True + + # Check if pytest is running in Circle CI + if os.getenv("CIRCLECI") == "true": + print("Running on Circle CI") + return True + return False + + +@pytest.mark.impure +def test_inspect(api: TestClient, test_flake_with_core: Path) -> None: + response = api.post( + "/api/vms/inspect", + json=dict(flake_url=str(test_flake_with_core), flake_attr="vm1"), + ) + assert response.status_code == 200, "Failed to inspect vm" + config = response.json()["config"] + assert config.get("flake_attr") == "vm1" + assert config.get("cores") == 1 + assert config.get("memory_size") == 1024 + assert config.get("graphics") is True + + +def test_incorrect_uuid(api: TestClient) -> None: + uuid_endpoints = [ + "/api/vms/{}/status", + "/api/vms/{}/logs", + ] + + for endpoint in uuid_endpoints: + response = api.get(endpoint.format("1234")) + assert response.status_code == 422, "Failed to get vm status" @pytest.mark.impure def test_create(api: TestClient, test_flake_with_core: Path) -> None: + if is_running_in_ci(): + pytest.skip("Skipping test in CI. As it requires KVM") print(f"flake_url: {test_flake_with_core} ") response = api.post( "/api/vms/create", @@ -57,3 +90,10 @@ def test_create(api: TestClient, test_flake_with_core: Path) -> None: print(line.decode("utf-8"), end="") print("=========END LOGS==========") assert response.status_code == 200, "Failed to get vm logs" + + response = api.get(f"/api/vms/{uuid}/status") + assert response.status_code == 200, "Failed to get vm status" + returncodes = response.json()["returncode"] + assert response.json()["running"] is False, "VM is still running. Should be stopped" + for exit_code in returncodes: + assert exit_code == 0, "One VM failed with exit code != 0"