Skip to content

Commit

Permalink
Move local calendar text fixtures to conftest.py (home-assistant#89674)
Browse files Browse the repository at this point in the history
* Move local calendar text fixtures to conftest.py

* Apply suggestions from code review

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Add imports for suggested typing fixes

* Apply suggestions from code review

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

---------

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
  • Loading branch information
allenporter and epenet authored Mar 14, 2023
1 parent 85e0177 commit 1bc4802
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 153 deletions.
161 changes: 161 additions & 0 deletions tests/components/local_calendar/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
"""Fixtures for local calendar."""

from collections.abc import Awaitable, Callable, Generator
from http import HTTPStatus
from pathlib import Path
from typing import Any
from unittest.mock import patch
import urllib

from aiohttp import ClientWebSocketResponse
import pytest

from homeassistant.components.local_calendar import LocalCalendarStore
from homeassistant.components.local_calendar.const import CONF_CALENDAR_NAME, DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component

from tests.common import MockConfigEntry
from tests.typing import ClientSessionGenerator, WebSocketGenerator

CALENDAR_NAME = "Light Schedule"
FRIENDLY_NAME = "Light schedule"
TEST_ENTITY = "calendar.light_schedule"


class FakeStore(LocalCalendarStore):
"""Mock storage implementation."""

def __init__(self, hass: HomeAssistant, path: Path) -> None:
"""Initialize FakeStore."""
super().__init__(hass, path)
self._content = ""

def _load(self) -> str:
"""Read from calendar storage."""
return self._content

def _store(self, ics_content: str) -> None:
"""Persist the calendar storage."""
self._content = ics_content


@pytest.fixture(name="store", autouse=True)
def mock_store() -> Generator[None, None, None]:
"""Test cleanup, remove any media storage persisted during the test."""

stores: dict[Path, FakeStore] = {}

def new_store(hass: HomeAssistant, path: Path) -> FakeStore:
if path not in stores:
stores[path] = FakeStore(hass, path)
return stores[path]

with patch(
"homeassistant.components.local_calendar.LocalCalendarStore", new=new_store
):
yield


@pytest.fixture(name="time_zone")
def mock_time_zone() -> str:
"""Fixture for time zone to use in tests."""
# Set our timezone to CST/Regina so we can check calculations
# This keeps UTC-6 all year round
return "America/Regina"


@pytest.fixture(autouse=True)
def set_time_zone(hass: HomeAssistant, time_zone: str):
"""Set the time zone for the tests."""
# Set our timezone to CST/Regina so we can check calculations
# This keeps UTC-6 all year round
hass.config.set_time_zone(time_zone)


@pytest.fixture(name="config_entry")
def mock_config_entry() -> MockConfigEntry:
"""Fixture for mock configuration entry."""
return MockConfigEntry(domain=DOMAIN, data={CONF_CALENDAR_NAME: CALENDAR_NAME})


@pytest.fixture(name="setup_integration")
async def setup_integration(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
"""Set up the integration."""
config_entry.add_to_hass(hass)
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()


GetEventsFn = Callable[[str, str], Awaitable[dict[str, Any]]]


@pytest.fixture(name="get_events")
def get_events_fixture(hass_client: ClientSessionGenerator) -> GetEventsFn:
"""Fetch calendar events from the HTTP API."""

async def _fetch(start: str, end: str) -> None:
client = await hass_client()
response = await client.get(
f"/api/calendars/{TEST_ENTITY}?start={urllib.parse.quote(start)}&end={urllib.parse.quote(end)}"
)
assert response.status == HTTPStatus.OK
return await response.json()

return _fetch


def event_fields(data: dict[str, str]) -> dict[str, str]:
"""Filter event API response to minimum fields."""
return {
k: data.get(k)
for k in ["summary", "start", "end", "recurrence_id"]
if data.get(k)
}


class Client:
"""Test client with helper methods for calendar websocket."""

def __init__(self, client: ClientWebSocketResponse) -> None:
"""Initialize Client."""
self.client = client
self.id = 0

async def cmd(self, cmd: str, payload: dict[str, Any] = None) -> dict[str, Any]:
"""Send a command and receive the json result."""
self.id += 1
await self.client.send_json(
{
"id": self.id,
"type": f"calendar/event/{cmd}",
**(payload if payload is not None else {}),
}
)
resp = await self.client.receive_json()
assert resp.get("id") == self.id
return resp

async def cmd_result(self, cmd: str, payload: dict[str, Any] = None) -> Any:
"""Send a command and parse the result."""
resp = await self.cmd(cmd, payload)
assert resp.get("success")
assert resp.get("type") == "result"
return resp.get("result")


ClientFixture = Callable[[], Awaitable[Client]]


@pytest.fixture
async def ws_client(
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
) -> ClientFixture:
"""Fixture for creating the test websocket client."""

async def create_client() -> Client:
ws_client = await hass_ws_client(hass)
return Client(ws_client)

return create_client
161 changes: 8 additions & 153 deletions tests/components/local_calendar/test_calendar.py
Original file line number Diff line number Diff line change
@@ -1,168 +1,23 @@
"""Tests for calendar platform of local calendar."""

from collections.abc import Awaitable, Callable
import datetime
from http import HTTPStatus
from pathlib import Path
from typing import Any
from unittest.mock import patch
import urllib

from aiohttp import ClientWebSocketResponse
import pytest

from homeassistant.components.local_calendar import LocalCalendarStore
from homeassistant.components.local_calendar.const import CONF_CALENDAR_NAME, DOMAIN
from homeassistant.const import STATE_OFF, STATE_ON
from homeassistant.core import HomeAssistant
from homeassistant.helpers.template import DATE_STR_FORMAT
from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util

from tests.common import MockConfigEntry
from tests.typing import ClientSessionGenerator

CALENDAR_NAME = "Light Schedule"
FRIENDLY_NAME = "Light schedule"
TEST_ENTITY = "calendar.light_schedule"


class FakeStore(LocalCalendarStore):
"""Mock storage implementation."""

def __init__(self, hass: HomeAssistant, path: Path) -> None:
"""Initialize FakeStore."""
super().__init__(hass, path)
self._content = ""

def _load(self) -> str:
"""Read from calendar storage."""
return self._content

def _store(self, ics_content: str) -> None:
"""Persist the calendar storage."""
self._content = ics_content


@pytest.fixture(name="store", autouse=True)
def mock_store() -> None:
"""Test cleanup, remove any media storage persisted during the test."""

stores: dict[Path, FakeStore] = {}

def new_store(hass: HomeAssistant, path: Path) -> FakeStore:
if path not in stores:
stores[path] = FakeStore(hass, path)
return stores[path]

with patch(
"homeassistant.components.local_calendar.LocalCalendarStore", new=new_store
):
yield


@pytest.fixture(name="time_zone")
def mock_time_zone() -> str:
"""Fixture for time zone to use in tests."""
# Set our timezone to CST/Regina so we can check calculations
# This keeps UTC-6 all year round
return "America/Regina"


@pytest.fixture(autouse=True)
def set_time_zone(hass: HomeAssistant, time_zone: str):
"""Set the time zone for the tests."""
# Set our timezone to CST/Regina so we can check calculations
# This keeps UTC-6 all year round
hass.config.set_time_zone(time_zone)


@pytest.fixture(name="config_entry")
def mock_config_entry() -> MockConfigEntry:
"""Fixture for mock configuration entry."""
return MockConfigEntry(domain=DOMAIN, data={CONF_CALENDAR_NAME: CALENDAR_NAME})


@pytest.fixture(name="setup_integration")
async def setup_integration(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
"""Set up the integration."""
config_entry.add_to_hass(hass)
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()


GetEventsFn = Callable[[str, str], Awaitable[dict[str, Any]]]


@pytest.fixture(name="get_events")
def get_events_fixture(hass_client: ClientSessionGenerator) -> GetEventsFn:
"""Fetch calendar events from the HTTP API."""

async def _fetch(start: str, end: str) -> None:
client = await hass_client()
response = await client.get(
f"/api/calendars/{TEST_ENTITY}?start={urllib.parse.quote(start)}&end={urllib.parse.quote(end)}"
)
assert response.status == HTTPStatus.OK
return await response.json()

return _fetch


def event_fields(data: dict[str, str]) -> dict[str, str]:
"""Filter event API response to minimum fields."""
return {
k: data.get(k)
for k in ["summary", "start", "end", "recurrence_id"]
if data.get(k)
}


class Client:
"""Test client with helper methods for calendar websocket."""

def __init__(self, client):
"""Initialize Client."""
self.client = client
self.id = 0

async def cmd(self, cmd: str, payload: dict[str, Any] = None) -> dict[str, Any]:
"""Send a command and receive the json result."""
self.id += 1
await self.client.send_json(
{
"id": self.id,
"type": f"calendar/event/{cmd}",
**(payload if payload is not None else {}),
}
)
resp = await self.client.receive_json()
assert resp.get("id") == self.id
return resp

async def cmd_result(self, cmd: str, payload: dict[str, Any] = None) -> Any:
"""Send a command and parse the result."""
resp = await self.cmd(cmd, payload)
assert resp.get("success")
assert resp.get("type") == "result"
return resp.get("result")


ClientFixture = Callable[[], Awaitable[Client]]


@pytest.fixture
async def ws_client(
hass: HomeAssistant,
hass_ws_client: Callable[[HomeAssistant], Awaitable[ClientWebSocketResponse]],
) -> ClientFixture:
"""Fixture for creating the test websocket client."""

async def create_client() -> Client:
ws_client = await hass_ws_client(hass)
return Client(ws_client)
from .conftest import (
FRIENDLY_NAME,
TEST_ENTITY,
ClientFixture,
GetEventsFn,
event_fields,
)

return create_client
from tests.common import MockConfigEntry


async def test_empty_calendar(
Expand Down

0 comments on commit 1bc4802

Please sign in to comment.