Skip to content

Commit

Permalink
Adjust tests to comply with ruff (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
ludeeus authored Feb 23, 2024
1 parent 29e7c3c commit ea6e513
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 91 deletions.
61 changes: 38 additions & 23 deletions tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,55 @@
from __future__ import annotations

import json
import os
from dataclasses import dataclass
from pathlib import Path
from typing import Any

from aiohttp import WSMsgType


class WSMessage:
def __init__(self, type: WSMsgType, json: dict | None = None) -> None:
self.type = type
"""WSMessage."""

def __init__(self, messagetype: WSMsgType, json: dict | None = None) -> None:
"""Initialize."""
self.type = messagetype
self._json = json

def json(self):
def json(self) -> dict | None:
"""json."""
return self._json


def load_response(filename):
def load_response(filename: str) -> dict[str, Any]:
"""Load a response."""
filename = f"{filename}.json" if "." not in filename else filename
path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
path = Path(
Path.resolve(Path(__file__)).parent,
"responses",
filename.lower().replace("/", "_"),
)
with open(path, encoding="utf-8") as fptr:
with path.open(encoding="utf-8") as fptr:
return json.loads(fptr.read())


class WSMessageHandler:
messages = []
"""WSMessageHandler."""

def __init__(self) -> None:
"""Initialize."""
self.messages = []

def add(self, msg: WSMessage):
def add(self, msg: WSMessage) -> None:
"""Add."""
self.messages.append(msg)

def get(self):
def get(self) -> WSMessage:
"""Get."""
return (
self.messages.pop(0) if self.messages else WSMessage(type=WSMsgType.CLOSED)
self.messages.pop(0)
if self.messages
else WSMessage(messagetype=WSMsgType.CLOSED)
)


Expand All @@ -56,16 +68,16 @@ class MockResponse:
mock_status: int = 200

@property
def status(self):
def status(self) -> int:
"""status."""
return self.mock_status

@property
def reason(self):
"""Return the reason"""
def reason(self) -> str:
"""Return the reason."""
return "unknown"

async def json(self, **_):
async def json(self, **_: Any) -> Any:
"""json."""
if self.mock_raises is not None:
raise self.mock_raises # pylint: disable=raising-bad-type
Expand All @@ -77,35 +89,38 @@ async def json(self, **_):
return self.mock_data
return load_response(self.mock_endpoint)

def release(self):
def release(self) -> None:
"""release."""

def clear(self):
def clear(self) -> None:
"""clear."""
self.mock_data = None
self.mock_endpoint = ""
self.mock_headers = None
self.mock_raises = None
self.mock_status = 200

async def wait_for_close(self):
pass
async def wait_for_close(self) -> None:
"""wait_for_close."""


class MockedRequests:
"""Mock request class."""

_calls = []
def __init__(self) -> None:
"""Initialize."""
self._calls = []

def add(self, url: str):
def add(self, url: str) -> None:
"""add."""
self._calls.append(url)

def clear(self):
def clear(self) -> None:
"""clear."""
self._calls.clear()

def __repr__(self) -> str:
"""repr."""
return f"<MockedRequests: {self._calls}>"

@property
Expand Down
31 changes: 19 additions & 12 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Test fixtures and configuration."""
import logging
from typing import Any, AsyncGenerator

import aiohttp
import pytest
Expand All @@ -15,39 +16,43 @@


@pytest.fixture
def mock_requests():
def mock_requests() -> MockedRequests:
"""Return a new mock request instanse."""
return MockedRequests()


@pytest.fixture
def mock_response():
def mock_response() -> MockResponse:
"""Return a new mock response instanse."""
return MockResponse()


@pytest.fixture
def mock_ws_messages():
def mock_ws_messages() -> WSMessageHandler:
"""Return a new mock ws instanse."""
return WSMessageHandler()


@pytest_asyncio.fixture
async def client_session(mock_response, mock_requests, mock_ws_messages):
async def client_session(
mock_response: MockResponse,
mock_requests: MockedRequests,
mock_ws_messages: WSMessageHandler,
) -> AsyncGenerator[aiohttp.ClientSession, None]:
"""Mock our the request part of the client session."""

class MockedWSContext:
@property
def closed(self):
def closed(self) -> bool:
return len(mock_ws_messages.messages) == 0

async def receive(self):
async def receive(self) -> Any:
return mock_ws_messages.get()

async def _mocked_ws_connect(*args, **kwargs):
async def _mocked_ws_connect(*_: Any, **__: Any) -> Any:
return MockedWSContext()

async def _mocked_request(*args, **kwargs):
async def _mocked_request(*args: Any, **kwargs: Any) -> Any:
if len(args) > 2:
mock_response.mock_endpoint = args[2].split("/api/")[-1]
mock_requests.add({"method": args[1], "url": args[2], **kwargs})
Expand All @@ -58,18 +63,20 @@ async def _mocked_request(*args, **kwargs):

async with aiohttp.ClientSession() as session:
mock_requests.clear()
session._request = _mocked_request # pylint: disable=protected-access
session._ws_connect = _mocked_ws_connect
session._request = _mocked_request # noqa: SLF001
session._ws_connect = _mocked_ws_connect # noqa: SLF001
yield session


@pytest_asyncio.fixture
async def api_client(client_session):
async def api_client(
client_session: AsyncGenerator[aiohttp.ClientSession, None],
) -> AsyncGenerator[ApiClient, None]:
"""Fixture to provide a API Client."""
yield ApiClient(
host="127.0.0.1",
port=1337,
username="test",
password="test",
password="test", # noqa: S106
client_session=client_session,
)
6 changes: 6 additions & 0 deletions tests/ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This extend our general Ruff rules specifically for tests
extend = "../pyproject.toml"

lint.extend-ignore = [
"S101", # Use of assert detected.
]
10 changes: 5 additions & 5 deletions tests/test_api_calls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,38 @@


@pytest.mark.asyncio
async def test_server(api_client: ApiClient):
async def test_server(api_client: ApiClient) -> None:
"""Test /server endpoint."""
response = await api_client.get_server()
assert response["id"] == 0


@pytest.mark.asyncio
async def test_devices(api_client: ApiClient):
async def test_devices(api_client: ApiClient) -> None:
"""Test /devices endpoint."""
response = await api_client.get_devices()
assert isinstance(response, list)
assert response[0]["id"] == 0


@pytest.mark.asyncio
async def test_geofences(api_client: ApiClient):
async def test_geofences(api_client: ApiClient) -> None:
"""Test /geofences endpoint."""
response = await api_client.get_geofences()
assert isinstance(response, list)
assert response[0]["id"] == 0


@pytest.mark.asyncio
async def test_positions(api_client: ApiClient):
async def test_positions(api_client: ApiClient) -> None:
"""Test /positions endpoint."""
response = await api_client.get_positions()
assert isinstance(response, list)
assert response[0]["id"] == 0


@pytest.mark.asyncio
async def test_reports_events(api_client: ApiClient):
async def test_reports_events(api_client: ApiClient) -> None:
"""Test /reports/events endpoint."""
response = await api_client.get_reports_events()
assert isinstance(response, list)
Expand Down
12 changes: 8 additions & 4 deletions tests/test_base_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@


@pytest.mark.asyncio
async def test_base_api(api_client: ApiClient):
async def test_base_api(api_client: ApiClient) -> None:
"""Test base API."""
response = await api_client.get_server()
assert response["bingKey"] == "string"
Expand All @@ -24,23 +24,27 @@ async def test_base_api(api_client: ApiClient):
@pytest.mark.asyncio
async def test_base_api_unauthenticated(
api_client: ApiClient, mock_response: MockResponse
):
) -> None:
"""Test unauthenticated base API."""
mock_response.mock_status = 401
with pytest.raises(TraccarAuthenticationException):
await api_client.get_server()


@pytest.mark.asyncio
async def test_base_api_issue(api_client: ApiClient, mock_response: MockResponse):
async def test_base_api_issue(
api_client: ApiClient, mock_response: MockResponse
) -> None:
"""Test API issue."""
mock_response.mock_status = 500
with pytest.raises(TraccarResponseException):
await api_client.get_server()


@pytest.mark.asyncio
async def test_base_api_timeout(api_client: ApiClient, mock_response: MockResponse):
async def test_base_api_timeout(
api_client: ApiClient, mock_response: MockResponse
) -> None:
"""Test API issue."""
mock_response.mock_raises = asyncio.TimeoutError
with pytest.raises(TraccarConnectionException):
Expand Down
8 changes: 4 additions & 4 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


@pytest.mark.asyncio
async def test_client_init(client_session: ClientSession):
async def test_client_init(client_session: ClientSession) -> None:
"""Test client init."""
client_params = {
"host": "127.0.0.1",
Expand All @@ -16,12 +16,12 @@ async def test_client_init(client_session: ClientSession):
"client_session": client_session,
}

assert ApiClient(**client_params)._base_url == "http://127.0.0.1:8080/api"
assert ApiClient(**client_params)._base_url == "http://127.0.0.1:8080/api" # noqa: SLF001
assert (
ApiClient(**{**client_params, "port": None})._base_url
ApiClient(**{**client_params, "port": None})._base_url # noqa: SLF001
== "http://127.0.0.1:8082/api"
)
assert (
ApiClient(**{**client_params, "ssl": True})._base_url
ApiClient(**{**client_params, "ssl": True})._base_url # noqa: SLF001
== "https://127.0.0.1:8080/api"
)
Loading

0 comments on commit ea6e513

Please sign in to comment.