f8d3cbdd59
Add the FastAPI app, PostgreSQL migrations, Docker/Helm packaging, API contracts, docs, client examples, and the unit/integration/compatibility test suite for local client and tooling labs without a real vCenter.
62 lines
1.8 KiB
Python
62 lines
1.8 KiB
Python
"""Injectable simulation clocks; task leases deliberately do not use these."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from datetime import UTC, datetime, timedelta
|
|
from typing import Protocol
|
|
|
|
|
|
class Clock(Protocol):
|
|
async def now(self) -> datetime: ...
|
|
|
|
async def sleep(self, seconds: float) -> None: ...
|
|
|
|
|
|
class RealClock:
|
|
async def now(self) -> datetime:
|
|
return datetime.now(UTC)
|
|
|
|
async def sleep(self, seconds: float) -> None:
|
|
await asyncio.sleep(seconds)
|
|
|
|
|
|
class AcceleratedClock:
|
|
def __init__(self, scale: float) -> None:
|
|
if scale <= 0:
|
|
raise ValueError("clock scale must be positive")
|
|
self._scale = scale
|
|
|
|
async def now(self) -> datetime:
|
|
return datetime.now(UTC)
|
|
|
|
async def sleep(self, seconds: float) -> None:
|
|
await asyncio.sleep(seconds / self._scale)
|
|
|
|
|
|
class ManualClock:
|
|
def __init__(self, initial: datetime) -> None:
|
|
if initial.tzinfo is None:
|
|
raise ValueError("manual clock requires timezone-aware time")
|
|
self._now = initial
|
|
self._condition = asyncio.Condition()
|
|
|
|
async def now(self) -> datetime:
|
|
async with self._condition:
|
|
return self._now
|
|
|
|
async def sleep(self, seconds: float) -> None:
|
|
if seconds < 0:
|
|
raise ValueError("sleep duration cannot be negative")
|
|
async with self._condition:
|
|
target = self._now + timedelta(seconds=seconds)
|
|
await self._condition.wait_for(lambda: self._now >= target)
|
|
|
|
async def advance(self, seconds: float) -> datetime:
|
|
if seconds < 0:
|
|
raise ValueError("clock cannot move backwards")
|
|
async with self._condition:
|
|
self._now += timedelta(seconds=seconds)
|
|
self._condition.notify_all()
|
|
return self._now
|