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