Initial commit
This commit is contained in:
141
tests/test_app.py
Normal file
141
tests/test_app.py
Normal file
@@ -0,0 +1,141 @@
|
||||
import importlib
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from typing import List, Tuple
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def client(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> TestClient:
|
||||
monkeypatch.setenv("TELEGRAM_API_ID", "123456")
|
||||
monkeypatch.setenv("TELEGRAM_API_HASH", "testhash")
|
||||
monkeypatch.setenv("BASE_URL", "http://testserver")
|
||||
monkeypatch.setenv("DATABASE_PATH", str(tmp_path / "hooks.json"))
|
||||
monkeypatch.setenv("TELEGRAM_SESSION_PATH", str(tmp_path / "telegram.session"))
|
||||
|
||||
class DummyTelegramClient:
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._connected = False
|
||||
|
||||
async def connect(self) -> None:
|
||||
self._connected = True
|
||||
|
||||
async def disconnect(self) -> None:
|
||||
self._connected = False
|
||||
|
||||
def is_connected(self) -> bool:
|
||||
return self._connected
|
||||
|
||||
async def send_code_request(self, phone: str): # noqa: ANN001
|
||||
return SimpleNamespace(phone_code_hash="dummy-hash")
|
||||
|
||||
async def sign_in(self, *args, **kwargs): # noqa: ANN001, ANN002
|
||||
return None
|
||||
|
||||
def is_user_authorized(self) -> bool:
|
||||
return True
|
||||
|
||||
async def get_me(self): # noqa: ANN201
|
||||
return SimpleNamespace(first_name="Test", last_name="User", username="tester", id=1)
|
||||
|
||||
async def log_out(self) -> None:
|
||||
self._connected = False
|
||||
|
||||
async def send_message(self, *args, **kwargs) -> None: # noqa: ANN001, ANN002
|
||||
return None
|
||||
|
||||
monkeypatch.setattr("telethon.client.telegramclient.TelegramClient", DummyTelegramClient)
|
||||
monkeypatch.setattr("telethon.TelegramClient", DummyTelegramClient)
|
||||
|
||||
# Clear cached settings and reload modules to pick up new paths
|
||||
from app import config
|
||||
|
||||
config.get_settings.cache_clear() # type: ignore[attr-defined]
|
||||
|
||||
importlib.reload(importlib.import_module("app.storage"))
|
||||
telegram_service_module = importlib.reload(importlib.import_module("app.telegram_service"))
|
||||
main_module = importlib.reload(importlib.import_module("app.main"))
|
||||
|
||||
# Stub out Telegram interactions
|
||||
call_log: List[Tuple[str, str]] = []
|
||||
|
||||
async def fake_ensure_connected() -> None:
|
||||
return None
|
||||
|
||||
async def fake_is_authorized() -> bool:
|
||||
return True
|
||||
|
||||
async def fake_get_user() -> str:
|
||||
return "Test User"
|
||||
|
||||
async def fake_send_message(chat_id: str, message: str) -> None:
|
||||
call_log.append((chat_id, message))
|
||||
|
||||
async def fake_disconnect() -> None:
|
||||
return None
|
||||
|
||||
async def fake_verify_code(*args, **kwargs) -> None: # noqa: ANN002
|
||||
return None
|
||||
|
||||
monkeypatch.setattr(main_module.telegram_service, "ensure_connected", fake_ensure_connected)
|
||||
monkeypatch.setattr(main_module.telegram_service, "is_authorized", fake_is_authorized)
|
||||
monkeypatch.setattr(main_module.telegram_service, "get_user", fake_get_user)
|
||||
monkeypatch.setattr(main_module.telegram_service, "send_message", fake_send_message)
|
||||
monkeypatch.setattr(main_module.telegram_service, "disconnect", fake_disconnect)
|
||||
monkeypatch.setattr(main_module.telegram_service, "verify_code", fake_verify_code)
|
||||
monkeypatch.setattr(main_module.telegram_service, "is_connected", lambda: True)
|
||||
|
||||
test_client = TestClient(main_module.app)
|
||||
test_client.call_log = call_log # type: ignore[attr-defined]
|
||||
return test_client
|
||||
|
||||
|
||||
def test_create_list_and_trigger_hook(client: TestClient) -> None:
|
||||
payload = {
|
||||
"chat_id": "@example",
|
||||
"message": "Hello **Markdown**",
|
||||
}
|
||||
create_resp = client.post("/api/hooks", json=payload)
|
||||
assert create_resp.status_code == 201
|
||||
data = create_resp.json()
|
||||
assert data["chat_id"] == payload["chat_id"]
|
||||
assert payload["message"] in data["message"]
|
||||
assert data["action_url"].endswith(f"/action/{data['hook_id']}")
|
||||
|
||||
list_resp = client.get("/api/hooks")
|
||||
assert list_resp.status_code == 200
|
||||
hooks = list_resp.json()
|
||||
assert len(hooks) == 1
|
||||
|
||||
trigger_resp = client.get(f"/action/{data['hook_id']}")
|
||||
assert trigger_resp.status_code == 200
|
||||
assert trigger_resp.json()["status"] == "sent"
|
||||
|
||||
call_log = getattr(client, "call_log")
|
||||
assert call_log == [(payload["chat_id"], payload["message"])]
|
||||
|
||||
new_id = "customid123"
|
||||
patch_resp = client.patch(f"/api/hooks/{data['hook_id']}", json={"hook_id": new_id})
|
||||
assert patch_resp.status_code == 200
|
||||
patched = patch_resp.json()
|
||||
assert patched["hook_id"] == new_id
|
||||
assert patched["action_url"].endswith(f"/action/{new_id}")
|
||||
|
||||
# Old ID should now be gone
|
||||
old_trigger = client.get(f"/action/{data['hook_id']}")
|
||||
assert old_trigger.status_code == 404
|
||||
|
||||
call_log.clear()
|
||||
new_trigger = client.get(f"/action/{new_id}")
|
||||
assert new_trigger.status_code == 200
|
||||
assert getattr(client, "call_log") == [(payload["chat_id"], payload["message"])]
|
||||
|
||||
|
||||
def test_login_verify_without_phone_number(client: TestClient) -> None:
|
||||
response = client.post("/api/login/verify", json={"code": "123456"})
|
||||
assert response.status_code == 200
|
||||
payload = response.json()
|
||||
assert payload["authorized"] is True
|
||||
assert payload["user"] == "Test User"
|
||||
Reference in New Issue
Block a user