from __future__ import annotations from datetime import datetime, timezone from typing import Any, cast from uuid import uuid4 import pytest from models.automation_jobs import ScheduleType from v1.auth.registration_bootstrap import ( compute_first_run_at_utc, ) from schemas.domain.automation import ScheduleConfig, ScheduleRunAt def test_compute_first_run_at_utc_from_asia_shanghai() -> None: now_utc = datetime(2026, 3, 23, 0, 30, tzinfo=timezone.utc) first_run_at = compute_first_run_at_utc( now_utc=now_utc, timezone_name="Asia/Shanghai", schedule=ScheduleConfig( type=ScheduleType.DAILY, run_at=ScheduleRunAt(hour=8, minute=0), ), ) assert first_run_at == datetime(2026, 3, 24, 0, 0, tzinfo=timezone.utc) def test_compute_first_run_at_utc_rolls_to_next_day_when_passed() -> None: now_utc = datetime(2026, 3, 23, 2, 30, tzinfo=timezone.utc) first_run_at = compute_first_run_at_utc( now_utc=now_utc, timezone_name="Asia/Shanghai", schedule=ScheduleConfig( type=ScheduleType.DAILY, run_at=ScheduleRunAt(hour=8, minute=0), ), ) assert first_run_at == datetime(2026, 3, 24, 0, 0, tzinfo=timezone.utc) @pytest.mark.asyncio async def test_registration_service_is_idempotent_when_job_exists() -> None: from v1.auth.registration_bootstrap import RegistrationAutomationBootstrapService expected_owner_id = uuid4() class _Repo: inserted = 0 upsert_calls = 0 async def get_profile_timezone(self, *, user_id): assert user_id == expected_owner_id return "Asia/Shanghai" async def insert_bootstrap_automation_job_if_absent(self, **kwargs): assert kwargs["owner_id"] == expected_owner_id assert kwargs["bootstrap_key"] == "memory_extraction" self.inserted += 1 return False async def upsert_initial_memory(self, **kwargs): self.upsert_calls += 1 return False class _Session: async def commit(self): raise AssertionError("must not commit when already exists") async def rollback(self): raise AssertionError("must not rollback when no error") service = RegistrationAutomationBootstrapService( repository=cast(Any, _Repo()), session=cast(Any, _Session()) ) await service.ensure_user_automation_jobs(user_id=str(expected_owner_id)) @pytest.mark.asyncio async def test_registration_service_creates_initial_memories_when_missing() -> None: from v1.auth.registration_bootstrap import RegistrationAutomationBootstrapService expected_owner_id = uuid4() class _Repo: async def get_profile_timezone(self, *, user_id): assert user_id == expected_owner_id return "Asia/Shanghai" async def upsert_initial_memory(self, **kwargs): return True async def insert_bootstrap_automation_job_if_absent(self, **kwargs): _ = kwargs return True class _Session: committed = 0 async def commit(self): self.committed += 1 async def rollback(self): raise AssertionError("must not rollback when no error") session = _Session() service = RegistrationAutomationBootstrapService( repository=cast(Any, _Repo()), session=cast(Any, session) ) await service.ensure_user_automation_jobs(user_id=str(expected_owner_id)) assert session.committed == 1