Add tests/test_auth.py

This commit is contained in:
2026-09-02 16:45:34 +03:00
parent 686acb4423
commit 2dbdc571b9
+119
View File
@@ -0,0 +1,119 @@
"""Unit-тесты IAM-авторизации и кэша токена."""
from __future__ import annotations
import datetime as dt
import httpx
import pytest
from selectel_ml_tui.auth import (
IamAuthError,
IamClient,
IamToken,
IamTokenManager,
)
from selectel_ml_tui.config import Credentials, Settings
class FakeIamClient:
"""Заглушка IamClient для проверки логики кэширования."""
def __init__(self, token: IamToken) -> None:
self._token = token
self.calls = 0
async def get_token(self) -> IamToken:
self.calls += 1
return self._token
def _far_future() -> dt.datetime:
return dt.datetime.now(dt.timezone.utc) + dt.timedelta(hours=23)
def _expired() -> dt.datetime:
return dt.datetime.now(dt.timezone.utc) - dt.timedelta(minutes=1)
async def test_iam_get_token_success() -> None:
def handler(request: httpx.Request) -> httpx.Response:
body = request.content.decode()
assert '"name":"svc-user"' in body
assert '"password":"secret"' in body
assert '"id":"proj-1"' in body
return httpx.Response(
201,
headers={"X-Subject-Token": "iam-token-abc"},
json={
"token": {
"expires_at": "2026-08-20T10:00:00.000000Z",
}
},
)
client = IamClient(
Settings(),
Credentials(
service_user="svc-user",
password="secret",
domain_id="239633",
project_id="proj-1",
),
transport=httpx.MockTransport(handler),
)
token = await client.get_token()
assert token.value == "iam-token-abc"
assert token.expires_at == dt.datetime(2026, 8, 20, 10, 0, tzinfo=dt.timezone.utc)
async def test_iam_get_token_missing_credentials() -> None:
client = IamClient(Settings(), Credentials())
with pytest.raises(IamAuthError, match="логин/пароль"):
await client.get_token()
async def test_iam_get_token_missing_subject_token() -> None:
def handler(request: httpx.Request) -> httpx.Response:
return httpx.Response(
201, json={"token": {"expires_at": "2026-08-20T10:00:00Z"}}
)
client = IamClient(
Settings(),
Credentials(
service_user="svc", password="pwd", domain_id="239633", project_id="p"
),
transport=httpx.MockTransport(handler),
)
with pytest.raises(IamAuthError, match="X-Subject-Token"):
await client.get_token()
async def test_iam_token_manager_caches() -> None:
fake = FakeIamClient(IamToken(value="t1", expires_at=_far_future()))
manager = IamTokenManager(fake) # type: ignore[arg-type]
assert await manager.get_token() == "t1"
assert await manager.get_token() == "t1"
assert fake.calls == 1
assert manager.is_valid()
async def test_iam_token_manager_refreshes_after_expiry() -> None:
fake = FakeIamClient(IamToken(value="t-expired", expires_at=_expired()))
manager = IamTokenManager(fake) # type: ignore[arg-type]
assert await manager.get_token() == "t-expired"
assert not manager.is_valid()
assert await manager.get_token() == "t-expired"
assert fake.calls == 2
async def test_iam_token_manager_invalidate() -> None:
fake = FakeIamClient(IamToken(value="t1", expires_at=_far_future()))
manager = IamTokenManager(fake) # type: ignore[arg-type]
await manager.get_token()
assert manager.is_valid()
manager.invalidate()
assert not manager.is_valid()
await manager.get_token()
assert fake.calls == 2