mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-12-25 04:46:25 +00:00
Use status 404 in more places when appropriate (#5480)
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import asyncio
|
||||
from unittest.mock import MagicMock, PropertyMock, patch
|
||||
|
||||
from aiohttp import ClientResponse
|
||||
from aiohttp.test_utils import TestClient
|
||||
import pytest
|
||||
|
||||
@@ -82,7 +83,7 @@ async def test_api_addon_logs_not_installed(api_client: TestClient):
|
||||
"""Test error is returned for non-existing add-on."""
|
||||
resp = await api_client.get("/addons/hic_sunt_leones/logs")
|
||||
|
||||
assert resp.status == 400
|
||||
assert resp.status == 404
|
||||
assert resp.content_type == "text/plain"
|
||||
content = await resp.text()
|
||||
assert content == "Addon hic_sunt_leones does not exist"
|
||||
@@ -366,3 +367,71 @@ async def test_addon_options_boot_mode_manual_only_invalid(
|
||||
body["message"]
|
||||
== "Addon local_example boot option is set to manual_only so it cannot be changed"
|
||||
)
|
||||
|
||||
|
||||
async def get_message(resp: ClientResponse, json_expected: bool) -> str:
|
||||
"""Get message from response based on response type."""
|
||||
if json_expected:
|
||||
body = await resp.json()
|
||||
return body["message"]
|
||||
return await resp.text()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("method", "url", "json_expected"),
|
||||
[
|
||||
("get", "/addons/bad/info", True),
|
||||
("post", "/addons/bad/uninstall", True),
|
||||
("post", "/addons/bad/start", True),
|
||||
("post", "/addons/bad/stop", True),
|
||||
("post", "/addons/bad/restart", True),
|
||||
("post", "/addons/bad/options", True),
|
||||
("post", "/addons/bad/sys_options", True),
|
||||
("post", "/addons/bad/options/validate", True),
|
||||
("post", "/addons/bad/rebuild", True),
|
||||
("post", "/addons/bad/stdin", True),
|
||||
("post", "/addons/bad/security", True),
|
||||
("get", "/addons/bad/stats", True),
|
||||
("get", "/addons/bad/logs", False),
|
||||
("get", "/addons/bad/logs/follow", False),
|
||||
("get", "/addons/bad/logs/boots/1", False),
|
||||
("get", "/addons/bad/logs/boots/1/follow", False),
|
||||
],
|
||||
)
|
||||
async def test_addon_not_found(
|
||||
api_client: TestClient, method: str, url: str, json_expected: bool
|
||||
):
|
||||
"""Test addon not found error."""
|
||||
resp = await api_client.request(method, url)
|
||||
assert resp.status == 404
|
||||
assert await get_message(resp, json_expected) == "Addon bad does not exist"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("method", "url", "json_expected"),
|
||||
[
|
||||
("post", "/addons/local_ssh/uninstall", True),
|
||||
("post", "/addons/local_ssh/start", True),
|
||||
("post", "/addons/local_ssh/stop", True),
|
||||
("post", "/addons/local_ssh/restart", True),
|
||||
("post", "/addons/local_ssh/options", True),
|
||||
("post", "/addons/local_ssh/sys_options", True),
|
||||
("post", "/addons/local_ssh/options/validate", True),
|
||||
("post", "/addons/local_ssh/rebuild", True),
|
||||
("post", "/addons/local_ssh/stdin", True),
|
||||
("post", "/addons/local_ssh/security", True),
|
||||
("get", "/addons/local_ssh/stats", True),
|
||||
("get", "/addons/local_ssh/logs", False),
|
||||
("get", "/addons/local_ssh/logs/follow", False),
|
||||
("get", "/addons/local_ssh/logs/boots/1", False),
|
||||
("get", "/addons/local_ssh/logs/boots/1/follow", False),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("repository")
|
||||
async def test_addon_not_installed(
|
||||
api_client: TestClient, method: str, url: str, json_expected: bool
|
||||
):
|
||||
"""Test addon not installed error."""
|
||||
resp = await api_client.request(method, url)
|
||||
assert resp.status == 400
|
||||
assert await get_message(resp, json_expected) == "Addon is not installed"
|
||||
|
||||
@@ -138,3 +138,15 @@ async def test_api_invalid_discovery(api_client: TestClient, install_addon_ssh:
|
||||
|
||||
resp = await api_client.post("/discovery", json={"service": "test", "config": None})
|
||||
assert resp.status == 400
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("method", "url"),
|
||||
[("get", "/discovery/bad"), ("delete", "/discovery/bad")],
|
||||
)
|
||||
async def test_discovery_not_found(api_client: TestClient, method: str, url: str):
|
||||
"""Test discovery not found error."""
|
||||
resp = await api_client.request(method, url)
|
||||
assert resp.status == 404
|
||||
resp = await resp.json()
|
||||
assert resp["message"] == "Discovery message not found"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
"""Test Docker API."""
|
||||
|
||||
from aiohttp.test_utils import TestClient
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_api_docker_info(api_client):
|
||||
async def test_api_docker_info(api_client: TestClient):
|
||||
"""Test docker info api."""
|
||||
resp = await api_client.get("/docker/info")
|
||||
result = await resp.json()
|
||||
@@ -12,3 +13,11 @@ async def test_api_docker_info(api_client):
|
||||
assert result["data"]["logging"] == "journald"
|
||||
assert result["data"]["storage"] == "overlay2"
|
||||
assert result["data"]["version"] == "1.0.0"
|
||||
|
||||
|
||||
async def test_registry_not_found(api_client: TestClient):
|
||||
"""Test registry not found error."""
|
||||
resp = await api_client.delete("/docker/registries/bad")
|
||||
assert resp.status == 404
|
||||
body = await resp.json()
|
||||
assert body["message"] == "Hostname bad does not exist in registries"
|
||||
|
||||
@@ -4,6 +4,7 @@ import asyncio
|
||||
from unittest.mock import ANY
|
||||
|
||||
from aiohttp.test_utils import TestClient
|
||||
import pytest
|
||||
|
||||
from supervisor.coresys import CoreSys
|
||||
from supervisor.jobs.const import ATTR_IGNORE_CONDITIONS, JobCondition
|
||||
@@ -213,6 +214,18 @@ async def test_job_manual_cleanup(api_client: TestClient, coresys: CoreSys):
|
||||
|
||||
# Confirm it no longer exists
|
||||
resp = await api_client.get(f"/jobs/{test.job_id}")
|
||||
assert resp.status == 400
|
||||
assert resp.status == 404
|
||||
result = await resp.json()
|
||||
assert result["message"] == f"No job found with id {test.job_id}"
|
||||
assert result["message"] == "Job does not exist"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("method", "url"),
|
||||
[("get", "/jobs/bad"), ("delete", "/jobs/bad")],
|
||||
)
|
||||
async def test_job_not_found(api_client: TestClient, method: str, url: str):
|
||||
"""Test job not found error."""
|
||||
resp = await api_client.request(method, url)
|
||||
assert resp.status == 404
|
||||
body = await resp.json()
|
||||
assert body["message"] == "Job does not exist"
|
||||
|
||||
@@ -264,25 +264,6 @@ async def test_api_update_mount(
|
||||
coresys.mounts.save_data.assert_called_once()
|
||||
|
||||
|
||||
async def test_api_update_error_mount_missing(
|
||||
api_client: TestClient, mount_propagation
|
||||
):
|
||||
"""Test update mount API errors when mount does not exist."""
|
||||
resp = await api_client.put(
|
||||
"/mounts/backup_test",
|
||||
json={
|
||||
"type": "cifs",
|
||||
"usage": "backup",
|
||||
"server": "backup.local",
|
||||
"share": "new_backups",
|
||||
},
|
||||
)
|
||||
assert resp.status == 400
|
||||
result = await resp.json()
|
||||
assert result["result"] == "error"
|
||||
assert result["message"] == "No mount exists with name backup_test"
|
||||
|
||||
|
||||
async def test_api_update_dbus_error_mount_remains(
|
||||
api_client: TestClient,
|
||||
all_dbus_services: dict[str, DBusServiceMock],
|
||||
@@ -399,20 +380,6 @@ async def test_api_reload_mount(
|
||||
]
|
||||
|
||||
|
||||
async def test_api_reload_error_mount_missing(
|
||||
api_client: TestClient, mount_propagation
|
||||
):
|
||||
"""Test reload mount API errors when mount does not exist."""
|
||||
resp = await api_client.post("/mounts/backup_test/reload")
|
||||
assert resp.status == 400
|
||||
result = await resp.json()
|
||||
assert result["result"] == "error"
|
||||
assert (
|
||||
result["message"]
|
||||
== "Cannot reload 'backup_test', no mount exists with that name"
|
||||
)
|
||||
|
||||
|
||||
async def test_api_delete_mount(
|
||||
api_client: TestClient,
|
||||
coresys: CoreSys,
|
||||
@@ -435,20 +402,6 @@ async def test_api_delete_mount(
|
||||
coresys.mounts.save_data.assert_called_once()
|
||||
|
||||
|
||||
async def test_api_delete_error_mount_missing(
|
||||
api_client: TestClient, mount_propagation
|
||||
):
|
||||
"""Test delete mount API errors when mount does not exist."""
|
||||
resp = await api_client.delete("/mounts/backup_test")
|
||||
assert resp.status == 400
|
||||
result = await resp.json()
|
||||
assert result["result"] == "error"
|
||||
assert (
|
||||
result["message"]
|
||||
== "Cannot remove 'backup_test', no mount exists with that name"
|
||||
)
|
||||
|
||||
|
||||
async def test_api_create_backup_mount_sets_default(
|
||||
api_client: TestClient,
|
||||
coresys: CoreSys,
|
||||
@@ -903,3 +856,19 @@ async def test_api_read_only_backup_mount_invalid(
|
||||
result = await resp.json()
|
||||
assert result["result"] == "error"
|
||||
assert "Backup mounts cannot be read only" in result["message"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("method", "url"),
|
||||
[
|
||||
("put", "/mounts/bad"),
|
||||
("delete", "/mounts/bad"),
|
||||
("post", "/mounts/bad/reload"),
|
||||
],
|
||||
)
|
||||
async def test_mount_not_found(api_client: TestClient, method: str, url: str):
|
||||
"""Test mount not found error."""
|
||||
resp = await api_client.request(method, url)
|
||||
assert resp.status == 404
|
||||
resp = await resp.json()
|
||||
assert resp["message"] == "No mount exists with name bad"
|
||||
|
||||
@@ -400,3 +400,22 @@ async def test_api_network_vlan(
|
||||
"id": Variant("u", 1),
|
||||
"parent": Variant("s", "0c23631e-2118-355c-bbb0-8943229cb0d6"),
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("method", "url"),
|
||||
[
|
||||
("get", "/network/interface/bad/info"),
|
||||
("post", "/network/interface/bad/update"),
|
||||
("get", "/network/interface/bad/accesspoints"),
|
||||
("post", "/network/interface/bad/vlan/1"),
|
||||
],
|
||||
)
|
||||
async def test_network_interface_not_found(
|
||||
api_client: TestClient, method: str, url: str
|
||||
):
|
||||
"""Test network interface not found error."""
|
||||
resp = await api_client.request(method, url)
|
||||
assert resp.status == 404
|
||||
body = await resp.json()
|
||||
assert body["message"] == "Interface bad does not exist"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from aiohttp.test_utils import TestClient
|
||||
import pytest
|
||||
|
||||
from supervisor.const import (
|
||||
@@ -24,7 +25,7 @@ from supervisor.resolution.data import Issue, Suggestion
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_api_resolution_base(coresys: CoreSys, api_client):
|
||||
async def test_api_resolution_base(coresys: CoreSys, api_client: TestClient):
|
||||
"""Test resolution manager api."""
|
||||
coresys.resolution.unsupported = UnsupportedReason.OS
|
||||
coresys.resolution.suggestions = Suggestion(
|
||||
@@ -42,7 +43,9 @@ async def test_api_resolution_base(coresys: CoreSys, api_client):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_api_resolution_dismiss_suggestion(coresys: CoreSys, api_client):
|
||||
async def test_api_resolution_dismiss_suggestion(
|
||||
coresys: CoreSys, api_client: TestClient
|
||||
):
|
||||
"""Test resolution manager suggestion apply api."""
|
||||
coresys.resolution.suggestions = clear_backup = Suggestion(
|
||||
SuggestionType.CLEAR_FULL_BACKUP, ContextType.SYSTEM
|
||||
@@ -54,7 +57,9 @@ async def test_api_resolution_dismiss_suggestion(coresys: CoreSys, api_client):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_api_resolution_apply_suggestion(coresys: CoreSys, api_client):
|
||||
async def test_api_resolution_apply_suggestion(
|
||||
coresys: CoreSys, api_client: TestClient
|
||||
):
|
||||
"""Test resolution manager suggestion apply api."""
|
||||
coresys.resolution.suggestions = clear_backup = Suggestion(
|
||||
SuggestionType.CLEAR_FULL_BACKUP, ContextType.SYSTEM
|
||||
@@ -82,7 +87,7 @@ async def test_api_resolution_apply_suggestion(coresys: CoreSys, api_client):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_api_resolution_dismiss_issue(coresys: CoreSys, api_client):
|
||||
async def test_api_resolution_dismiss_issue(coresys: CoreSys, api_client: TestClient):
|
||||
"""Test resolution manager issue apply api."""
|
||||
coresys.resolution.issues = updated_failed = Issue(
|
||||
IssueType.UPDATE_FAILED, ContextType.SYSTEM
|
||||
@@ -94,7 +99,7 @@ async def test_api_resolution_dismiss_issue(coresys: CoreSys, api_client):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_api_resolution_unhealthy(coresys: CoreSys, api_client):
|
||||
async def test_api_resolution_unhealthy(coresys: CoreSys, api_client: TestClient):
|
||||
"""Test resolution manager api."""
|
||||
coresys.resolution.unhealthy = UnhealthyReason.DOCKER
|
||||
|
||||
@@ -104,7 +109,7 @@ async def test_api_resolution_unhealthy(coresys: CoreSys, api_client):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_api_resolution_check_options(coresys: CoreSys, api_client):
|
||||
async def test_api_resolution_check_options(coresys: CoreSys, api_client: TestClient):
|
||||
"""Test client API with checks options."""
|
||||
free_space = coresys.resolution.check.get("free_space")
|
||||
|
||||
@@ -121,7 +126,7 @@ async def test_api_resolution_check_options(coresys: CoreSys, api_client):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_api_resolution_check_run(coresys: CoreSys, api_client):
|
||||
async def test_api_resolution_check_run(coresys: CoreSys, api_client: TestClient):
|
||||
"""Test client API with run check."""
|
||||
coresys.core.state = CoreState.RUNNING
|
||||
free_space = coresys.resolution.check.get("free_space")
|
||||
@@ -133,7 +138,9 @@ async def test_api_resolution_check_run(coresys: CoreSys, api_client):
|
||||
assert free_space.run_check.called
|
||||
|
||||
|
||||
async def test_api_resolution_suggestions_for_issue(coresys: CoreSys, api_client):
|
||||
async def test_api_resolution_suggestions_for_issue(
|
||||
coresys: CoreSys, api_client: TestClient
|
||||
):
|
||||
"""Test getting suggestions that fix an issue."""
|
||||
coresys.resolution.issues = corrupt_repo = Issue(
|
||||
IssueType.CORRUPT_REPOSITORY, ContextType.STORE, "repo_1"
|
||||
@@ -165,3 +172,39 @@ async def test_api_resolution_suggestions_for_issue(coresys: CoreSys, api_client
|
||||
]
|
||||
assert len(suggestion) == 1
|
||||
assert suggestion[0]["auto"] is False
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("method", "url"),
|
||||
[("delete", "/resolution/issue/bad"), ("get", "/resolution/issue/bad/suggestions")],
|
||||
)
|
||||
async def test_issue_not_found(api_client: TestClient, method: str, url: str):
|
||||
"""Test issue not found error."""
|
||||
resp = await api_client.request(method, url)
|
||||
assert resp.status == 404
|
||||
body = await resp.json()
|
||||
assert body["message"] == "The supplied UUID is not a valid issue"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("method", "url"),
|
||||
[("delete", "/resolution/suggestion/bad"), ("post", "/resolution/suggestion/bad")],
|
||||
)
|
||||
async def test_suggestion_not_found(api_client: TestClient, method: str, url: str):
|
||||
"""Test suggestion not found error."""
|
||||
resp = await api_client.request(method, url)
|
||||
assert resp.status == 404
|
||||
body = await resp.json()
|
||||
assert body["message"] == "The supplied UUID is not a valid suggestion"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("method", "url"),
|
||||
[("post", "/resolution/check/bad/options"), ("post", "/resolution/check/bad/run")],
|
||||
)
|
||||
async def test_check_not_found(api_client: TestClient, method: str, url: str):
|
||||
"""Test check not found error."""
|
||||
resp = await api_client.request(method, url)
|
||||
assert resp.status == 404
|
||||
body = await resp.json()
|
||||
assert body["message"] == "The supplied check slug is not available"
|
||||
|
||||
16
tests/api/test_services.py
Normal file
16
tests/api/test_services.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""Test services API."""
|
||||
|
||||
from aiohttp.test_utils import TestClient
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("method", "url"),
|
||||
[("get", "/services/bad"), ("post", "/services/bad"), ("delete", "/services/bad")],
|
||||
)
|
||||
async def test_service_not_found(api_client: TestClient, method: str, url: str):
|
||||
"""Test service not found error."""
|
||||
resp = await api_client.request(method, url)
|
||||
assert resp.status == 404
|
||||
body = await resp.json()
|
||||
assert body["message"] == "Service does not exist"
|
||||
@@ -4,6 +4,7 @@ import asyncio
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, PropertyMock, patch
|
||||
|
||||
from aiohttp import ClientResponse
|
||||
from aiohttp.test_utils import TestClient
|
||||
import pytest
|
||||
|
||||
@@ -235,7 +236,7 @@ async def test_api_detached_addon_changelog(
|
||||
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"
|
||||
assert result == "Addon local_ssh does not exist in the store"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("resource", ["store/addons", "addons"])
|
||||
@@ -279,4 +280,72 @@ async def test_api_detached_addon_documentation(
|
||||
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"
|
||||
assert result == "Addon local_ssh does not exist in the store"
|
||||
|
||||
|
||||
async def get_message(resp: ClientResponse, json_expected: bool) -> str:
|
||||
"""Get message from response based on response type."""
|
||||
if json_expected:
|
||||
body = await resp.json()
|
||||
return body["message"]
|
||||
return await resp.text()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("method", "url", "json_expected"),
|
||||
[
|
||||
("get", "/store/addons/bad", True),
|
||||
("get", "/store/addons/bad/1", True),
|
||||
("get", "/store/addons/bad/icon", False),
|
||||
("get", "/store/addons/bad/logo", False),
|
||||
("post", "/store/addons/bad/install", True),
|
||||
("post", "/store/addons/bad/install/1", True),
|
||||
("post", "/store/addons/bad/update", True),
|
||||
("post", "/store/addons/bad/update/1", True),
|
||||
# Legacy paths
|
||||
("get", "/addons/bad/icon", False),
|
||||
("get", "/addons/bad/logo", False),
|
||||
("post", "/addons/bad/install", True),
|
||||
("post", "/addons/bad/update", True),
|
||||
],
|
||||
)
|
||||
async def test_store_addon_not_found(
|
||||
api_client: TestClient, method: str, url: str, json_expected: bool
|
||||
):
|
||||
"""Test store addon not found error."""
|
||||
resp = await api_client.request(method, url)
|
||||
assert resp.status == 404
|
||||
assert await get_message(resp, json_expected) == "Addon bad does not exist"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("method", "url"),
|
||||
[
|
||||
("post", "/store/addons/local_ssh/update"),
|
||||
("post", "/store/addons/local_ssh/update/1"),
|
||||
# Legacy paths
|
||||
("post", "/addons/local_ssh/update"),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("repository")
|
||||
async def test_store_addon_not_installed(api_client: TestClient, method: str, url: str):
|
||||
"""Test store addon not installed error."""
|
||||
resp = await api_client.request(method, url)
|
||||
assert resp.status == 400
|
||||
body = await resp.json()
|
||||
assert body["message"] == "Addon local_ssh is not installed"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("method", "url"),
|
||||
[
|
||||
("get", "/store/repositories/bad"),
|
||||
("delete", "/store/repositories/bad"),
|
||||
],
|
||||
)
|
||||
async def test_repository_not_found(api_client: TestClient, method: str, url: str):
|
||||
"""Test repository not found error."""
|
||||
resp = await api_client.request(method, url)
|
||||
assert resp.status == 404
|
||||
body = await resp.json()
|
||||
assert body["message"] == "Repository bad does not exist in the store"
|
||||
|
||||
Reference in New Issue
Block a user