diff --git a/nanokvm/client.py b/nanokvm/client.py index af56d3e..e3084c0 100644 --- a/nanokvm/client.py +++ b/nanokvm/client.py @@ -28,6 +28,7 @@ GetHardwareRsp, GetHdmiStateRsp, GetHidModeRsp, + GetImagesRsp, GetInfoRsp, GetMdnsStateRsp, GetMemoryLimitRsp, @@ -194,7 +195,7 @@ async def _api_request_json( raw_response = await response.json(content_type=None) _LOGGER.debug("Raw JSON response data: %s", raw_response) # Parse the outer ApiResponse structure - api_response = ApiResponse[response_model].parse_obj(raw_response) # type: ignore + api_response = ApiResponse[response_model].model_validate(raw_response) # type: ignore except (json.JSONDecodeError, ValidationError) as err: raise NanoKVMInvalidResponseError( f"Invalid JSON response received: {err}" @@ -397,6 +398,14 @@ async def get_tailscale_status(self) -> GetTailscaleStatusRsp: response_model=GetTailscaleStatusRsp, ) + async def get_images(self) -> GetImagesRsp: + """Get the list of available image files.""" + return await self._api_request_json( + hdrs.METH_GET, + "/storage/image", + response_model=GetImagesRsp, + ) + async def get_mounted_image(self) -> GetMountedImageRsp: """Get the currently mounted image file.""" return await self._api_request_json( diff --git a/tests/test_client.py b/tests/test_client.py index 0bf93cb..3fc4ecc 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1,6 +1,8 @@ from aiohttp import ClientSession +from aioresponses import aioresponses -from nanokvm.client import NanoKVMClient +from nanokvm.client import NanoKVMApiError, NanoKVMClient +from nanokvm.models import ApiResponseCode async def test_client() -> None: @@ -8,3 +10,73 @@ async def test_client() -> None: async with ClientSession() as session: client = NanoKVMClient("http://localhost:8888/api/", session) assert client is not None + + +async def test_get_images_success() -> None: + """Test get_images with a successful response.""" + async with ClientSession() as session: + client = NanoKVMClient( + "http://localhost:8888/api/", session, token="test-token" + ) + + with aioresponses() as m: + m.get( + "http://localhost:8888/api/storage/image", + payload={ + "code": 0, + "msg": "success", + "data": { + "files": [ + "/data/alpine-standard-3.23.2-x86_64.iso", + "/data/cs10-js.iso", + ] + }, + }, + ) + + response = await client.get_images() + + assert response is not None + assert len(response.files) == 2 + assert "/data/alpine-standard-3.23.2-x86_64.iso" in response.files + assert "/data/cs10-js.iso" in response.files + + +async def test_get_images_empty() -> None: + """Test get_images with an empty list.""" + async with ClientSession() as session: + client = NanoKVMClient( + "http://localhost:8888/api/", session, token="test-token" + ) + + with aioresponses() as m: + m.get( + "http://localhost:8888/api/storage/image", + payload={"code": 0, "msg": "success", "data": {"files": []}}, + ) + + response = await client.get_images() + + assert response is not None + assert len(response.files) == 0 + + +async def test_get_images_api_error() -> None: + """Test get_images with an API error response.""" + async with ClientSession() as session: + client = NanoKVMClient( + "http://localhost:8888/api/", session, token="test-token" + ) + + with aioresponses() as m: + m.get( + "http://localhost:8888/api/storage/image", + payload={"code": -1, "msg": "failed to list images", "data": None}, + ) + + try: + await client.get_images() + raise AssertionError("Expected NanoKVMApiError to be raised") + except NanoKVMApiError as e: + assert e.code == ApiResponseCode.FAILURE + assert "failed to list images" in e.msg