Skip to content

Commit

Permalink
test(pytest): add test configuration and fixtures
Browse files Browse the repository at this point in the history
Add initial test setup for politikontroller_py including:
- Basic pytest configuration with asyncio support
- Client and Account fixtures
- Custom aresponses route handler for API testing
- Initial API check test
  • Loading branch information
bendikrb committed Dec 2, 2024
1 parent c32cd95 commit 9684e34
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 0 deletions.
5 changes: 5 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""politikontroller_py tests."""

import pytest

pytestmark = pytest.mark.asyncio(loop_scope="package")
29 changes: 29 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from __future__ import annotations

import logging
from typing import Callable

import pytest

from politikontroller_py import Account, Client

_LOGGER = logging.getLogger(__name__)


@pytest.fixture
async def politikontroller_client(default_login_details) -> Callable[..., Client]:
"""Return Politikontroller Client."""

def _politikontroller_client(
credentials: Account | None = None,
load_default_login_details: bool = True,
) -> Client:
login_details = default_login_details if load_default_login_details is True else credentials
return Client.initialize(login_details.username, login_details.password)

return _politikontroller_client


@pytest.fixture
def default_login_details():
return Account(username="4747474747", password="securepassword123")
1 change: 1 addition & 0 deletions tests/fixtures/check.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2sSIAJIbo5IKek7JJ/M6ng==
63 changes: 63 additions & 0 deletions tests/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from __future__ import annotations

from pathlib import Path
from urllib.parse import parse_qs, urlencode, urlparse

from aresponses.main import Route

# noinspection PyProtectedMember
from aresponses.utils import ANY, _text_matches_pattern

from politikontroller_py.utils import aes_decrypt

FIXTURE_DIR = Path(__file__).parent / "fixtures"


def load_fixture(name: str) -> str:
"""Load a fixture."""
path = FIXTURE_DIR / f"{name}.txt"
if not path.exists(): # pragma: no cover
raise FileNotFoundError(f"Fixture {name} not found")
return path.read_text(encoding="utf-8")


class CustomRoute(Route):
"""Custom route for aresponses."""

def __init__(
self,
method_pattern=ANY,
host_pattern=ANY,
path_pattern=ANY,
path_qs=None,
body_pattern=ANY,
match_querystring=False,
match_partial_query=True,
repeat=1,
):
super().__init__(method_pattern, host_pattern, path_pattern, body_pattern, match_querystring, repeat)
if path_qs is not None:
self.path_qs = urlencode({k: v for k, v in path_qs.items() if v is not None})
self.match_querystring = True
self.match_partial_query = match_partial_query

async def matches(self, request):
"""Check if the request matches this route."""
path_to_match = urlparse(request.path_qs)
query_to_match = parse_qs(aes_decrypt(path_to_match.query))
parsed_query = parse_qs(self.path_qs) if self.path_qs else {}

if not _text_matches_pattern(self.host_pattern, request.host):
return False

if self.match_querystring:
if not self.match_partial_query and query_to_match != parsed_query:
return False
for key, value in parsed_query.items():
if key not in query_to_match or query_to_match[key] != value:
return False

if not _text_matches_pattern(self.method_pattern, request.method): # noqa: SIM103
return False

return True
17 changes: 17 additions & 0 deletions tests/ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# This extends our general Ruff rules specifically for tests
extend = "../pyproject.toml"

lint.extend-select = [
"PT", # Use @pytest.fixture without parentheses
]

lint.extend-ignore = [
"S101",
"S106",
"S108",
"SLF001",
"TCH002",
"PLR2004",
]

lint.pylint.max-branches = 13
28 changes: 28 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""Tests for NrkPodcastAPI."""

from __future__ import annotations

import logging

from aiohttp import ClientSession
from aresponses import Response, ResponsesMockServer

from politikontroller_py.models.api import APIEndpoint

from .helpers import CustomRoute, load_fixture

logger = logging.getLogger(__name__)


async def test_check(aresponses: ResponsesMockServer, politikontroller_client):
aresponses.add(
response=Response(text=load_fixture("check")),
route=CustomRoute(
path_qs={"p": APIEndpoint.CHECK},
),
)
async with ClientSession() as session:
client = politikontroller_client()
client.session = session
result = await client.check()
assert result == "YES"

0 comments on commit 9684e34

Please sign in to comment.