forked from cleveragents/cleveragents-core
141 lines
4.9 KiB
Python
141 lines
4.9 KiB
Python
"""ASV benchmarks for project repository operations.
|
|
|
|
Measures:
|
|
- NamespacedProjectRepository create/get/list throughput
|
|
- ProjectResourceLinkRepository create_link/list_links throughput
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime
|
|
|
|
from sqlalchemy import create_engine, event, text
|
|
from sqlalchemy.orm import sessionmaker
|
|
|
|
from cleveragents.domain.models.core.project import NamespacedProject
|
|
from cleveragents.infrastructure.database.models import (
|
|
Base,
|
|
ResourceModel,
|
|
ResourceTypeModel,
|
|
)
|
|
from cleveragents.infrastructure.database.repositories import (
|
|
NamespacedProjectRepository,
|
|
ProjectResourceLinkRepository,
|
|
)
|
|
|
|
|
|
def _now_iso() -> str:
|
|
return datetime.now(tz=UTC).isoformat()
|
|
|
|
|
|
def _set_sqlite_pragma(dbapi_conn: object, _connection_record: object) -> None:
|
|
cursor = dbapi_conn.cursor() # type: ignore[union-attr]
|
|
cursor.execute("PRAGMA foreign_keys = ON")
|
|
cursor.close()
|
|
|
|
|
|
class ProjectRepositoryCRUD:
|
|
"""Benchmark project repository CRUD operations."""
|
|
|
|
def setup(self) -> None:
|
|
self.engine = create_engine("sqlite:///:memory:")
|
|
event.listen(self.engine, "connect", _set_sqlite_pragma)
|
|
with self.engine.connect() as conn:
|
|
conn.execute(text("PRAGMA foreign_keys = ON"))
|
|
conn.commit()
|
|
Base.metadata.create_all(self.engine)
|
|
self.sf = sessionmaker(bind=self.engine)
|
|
|
|
def teardown(self) -> None:
|
|
self.engine.dispose()
|
|
|
|
def time_create_and_get_project(self) -> None:
|
|
repo = NamespacedProjectRepository(session_factory=self.sf)
|
|
session = self.sf()
|
|
project = NamespacedProject(name="bench-proj", namespace="bench")
|
|
repo.create(project)
|
|
session.commit()
|
|
repo.get("bench/bench-proj")
|
|
repo.delete("bench/bench-proj")
|
|
session.commit()
|
|
|
|
def time_list_50_projects(self) -> None:
|
|
repo = NamespacedProjectRepository(session_factory=self.sf)
|
|
session = self.sf()
|
|
for i in range(50):
|
|
repo.create(NamespacedProject(name=f"proj-{i}", namespace="bench"))
|
|
session.commit()
|
|
repo.list_projects(namespace="bench", limit=50)
|
|
for i in range(50):
|
|
repo.delete(f"bench/proj-{i}")
|
|
session.commit()
|
|
|
|
|
|
class LinkRepositoryCRUD:
|
|
"""Benchmark link repository operations."""
|
|
|
|
def setup(self) -> None:
|
|
self.engine = create_engine("sqlite:///:memory:")
|
|
event.listen(self.engine, "connect", _set_sqlite_pragma)
|
|
with self.engine.connect() as conn:
|
|
conn.execute(text("PRAGMA foreign_keys = ON"))
|
|
conn.commit()
|
|
Base.metadata.create_all(self.engine)
|
|
|
|
# Use a single session for all setup operations so FK
|
|
# relationships are visible within the same transaction.
|
|
self._setup_session = sessionmaker(bind=self.engine)()
|
|
self.sf = sessionmaker(bind=self.engine)
|
|
|
|
session = self._setup_session
|
|
# Resource type
|
|
rt = ResourceTypeModel()
|
|
rt.name = "bench/git-checkout" # type: ignore[assignment]
|
|
rt.namespace = "bench" # type: ignore[assignment]
|
|
rt.resource_kind = "physical" # type: ignore[assignment]
|
|
rt.user_addable = True # type: ignore[assignment]
|
|
rt.created_at = _now_iso() # type: ignore[assignment]
|
|
rt.updated_at = _now_iso() # type: ignore[assignment]
|
|
session.add(rt)
|
|
session.commit()
|
|
|
|
# Project — use the same session so the commit is on the same
|
|
# connection that created the resource type.
|
|
project_repo = NamespacedProjectRepository(
|
|
session_factory=lambda: session,
|
|
)
|
|
project_repo.create(NamespacedProject(name="link-bench", namespace="bench"))
|
|
session.commit()
|
|
|
|
# Resources
|
|
for i in range(30):
|
|
r = ResourceModel()
|
|
r.resource_id = str(i).zfill(26) # type: ignore[assignment]
|
|
r.type_name = "bench/git-checkout" # type: ignore[assignment]
|
|
r.resource_kind = "physical" # type: ignore[assignment]
|
|
r.created_at = _now_iso() # type: ignore[assignment]
|
|
r.updated_at = _now_iso() # type: ignore[assignment]
|
|
session.add(r)
|
|
session.commit()
|
|
|
|
def teardown(self) -> None:
|
|
self.engine.dispose()
|
|
|
|
def time_create_and_list_30_links(self) -> None:
|
|
# Use a scoped session so create_link and remove_link share state.
|
|
session = self.sf()
|
|
link_repo = ProjectResourceLinkRepository(session_factory=lambda: session)
|
|
link_ids: list[str] = []
|
|
for i in range(30):
|
|
link = link_repo.create_link(
|
|
project_name="bench/link-bench",
|
|
resource_id=str(i).zfill(26),
|
|
)
|
|
session.commit()
|
|
link_ids.append(str(link.link_id))
|
|
link_repo.list_links("bench/link-bench")
|
|
for lid in link_ids:
|
|
link_repo.remove_link(lid)
|
|
session.commit()
|
|
session.close()
|