Use a mocked API client in Traccar Server tests (#109358)

This commit is contained in:
Joakim Sørensen 2024-02-02 09:36:26 +01:00 committed by GitHub
parent 1f466e737e
commit 025fe51322
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 210 additions and 75 deletions

View File

@ -3,12 +3,79 @@ from collections.abc import Generator
from unittest.mock import AsyncMock, patch
import pytest
from pytraccar import ApiClient
from homeassistant.components.traccar_server.const import (
CONF_CUSTOM_ATTRIBUTES,
CONF_EVENTS,
CONF_MAX_ACCURACY,
CONF_SKIP_ACCURACY_FILTER_FOR,
DOMAIN,
)
from homeassistant.const import (
CONF_HOST,
CONF_PASSWORD,
CONF_PORT,
CONF_SSL,
CONF_USERNAME,
CONF_VERIFY_SSL,
)
from tests.common import (
MockConfigEntry,
load_json_array_fixture,
load_json_object_fixture,
)
@pytest.fixture
def mock_setup_entry() -> Generator[AsyncMock, None, None]:
"""Override async_setup_entry."""
def mock_traccar_api_client() -> Generator[AsyncMock, None, None]:
"""Mock a Traccar ApiClient client."""
with patch(
"homeassistant.components.traccar_server.async_setup_entry", return_value=True
) as mock_setup_entry:
yield mock_setup_entry
"homeassistant.components.traccar_server.ApiClient",
autospec=True,
) as mock_client, patch(
"homeassistant.components.traccar_server.config_flow.ApiClient",
new=mock_client,
):
client: ApiClient = mock_client.return_value
client.get_devices.return_value = load_json_array_fixture(
"traccar_server/devices.json"
)
client.get_geofences.return_value = load_json_array_fixture(
"traccar_server/geofences.json"
)
client.get_positions.return_value = load_json_array_fixture(
"traccar_server/positions.json"
)
client.get_server.return_value = load_json_object_fixture(
"traccar_server/server.json"
)
client.get_reports_events.return_value = load_json_array_fixture(
"traccar_server/reports_events.json"
)
yield client
@pytest.fixture
def mock_config_entry() -> MockConfigEntry:
"""Mock a Traccar Server config entry."""
return MockConfigEntry(
domain=DOMAIN,
title="1.1.1.1:8082",
data={
CONF_HOST: "1.1.1.1",
CONF_PORT: "8082",
CONF_USERNAME: "test@example.org",
CONF_PASSWORD: "ThisIsNotThePasswordYouAreL00kingFor",
CONF_SSL: False,
CONF_VERIFY_SSL: True,
},
options={
CONF_CUSTOM_ATTRIBUTES: ["custom_attr_1"],
CONF_EVENTS: ["device_moving"],
CONF_MAX_ACCURACY: 5.0,
CONF_SKIP_ACCURACY_FILTER_FOR: [],
},
)

View File

@ -0,0 +1,17 @@
[
{
"id": 0,
"name": "X-Wing",
"uniqueId": "abc123",
"status": "unknown",
"disabled": false,
"lastUpdate": "1970-01-01T00:00:00Z",
"positionId": 0,
"groupId": 0,
"phone": null,
"model": "1337",
"contact": null,
"category": "starfighter",
"attributes": {}
}
]

View File

@ -0,0 +1,10 @@
[
{
"id": 0,
"name": "Tatooine",
"description": "A harsh desert world orbiting twin suns in the galaxy's Outer Rim",
"area": "string",
"calendarId": 0,
"attributes": {}
}
]

View File

@ -0,0 +1,24 @@
[
{
"id": 0,
"deviceId": 0,
"protocol": "C-3PO",
"deviceTime": "1970-01-01T00:00:00Z",
"fixTime": "1970-01-01T00:00:00Z",
"serverTime": "1970-01-01T00:00:00Z",
"outdated": true,
"valid": true,
"latitude": 52.0,
"longitude": 25.0,
"altitude": 546841384638,
"speed": 4568795,
"course": 360,
"address": "Mos Espa",
"accuracy": 3.5,
"network": {},
"geofenceIds": [0],
"attributes": {
"custom_attr_1": "custom_attr_1_value"
}
}
]

View File

@ -0,0 +1,12 @@
[
{
"id": 0,
"type": "deviceMoving",
"eventTime": "2019-08-24T14:15:22Z",
"deviceId": 0,
"positionId": 0,
"geofenceId": 0,
"maintenanceId": 0,
"attributes": {}
}
]

View File

@ -0,0 +1,21 @@
{
"id": 0,
"registration": true,
"readonly": true,
"deviceReadonly": true,
"limitCommands": true,
"map": null,
"bingKey": null,
"mapUrl": null,
"poiLayer": null,
"latitude": 0,
"longitude": 0,
"zoom": 0,
"twelveHourFormat": true,
"version": "99.99",
"forceSettings": true,
"coordinateFormat": null,
"openIdEnabled": true,
"openIdForce": true,
"attributes": {}
}

View File

@ -1,6 +1,7 @@
"""Test the Traccar Server config flow."""
from collections.abc import Generator
from typing import Any
from unittest.mock import AsyncMock, patch
from unittest.mock import AsyncMock
import pytest
from pytraccar import TraccarException
@ -29,7 +30,10 @@ from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
async def test_form(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> None:
async def test_form(
hass: HomeAssistant,
mock_traccar_api_client: Generator[AsyncMock, None, None],
) -> None:
"""Test we get the form."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
@ -37,19 +41,15 @@ async def test_form(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> None:
assert result["type"] == FlowResultType.FORM
assert result["errors"] == {}
with patch(
"homeassistant.components.traccar_server.config_flow.ApiClient.get_server",
return_value={"id": "1234"},
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_HOST: "1.1.1.1",
CONF_USERNAME: "test-username",
CONF_PASSWORD: "test-password",
},
)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_HOST: "1.1.1.1",
CONF_USERNAME: "test-username",
CONF_PASSWORD: "test-password",
},
)
await hass.async_block_till_done()
assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["title"] == "1.1.1.1:8082"
@ -61,7 +61,7 @@ async def test_form(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> None:
CONF_SSL: False,
CONF_VERIFY_SSL: True,
}
assert len(mock_setup_entry.mock_calls) == 1
assert result["result"].state == config_entries.ConfigEntryState.LOADED
@pytest.mark.parametrize(
@ -73,44 +73,40 @@ async def test_form(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> None:
)
async def test_form_cannot_connect(
hass: HomeAssistant,
mock_setup_entry: AsyncMock,
side_effect: Exception,
error: str,
mock_traccar_api_client: Generator[AsyncMock, None, None],
) -> None:
"""Test we handle cannot connect error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.traccar_server.config_flow.ApiClient.get_server",
side_effect=side_effect,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_HOST: "1.1.1.1",
CONF_USERNAME: "test-username",
CONF_PASSWORD: "test-password",
},
)
mock_traccar_api_client.get_server.side_effect = side_effect
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_HOST: "1.1.1.1",
CONF_USERNAME: "test-username",
CONF_PASSWORD: "test-password",
},
)
assert result["type"] == FlowResultType.FORM
assert result["errors"] == {"base": error}
with patch(
"homeassistant.components.traccar_server.config_flow.ApiClient.get_server",
return_value={"id": "1234"},
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_HOST: "1.1.1.1",
CONF_USERNAME: "test-username",
CONF_PASSWORD: "test-password",
},
)
await hass.async_block_till_done()
mock_traccar_api_client.get_server.side_effect = None
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_HOST: "1.1.1.1",
CONF_USERNAME: "test-username",
CONF_PASSWORD: "test-password",
},
)
await hass.async_block_till_done()
assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["title"] == "1.1.1.1:8082"
@ -122,27 +118,23 @@ async def test_form_cannot_connect(
CONF_SSL: False,
CONF_VERIFY_SSL: True,
}
assert len(mock_setup_entry.mock_calls) == 1
assert result["result"].state == config_entries.ConfigEntryState.LOADED
async def test_options(
hass: HomeAssistant,
mock_setup_entry: AsyncMock,
mock_config_entry: MockConfigEntry,
mock_traccar_api_client: Generator[AsyncMock, None, None],
) -> None:
"""Test options flow."""
mock_config_entry.add_to_hass(hass)
config_entry = MockConfigEntry(
domain=DOMAIN,
data={},
)
assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
config_entry.add_to_hass(hass)
assert mock_config_entry.options.get(CONF_MAX_ACCURACY) == 5.0
assert await hass.config_entries.async_setup(config_entry.entry_id)
assert CONF_MAX_ACCURACY not in config_entry.options
result = await hass.config_entries.options.async_init(config_entry.entry_id)
result = await hass.config_entries.options.async_init(mock_config_entry.entry_id)
result = await hass.config_entries.options.async_configure(
result["flow_id"],
@ -151,7 +143,7 @@ async def test_options(
await hass.async_block_till_done()
assert result["type"] == FlowResultType.CREATE_ENTRY
assert config_entry.options == {
assert mock_config_entry.options == {
CONF_MAX_ACCURACY: 2.0,
CONF_EVENTS: [],
CONF_CUSTOM_ATTRIBUTES: [],
@ -234,10 +226,10 @@ async def test_options(
)
async def test_import_from_yaml(
hass: HomeAssistant,
mock_setup_entry: AsyncMock,
imported: dict[str, Any],
data: dict[str, Any],
options: dict[str, Any],
mock_traccar_api_client: Generator[AsyncMock, None, None],
) -> None:
"""Test importing configuration from YAML."""
result = await hass.config_entries.flow.async_init(
@ -249,12 +241,10 @@ async def test_import_from_yaml(
assert result["title"] == f"{data[CONF_HOST]}:{data[CONF_PORT]}"
assert result["data"] == data
assert result["options"] == options
assert result["result"].state == config_entries.ConfigEntryState.LOADED
async def test_abort_import_already_configured(
hass: HomeAssistant,
mock_setup_entry: AsyncMock,
) -> None:
async def test_abort_import_already_configured(hass: HomeAssistant) -> None:
"""Test abort for existing server while importing."""
config_entry = MockConfigEntry(
@ -284,18 +274,12 @@ async def test_abort_import_already_configured(
async def test_abort_already_configured(
hass: HomeAssistant,
mock_setup_entry: AsyncMock,
mock_config_entry: MockConfigEntry,
mock_traccar_api_client: Generator[AsyncMock, None, None],
) -> None:
"""Test abort for existing server."""
config_entry = MockConfigEntry(
domain=DOMAIN,
data={CONF_HOST: "1.1.1.1", CONF_PORT: "8082"},
)
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
mock_config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}