Source code for florist.tests.integration.api.utils
import contextlib
import os
from typing import Literal
import pytest
import time
import threading
import uvicorn
import requests
from motor.motor_asyncio import AsyncIOMotorClient
from starlette.requests import Request
from florist.api.db.client_entities import EntityDAO
from florist.api.db.config import DatabaseConfig
from florist.api.auth.token import Token, _simple_hash, DEFAULT_USERNAME, DEFAULT_PASSWORD
[docs]
class TestUvicornServer(uvicorn.Server):
[docs]
@contextlib.contextmanager
def run_in_thread(self):
thread = threading.Thread(target=self.run)
thread.start()
try:
while not self.started:
time.sleep(1e-3)
yield
finally:
self.should_exit = True
thread.join()
[docs]
class MockApp:
def __init__(self, database_name: str):
self.db_client = AsyncIOMotorClient(DatabaseConfig.mongodb_uri)
self.database = self.db_client[database_name]
self.clients_auth_tokens = {}
[docs]
class MockRequest(Request):
def __init__(self, app: MockApp):
super().__init__({"type": "http"})
self._app = app
@property
def app(self):
return self._app
@app.setter
def app(self, value):
self._app = value
TEST_DATABASE_NAME = "test-database"
TEST_SQLITE_DB_PATH = "florist/tests/integration/api/client.db"
[docs]
@pytest.fixture
async def mock_request() -> MockRequest:
print(f"Creating test detabase '{TEST_DATABASE_NAME}'")
app = MockApp(TEST_DATABASE_NAME)
request = MockRequest(app)
print(f"Creating test detabase '{TEST_SQLITE_DB_PATH}'")
real_db_path = EntityDAO.db_path
EntityDAO.db_path = TEST_SQLITE_DB_PATH
yield request
print(f"Deleting test detabase '{TEST_DATABASE_NAME}'")
await app.db_client.drop_database(TEST_DATABASE_NAME)
EntityDAO.db_path = real_db_path
if os.path.exists(TEST_SQLITE_DB_PATH):
print(f"Deleting test detabase '{TEST_SQLITE_DB_PATH}'")
os.remove(TEST_SQLITE_DB_PATH)
[docs]
@pytest.fixture
async def use_test_database() -> None:
# saving real database config
sqlite_db_path = DatabaseConfig.sqlite_db_path
database_name = DatabaseConfig.mongodb_db_name
# replacing real database config with test database config
DatabaseConfig.sqlite_db_path = TEST_SQLITE_DB_PATH
EntityDAO.db_path = DatabaseConfig.sqlite_db_path
print(f"Creating test detabase '{DatabaseConfig.sqlite_db_path}'")
DatabaseConfig.mongodb_db_name = TEST_DATABASE_NAME
print(f"Using test detabase '{DatabaseConfig.mongodb_db_name}'")
yield
# restoring real database config
DatabaseConfig.sqlite_db_path = sqlite_db_path
EntityDAO.db_path = sqlite_db_path
DatabaseConfig.mongodb_db_name = database_name
# deleting test databases
print(f"Deleting test detabase '{TEST_DATABASE_NAME}'")
db_client = AsyncIOMotorClient(DatabaseConfig.mongodb_uri)
await db_client.drop_database(TEST_DATABASE_NAME)
if os.path.exists(TEST_SQLITE_DB_PATH):
print(f"Deleting test detabase '{TEST_SQLITE_DB_PATH}'")
os.remove(TEST_SQLITE_DB_PATH)
[docs]
def change_default_password(address: str, new_password: str, type: Literal["server", "client"]) -> None:
response = requests.post(
f"http://{address}/api/{type}/auth/change_password",
data={
"grant_type": "password",
"username": DEFAULT_USERNAME,
"current_password": _simple_hash(DEFAULT_PASSWORD),
"new_password": new_password,
},
)
assert response.status_code == 200, f"Failed to change {type} password: {response.json()}"
return Token(**response.json())