87 lines
2.7 KiB
Python
87 lines
2.7 KiB
Python
"""Tests for HTTP client (mocked)."""
|
|
|
|
import httpx
|
|
import pytest
|
|
import respx
|
|
|
|
from cnmaestro.client import CnMaestroClient, CnMaestroError
|
|
|
|
|
|
BASE = "https://example.test"
|
|
|
|
|
|
@pytest.fixture
|
|
def client(monkeypatch):
|
|
monkeypatch.setenv("CNMAESTRO_BASE_URL", BASE)
|
|
monkeypatch.setenv("CNMAESTRO_CLIENT_ID", "id")
|
|
monkeypatch.setenv("CNMAESTRO_CLIENT_SECRET", "secret")
|
|
c = CnMaestroClient()
|
|
yield c
|
|
c.close()
|
|
|
|
|
|
@respx.mock
|
|
def test_token_fetched_on_first_call(client):
|
|
respx.post(f"{BASE}/api/v2/access/token").mock(
|
|
return_value=httpx.Response(200, json={"access_token": "T1"})
|
|
)
|
|
respx.get(f"{BASE}/api/v2/devices").mock(
|
|
return_value=httpx.Response(200, json={"data": [], "paging": {"total": 0}})
|
|
)
|
|
list(client.paginated("/api/v2/devices"))
|
|
assert client._token == "T1"
|
|
|
|
|
|
@respx.mock
|
|
def test_401_triggers_refresh(client):
|
|
token_route = respx.post(f"{BASE}/api/v2/access/token").mock(
|
|
side_effect=[
|
|
httpx.Response(200, json={"access_token": "T1"}),
|
|
httpx.Response(200, json={"access_token": "T2"}),
|
|
]
|
|
)
|
|
respx.get(f"{BASE}/api/v2/devices").mock(
|
|
side_effect=[
|
|
httpx.Response(401),
|
|
httpx.Response(200, json={"data": [], "paging": {"total": 0}}),
|
|
]
|
|
)
|
|
list(client.paginated("/api/v2/devices"))
|
|
assert token_route.call_count == 2
|
|
assert client._token == "T2"
|
|
|
|
|
|
@respx.mock
|
|
def test_paginated_walks_offsets(client):
|
|
respx.post(f"{BASE}/api/v2/access/token").mock(
|
|
return_value=httpx.Response(200, json={"access_token": "T"})
|
|
)
|
|
page1 = [{"mac": f"M{i}"} for i in range(100)]
|
|
page2 = [{"mac": f"M{i}"} for i in range(100, 150)]
|
|
respx.get(f"{BASE}/api/v2/devices", params={"limit": 100, "offset": 0}).mock(
|
|
return_value=httpx.Response(200, json={"data": page1, "paging": {"total": 150}})
|
|
)
|
|
respx.get(f"{BASE}/api/v2/devices", params={"limit": 100, "offset": 100}).mock(
|
|
return_value=httpx.Response(200, json={"data": page2, "paging": {"total": 150}})
|
|
)
|
|
items = list(client.paginated("/api/v2/devices"))
|
|
assert len(items) == 150
|
|
|
|
|
|
@respx.mock
|
|
def test_delete_propagates_error(client):
|
|
respx.post(f"{BASE}/api/v2/access/token").mock(
|
|
return_value=httpx.Response(200, json={"access_token": "T"})
|
|
)
|
|
respx.delete(f"{BASE}/api/v2/devices/AA:BB").mock(
|
|
return_value=httpx.Response(404, text="not found")
|
|
)
|
|
with pytest.raises(CnMaestroError):
|
|
client.delete("/api/v2/devices/AA:BB")
|
|
|
|
|
|
def test_missing_credentials_raises(monkeypatch):
|
|
monkeypatch.delenv("CNMAESTRO_CLIENT_ID", raising=False)
|
|
monkeypatch.delenv("CNMAESTRO_CLIENT_SECRET", raising=False)
|
|
with pytest.raises(CnMaestroError):
|
|
CnMaestroClient()
|