Initial commit: stateful OpenStack API laboratory simulator.

Ship Keystone auth, multi-service handlers (Yoga→Dalmatian), Compose/Helm
packaging, API contract packs, and pytest/Pulumi coverage labs.
This commit is contained in:
2026-07-18 04:26:48 +03:00
commit 6033967e6a
509 changed files with 464404 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
"""PostgreSQL-backed integration tests."""
+130
View File
@@ -0,0 +1,130 @@
"""PostgreSQL migration acceptance checks."""
import os
import uuid
import asyncpg # type: ignore[import-untyped]
import pytest
from app.config import Settings
from app.db.migrations import migrate
from app.db.pool import AsyncpgDatabase
from app.db.primitives import ConflictError
from app.db.repositories.resources import ResourceRepository
from app.simulation.seed import apply_seed, small_profile
pytestmark = [
pytest.mark.integration,
pytest.mark.skipif(not os.getenv("TEST_DATABASE_URL"), reason="TEST_DATABASE_URL is required"),
]
async def test_migration_is_repeatable_and_constraints_hold() -> None:
connection = await asyncpg.connect(os.environ["TEST_DATABASE_URL"])
try:
await migrate(connection)
assert await migrate(connection) == 0
node_id = uuid.uuid4()
await connection.execute(
"INSERT INTO nodes(id, name, status) VALUES($1, $2, 'online') ON CONFLICT DO NOTHING",
node_id,
f"test-{node_id}",
)
with pytest.raises(asyncpg.CheckViolationError):
async with connection.transaction():
await connection.execute(
"INSERT INTO nodes(id, name, status) VALUES($1, $2, 'invalid')",
uuid.uuid4(),
f"invalid-{node_id}",
)
finally:
await connection.close()
async def test_small_seed_is_idempotent() -> None:
connection = await asyncpg.connect(os.environ["TEST_DATABASE_URL"])
try:
await migrate(connection)
await apply_seed(connection, small_profile())
await apply_seed(connection, small_profile())
assert await connection.fetchval("SELECT count(*) FROM nodes WHERE name = 'pve01'") == 1
assert (
await connection.fetchval(
"""SELECT count(*) FROM resources
WHERE external_id IN ('100', '101', '200', 'local', 'local-lvm')"""
)
== 5
)
assert await connection.fetchval("SELECT count(*) FROM tasks WHERE status = 'success'") == 2
assert await connection.fetchval("SELECT count(*) FROM virtual_machines") == 2
assert await connection.fetchval("SELECT count(*) FROM containers") == 1
assert await connection.fetchval("SELECT count(*) FROM storages") == 2
assert await connection.fetchval("SELECT count(*) FROM storage_contents") == 4
assert await connection.fetchval("SELECT count(*) FROM identity_groups") == 1
assert await connection.fetchval("SELECT count(*) FROM identity_group_members") == 1
assert await connection.fetchval("SELECT count(*) FROM group_acl_entries") == 1
assert await connection.fetchval("SELECT count(*) FROM roles") == 3
assert await connection.fetchval("SELECT count(*) FROM api_tokens") == 4
secrets = await connection.fetch("SELECT secret_hash FROM api_tokens")
assert all(str(row["secret_hash"]).startswith("scrypt$") for row in secrets)
assert all("-secret" not in str(row["secret_hash"]) for row in secrets)
finally:
await connection.close()
async def test_demo_cluster_seed_populates_realistic_state() -> None:
connection = await asyncpg.connect(os.environ["TEST_DATABASE_URL"])
try:
await migrate(connection)
from app.simulation.seed import build_profile
await apply_seed(connection, build_profile("demo-cluster"))
assert await connection.fetchval("SELECT count(*) FROM nodes") == 20
assert await connection.fetchval("SELECT count(*) FROM virtual_machines") == 850
assert await connection.fetchval("SELECT count(*) FROM containers") == 150
assert (
await connection.fetchval("SELECT count(*) FROM resources WHERE kind = 'ceph-osd'")
== 300
)
assert await connection.fetchval("SELECT count(*) FROM backups") >= 400
assert await connection.fetchval("SELECT count(*) FROM task_logs") >= 500
assert await connection.fetchval("SELECT count(*) FROM snapshots") >= 100
ceph_capacity = await connection.fetchval(
"SELECT capacity_bytes FROM storages WHERE storage_id = 'ceph-prod'"
)
assert ceph_capacity == 5 * 1024**5
profile = await connection.fetchval("SELECT metadata->>'profile' FROM clusters LIMIT 1")
assert profile == "demo-cluster"
finally:
await connection.close()
async def test_schema_readiness_and_optimistic_resource_repository() -> None:
url = os.environ["TEST_DATABASE_URL"]
connection = await asyncpg.connect(url)
database = AsyncpgDatabase(Settings(database_url=url))
try:
await migrate(connection)
await apply_seed(connection, small_profile())
await database.connect()
assert await database.is_ready()
repository = ResourceRepository(database.pool)
resource = await repository.get(kind="qemu", external_id="101")
assert resource is not None
updated = await repository.update_state(
resource.id,
expected_version=resource.version,
state={**resource.state, "status": "running"},
)
assert updated.version == resource.version + 1
assert updated.state["status"] == "running"
with pytest.raises(ConflictError):
await repository.update_state(
resource.id,
expected_version=resource.version,
state=resource.state,
)
finally:
await database.close()
await connection.close()
+81
View File
@@ -0,0 +1,81 @@
"""Durable task concurrency and recovery tests."""
import asyncio
import os
import uuid
import asyncpg # type: ignore[import-untyped]
import pytest
from asyncpg import Pool
from app.db.migrations import migrate
from app.tasks.repository import TaskRepository
pytestmark = [
pytest.mark.integration,
pytest.mark.skipif(not os.getenv("TEST_DATABASE_URL"), reason="TEST_DATABASE_URL is required"),
]
async def repository() -> tuple[Pool, TaskRepository]:
pool = await asyncpg.create_pool(os.environ["TEST_DATABASE_URL"], min_size=1, max_size=4)
async with pool.acquire() as connection:
await migrate(connection)
return pool, TaskRepository(pool)
async def test_two_worker_exclusion_idempotency_and_logs() -> None:
pool, tasks = await repository()
key = uuid.uuid4().hex
try:
created = await tasks.create(
upid=f"UPID:pve1:00000001:00000001:00000001:test:{key}:root@pam:",
task_type="test",
payload={"value": 1},
resource_key=f"vm:{key}",
idempotency_key=key,
)
repeated = await tasks.create(
upid=f"ignored-{key}", task_type="test", payload={}, idempotency_key=key
)
assert repeated.id == created.id
first, second = await asyncio.gather(
tasks.claim("worker-a", 30), tasks.claim("worker-b", 30)
)
claimed = first or second
assert claimed is not None
assert (first is None) != (second is None)
worker = "worker-a" if first is not None else "worker-b"
await tasks.append_log(claimed.id, "started")
await tasks.progress(claimed.id, worker, 50)
await tasks.finish(claimed.id, worker, status="success", result={"ok": True})
assert await tasks.logs(claimed.id) == ("started",)
finished = await tasks.get(claimed.id)
assert finished is not None
assert finished.status == "success"
finally:
await pool.close()
async def test_expired_lease_is_reclaimed_after_restart() -> None:
pool, tasks = await repository()
key = uuid.uuid4().hex
try:
created = await tasks.create(
upid=f"UPID:pve1:00000001:00000001:00000001:test:{key}:root@pam:",
task_type="test",
payload={},
)
assert await tasks.claim("dead-worker", 0) is not None
recovered = await tasks.claim("new-worker", 30)
assert recovered is not None
assert recovered.id == created.id
assert recovered.attempt == 2
await tasks.request_cancel(recovered.id)
cancelled = await tasks.get(recovered.id)
assert cancelled is not None
assert cancelled.cancel_requested
await tasks.finish(recovered.id, "new-worker", status="cancelled")
finally:
await pool.close()