Files
inecs f8d3cbdd59 Initial commit: VMware vSphere API simulator scaffold.
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.
2026-07-18 04:42:11 +03:00

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