Fix doc and changelog API response for orphaned addons (#5082)

* Fix doc and changelog API response for orphaned addons

* Use correct terminology in tests
This commit is contained in:
Mike Degatano 2024-05-21 03:02:01 -04:00 committed by GitHub
parent be6e39fed0
commit c0c0c4b7ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 88 additions and 3 deletions

View File

@ -249,7 +249,12 @@ class APIStore(CoreSysAttributes):
@api_process_raw(CONTENT_TYPE_TEXT) @api_process_raw(CONTENT_TYPE_TEXT)
async def addons_addon_changelog(self, request: web.Request) -> str: async def addons_addon_changelog(self, request: web.Request) -> str:
"""Return changelog from add-on.""" """Return changelog from add-on."""
# Frontend can't handle error response here, need to return 200 and error as text for now
try:
addon = self._extract_addon(request) addon = self._extract_addon(request)
except APIError as err:
return str(err)
if not addon.with_changelog: if not addon.with_changelog:
return f"No changelog found for add-on {addon.slug}!" return f"No changelog found for add-on {addon.slug}!"
@ -259,9 +264,14 @@ class APIStore(CoreSysAttributes):
@api_process_raw(CONTENT_TYPE_TEXT) @api_process_raw(CONTENT_TYPE_TEXT)
async def addons_addon_documentation(self, request: web.Request) -> str: async def addons_addon_documentation(self, request: web.Request) -> str:
"""Return documentation from add-on.""" """Return documentation from add-on."""
# Frontend can't handle error response here, need to return 200 and error as text for now
try:
addon = self._extract_addon(request) addon = self._extract_addon(request)
except APIError as err:
return str(err)
if not addon.with_documentation: if not addon.with_documentation:
raise APIError(f"No documentation found for add-on {addon.slug}!") return f"No documentation found for add-on {addon.slug}!"
with addon.path_documentation.open("r") as documentation: with addon.path_documentation.open("r") as documentation:
return documentation.read() return documentation.read()

View File

@ -1,6 +1,7 @@
"""Test Store API.""" """Test Store API."""
import asyncio import asyncio
from pathlib import Path
from unittest.mock import MagicMock, PropertyMock, patch from unittest.mock import MagicMock, PropertyMock, patch
from aiohttp.test_utils import TestClient from aiohttp.test_utils import TestClient
@ -8,6 +9,7 @@ import pytest
from supervisor.addons.addon import Addon from supervisor.addons.addon import Addon
from supervisor.arch import CpuArch from supervisor.arch import CpuArch
from supervisor.config import CoreConfig
from supervisor.const import AddonState from supervisor.const import AddonState
from supervisor.coresys import CoreSys from supervisor.coresys import CoreSys
from supervisor.docker.addon import DockerAddon from supervisor.docker.addon import DockerAddon
@ -199,7 +201,80 @@ async def test_api_store_addons_no_changelog(
Currently the frontend expects a valid body even in the error case. Make sure that is Currently the frontend expects a valid body even in the error case. Make sure that is
what the API returns. what the API returns.
""" """
assert store_addon.with_changelog is False
resp = await api_client.get(f"/{resource}/{store_addon.slug}/changelog") resp = await api_client.get(f"/{resource}/{store_addon.slug}/changelog")
assert resp.status == 200 assert resp.status == 200
result = await resp.text() result = await resp.text()
assert result == "No changelog found for add-on test_store_addon!" assert result == "No changelog found for add-on test_store_addon!"
@pytest.mark.parametrize("resource", ["store/addons", "addons"])
async def test_api_detached_addon_changelog(
api_client: TestClient,
coresys: CoreSys,
install_addon_ssh: Addon,
tmp_supervisor_data: Path,
resource: str,
):
"""Test /store/addons/{addon}/changelog for an detached addon.
Currently the frontend expects a valid body even in the error case. Make sure that is
what the API returns.
"""
(addons_dir := tmp_supervisor_data / "addons" / "local").mkdir()
with patch.object(
CoreConfig, "path_addons_local", new=PropertyMock(return_value=addons_dir)
):
await coresys.store.load()
assert install_addon_ssh.is_detached is True
assert install_addon_ssh.with_changelog is False
resp = await api_client.get(f"/{resource}/{install_addon_ssh.slug}/changelog")
assert resp.status == 200
result = await resp.text()
assert result == "Addon local_ssh with version latest does not exist in the store"
@pytest.mark.parametrize("resource", ["store/addons", "addons"])
async def test_api_store_addons_no_documentation(
api_client: TestClient, coresys: CoreSys, store_addon: AddonStore, resource: str
):
"""Test /store/addons/{addon}/documentation REST API.
Currently the frontend expects a valid body even in the error case. Make sure that is
what the API returns.
"""
assert store_addon.with_documentation is False
resp = await api_client.get(f"/{resource}/{store_addon.slug}/documentation")
assert resp.status == 200
result = await resp.text()
assert result == "No documentation found for add-on test_store_addon!"
@pytest.mark.parametrize("resource", ["store/addons", "addons"])
async def test_api_detached_addon_documentation(
api_client: TestClient,
coresys: CoreSys,
install_addon_ssh: Addon,
tmp_supervisor_data: Path,
resource: str,
):
"""Test /store/addons/{addon}/changelog for an detached addon.
Currently the frontend expects a valid body even in the error case. Make sure that is
what the API returns.
"""
(addons_dir := tmp_supervisor_data / "addons" / "local").mkdir()
with patch.object(
CoreConfig, "path_addons_local", new=PropertyMock(return_value=addons_dir)
):
await coresys.store.load()
assert install_addon_ssh.is_detached is True
assert install_addon_ssh.with_documentation is False
resp = await api_client.get(f"/{resource}/{install_addon_ssh.slug}/documentation")
assert resp.status == 200
result = await resp.text()
assert result == "Addon local_ssh with version latest does not exist in the store"