from pathlib import Path from uuid import UUID import pytest from caribou.migrate import Database as CaribouDatabase from caribou.migrate import load_migrations from polyfactory.factories.pydantic_factory import ModelFactory from polyfactory.pytest_plugin import register_fixture from pydantic import BaseModel from huesoporro.infra.repos import ChatbotRepo, IRepo, QuoteRepo, UserRepo from huesoporro.models import Chatbot, Quote, TwitchAuth, User from huesoporro.settings import Settings from huesoporro.svc.backoff_service import BackoffService from huesoporro.svc.chatbot_svcs import ( CreateChatbotSvc, GetChatbotByUserIdSvc, UpdateChatbotSvc, ) from huesoporro.svc.hello import HelloGeneratorSvc from huesoporro.svc.is_mod import IsModSvc from huesoporro.svc.quotes_svcs import CreateQuoteSvc, GetRandomQuoteSvc from huesoporro.svc.users_svcs import ( CreateUserSvc, DeleteUserSvc, GetTwitchAuthByAuthCodeSvc, GetUserByIdSvc, GetUserByUsernameSvc, UpdateUserSvc, ) @register_fixture() class TwitchAuthFactory(ModelFactory[TwitchAuth]): ... @register_fixture() class ChatbotFactory(ModelFactory[Chatbot]): ... @register_fixture() class UserFactory(ModelFactory[User]): ... @register_fixture() class QuoteFactory(ModelFactory[Quote]): ... @pytest.fixture def s(tmp_path: Path, user: User) -> Settings: return Settings( static_files_path=tmp_path / "static_files", db_filepath=tmp_path / "huesoporro.db", twitch_client_id="test_client_id", twitch_client_secret="test_client_secret", # type: ignore[arg-type] # noqa: S106 jwt_secret="test_jwt_secret", # type: ignore[arg-type] # noqa: S106 allowed_users=[user.username], ) @pytest.fixture def db(s, cdb): class BogusRepo(IRepo[BaseModel]): async def get_by_id(self, obj_id: UUID, auto_commit=True) -> BaseModel | None: pass async def list( # type: ignore[empty-body] self, offset: int = 0, limit: int = 10, auto_commit=True ) -> list[BaseModel]: pass async def create(self, obj: BaseModel, auto_commit: bool = True) -> BaseModel: # type: ignore[empty-body] pass async def update(self, obj: BaseModel, auto_commit=True) -> BaseModel: # type: ignore[empty-body] pass async def delete(self, obj: BaseModel, auto_commit=True) -> None: # type: ignore[empty-body] pass async def get_by_user(self, user: str) -> BaseModel: # type: ignore[empty-body] pass return BogusRepo(s=s).get_client @pytest.fixture def cdb(s) -> CaribouDatabase: cdb = CaribouDatabase( db_url=s.db_filepath, ) cdb.initialize_version_control() migrations = load_migrations(Path(__file__).parents[1] / "migrations") cdb.upgrade(migrations) return cdb @pytest.fixture async def user_repo(s, db): return UserRepo(s=s) @pytest.fixture def twitch_auth(twitch_auth_factory): return twitch_auth_factory.build( userinfo={ "aud": twitch_auth_factory.__faker__.pystr(), "exp": twitch_auth_factory.__faker__.pyint(), "iat": twitch_auth_factory.__faker__.pyint(), "iss": "https://id.twitch.tv/oauth2", "sub": twitch_auth_factory.__faker__.pystr(), "azp": twitch_auth_factory.__faker__.pystr(), "preferred_username": twitch_auth_factory.__faker__.user_name(), } ) @pytest.fixture async def user(user_factory: UserFactory, twitch_auth) -> User: return user_factory.build(external_auth={"twitch": twitch_auth}) @pytest.fixture async def persisted_user(user_repo: UserRepo, user: User) -> User: return await user_repo.create(user) @pytest.fixture def create_user_svc(user_repo): return CreateUserSvc(user_repo=user_repo) @pytest.fixture def update_user_svc(user_repo): return UpdateUserSvc(user_repo=user_repo) @pytest.fixture def delete_user_svc(user_repo): return DeleteUserSvc(user_repo=user_repo) @pytest.fixture def get_user_by_id_svc(user_repo): return GetUserByIdSvc(user_repo=user_repo) @pytest.fixture def get_user_by_username_svc(user_repo): return GetUserByUsernameSvc(user_repo=user_repo) @pytest.fixture def get_twitch_auth_by_auth_code_svc( twitch_authenticator, fake_twitch_authenticator, user_repo, s ): svc = GetTwitchAuthByAuthCodeSvc(authenticator=twitch_authenticator, s=s) svc.authenticator = fake_twitch_authenticator return svc @pytest.fixture async def chatbot_repo(s, db): return ChatbotRepo(s=s) @pytest.fixture async def chatbot(chatbot_factory, user): return chatbot_factory.build(user_id=user.id) @pytest.fixture async def five_chatbots(chatbot_factory, user): return [chatbot_factory.build() for _ in range(5)] @pytest.fixture async def persisted_five_chatbots(five_chatbots, chatbot_repo): return [await chatbot_repo.create(chatbot) for chatbot in five_chatbots] @pytest.fixture async def persisted_chatbot(chatbot_repo, chatbot, persisted_user): return await chatbot_repo.create(chatbot) @pytest.fixture async def create_chatbot_svc(chatbot_repo): return CreateChatbotSvc(repo=chatbot_repo) @pytest.fixture async def get_chatbot_by_user_id_svc(chatbot_repo): return GetChatbotByUserIdSvc(repo=chatbot_repo) @pytest.fixture async def update_chatbot_svc(chatbot_repo): return UpdateChatbotSvc(repo=chatbot_repo) @pytest.fixture async def is_mod_svc(chatbot_repo): return IsModSvc(repo=chatbot_repo) @pytest.fixture async def quote_repo(s, db): return QuoteRepo(s=s) @pytest.fixture async def quote(quote_factory): return quote_factory.build() @pytest.fixture async def five_quotes(quote_factory): return [quote_factory.build() for _ in range(5)] @pytest.fixture async def persisted_quote(quote_repo, quote): quote.is_active = True return await quote_repo.create(quote) @pytest.fixture async def persisted_five_quotes(five_quotes, quote_repo): return [await quote_repo.create(quote) for quote in five_quotes] @pytest.fixture async def create_quote_svc(quote_repo): return CreateQuoteSvc(repo=quote_repo) @pytest.fixture async def get_random_quote_svc(quote_repo): return GetRandomQuoteSvc(repo=quote_repo) @pytest.fixture def backoff_callable(): def foo(): return "foo" return foo @pytest.fixture def async_backoff_callable(): async def async_foo(): return "async foo" return async_foo @pytest.fixture async def backoff_svc(backoff_callable, async_backoff_callable): backoff_svc = BackoffService() backoff_svc.add_callable(backoff_callable, 3) backoff_svc.add_callable(async_backoff_callable, 3) return backoff_svc @pytest.fixture async def hello_generator_svc(): return HelloGeneratorSvc()