c65e8a5285
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 16s
CI / lint (pull_request) Successful in 17s
CI / quality (pull_request) Successful in 29s
CI / typecheck (pull_request) Successful in 59s
CI / security (pull_request) Successful in 59s
CI / unit_tests (pull_request) Successful in 3m9s
CI / integration_tests (pull_request) Successful in 3m34s
CI / e2e_tests (pull_request) Successful in 3m54s
CI / docker (pull_request) Successful in 55s
CI / coverage (pull_request) Successful in 6m1s
CI / build (push) Successful in 15s
CI / lint (push) Successful in 16s
CI / quality (push) Successful in 27s
CI / typecheck (push) Successful in 38s
CI / benchmark-regression (push) Has been skipped
CI / security (push) Successful in 48s
CI / unit_tests (push) Successful in 3m14s
CI / integration_tests (push) Successful in 3m30s
CI / docker (push) Successful in 56s
CI / e2e_tests (push) Successful in 4m43s
CI / coverage (push) Successful in 6m1s
CI / benchmark-publish (push) Successful in 19m50s
CI / benchmark-regression (pull_request) Successful in 37m17s
Implement cloud resource types (aws, gcp, azure) with credential fields, region/tenant metadata, and stubbed sandbox strategies. Credential resolution uses environment variables and profile names with no secrets logged. Key changes: - Add CloudResourceHandler with aws/gcp/azure type definitions - Add credential resolution from env vars and profile names - Add stubbed sandbox strategies (validate config, raise NotImplementedError) - Register cloud types in bootstrap_builtin_types - Credential masking via existing redaction patterns - Add Behave BDD tests, Robot integration tests, ASV benchmarks ISSUES CLOSED: #343
245 lines
6.9 KiB
Python
245 lines
6.9 KiB
Python
"""ASV benchmarks for custom sandbox strategy registration.
|
|
|
|
Measures the performance of:
|
|
- SandboxRef creation
|
|
- DiffView / DiffEntry model creation
|
|
- SandboxStrategyRegistry registration and lookup
|
|
- BuiltInSandboxStrategyAdapter create/write/read cycle
|
|
- Protocol runtime checking via isinstance
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import os
|
|
import sys
|
|
import tempfile
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
# Ensure the local *source* tree is importable even when ASV has an
|
|
# older build of the package installed.
|
|
_SRC = str(Path(__file__).resolve().parents[1] / "src")
|
|
if _SRC not in sys.path:
|
|
sys.path.insert(0, _SRC)
|
|
|
|
# Force-reload so ASV picks up the source tree version.
|
|
import cleveragents # noqa: E402
|
|
|
|
importlib.reload(cleveragents)
|
|
|
|
from cleveragents.domain.models.core.resource import ( # noqa: E402
|
|
PhysVirt,
|
|
Resource,
|
|
ResourceCapabilities,
|
|
)
|
|
from cleveragents.domain.models.core.resource import ( # noqa: E402
|
|
SandboxStrategy as SandboxStrategyEnum,
|
|
)
|
|
from cleveragents.domain.models.core.sandbox_strategy import ( # noqa: E402
|
|
DiffEntry,
|
|
DiffView,
|
|
SandboxRef,
|
|
SandboxStrategyProtocol,
|
|
)
|
|
from cleveragents.infrastructure.sandbox.strategy_adapter import ( # noqa: E402
|
|
BuiltInSandboxStrategyAdapter,
|
|
)
|
|
from cleveragents.infrastructure.sandbox.strategy_registry import ( # noqa: E402
|
|
SandboxStrategyRegistry,
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Helpers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
_COUNTER = 0
|
|
|
|
|
|
def _ulid(name: str) -> str:
|
|
global _COUNTER
|
|
_COUNTER += 1
|
|
base = abs(hash(name)) % (10**20)
|
|
raw = f"{_COUNTER:06d}{base:020d}"
|
|
charset = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
|
|
result = ""
|
|
for ch in raw:
|
|
result += charset[int(ch)]
|
|
return (result + "0" * 26)[:26]
|
|
|
|
|
|
class _MockStrategy:
|
|
"""Minimal strategy satisfying the Protocol for benchmarking."""
|
|
|
|
def create(self, plan_id, resource):
|
|
return None
|
|
|
|
def read(self, ref, path):
|
|
return b""
|
|
|
|
def write(self, ref, path, content):
|
|
return None
|
|
|
|
def diff(self, ref):
|
|
return None
|
|
|
|
def commit(self, ref):
|
|
pass
|
|
|
|
def rollback(self, ref):
|
|
pass
|
|
|
|
def checkpoint(self, ref, checkpoint_id):
|
|
pass
|
|
|
|
def restore_checkpoint(self, ref, checkpoint_id):
|
|
pass
|
|
|
|
def cleanup(self, ref):
|
|
pass
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# SandboxRef benchmarks
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TimeSandboxRef:
|
|
"""Benchmark SandboxRef creation."""
|
|
|
|
def time_create_ref(self) -> None:
|
|
SandboxRef(
|
|
sandbox_id="bench-ref",
|
|
plan_id="bench-plan",
|
|
resource_id="bench-res",
|
|
created_at=datetime.now(),
|
|
)
|
|
|
|
def time_create_ref_with_metadata(self) -> None:
|
|
SandboxRef(
|
|
sandbox_id="bench-ref-meta",
|
|
plan_id="bench-plan",
|
|
resource_id="bench-res",
|
|
created_at=datetime.now(),
|
|
metadata={"key": "value", "num": 42},
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# DiffEntry / DiffView benchmarks
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TimeDiffModels:
|
|
"""Benchmark DiffEntry and DiffView creation."""
|
|
|
|
def time_create_diff_entry(self) -> None:
|
|
DiffEntry(path="bench.txt", operation="modified")
|
|
|
|
def time_create_diff_entry_with_content(self) -> None:
|
|
DiffEntry(
|
|
path="bench.txt",
|
|
operation="modified",
|
|
before=b"old",
|
|
after=b"new",
|
|
)
|
|
|
|
def time_create_diff_view_10_entries(self) -> None:
|
|
entries = [
|
|
DiffEntry(path=f"file{i}.txt", operation="modified") for i in range(10)
|
|
]
|
|
DiffView(sandbox_id="bench-dv", entries=entries)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Protocol checking benchmarks
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TimeProtocolCheck:
|
|
"""Benchmark SandboxStrategyProtocol isinstance checks."""
|
|
|
|
def setup(self) -> None:
|
|
self.good = _MockStrategy()
|
|
|
|
def time_isinstance_check_pass(self) -> None:
|
|
isinstance(self.good, SandboxStrategyProtocol)
|
|
|
|
def time_isinstance_check_fail(self) -> None:
|
|
isinstance("not a strategy", SandboxStrategyProtocol)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# SandboxStrategyRegistry benchmarks
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TimeStrategyRegistry:
|
|
"""Benchmark registry operations."""
|
|
|
|
def setup(self) -> None:
|
|
self.registry = SandboxStrategyRegistry(
|
|
allowed_prefixes=("cleveragents.",),
|
|
)
|
|
self.registry.register(
|
|
"bench_adapter",
|
|
"cleveragents.infrastructure.sandbox.strategy_adapter",
|
|
"BuiltInSandboxStrategyAdapter",
|
|
)
|
|
|
|
def time_lookup_hit(self) -> None:
|
|
self.registry.get("bench_adapter")
|
|
|
|
def time_lookup_miss(self) -> None:
|
|
self.registry.get("nonexistent")
|
|
|
|
def time_has_check(self) -> None:
|
|
self.registry.has("bench_adapter")
|
|
|
|
def time_list_strategies(self) -> None:
|
|
self.registry.list_strategies()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# BuiltInSandboxStrategyAdapter benchmarks
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TimeAdapterLifecycle:
|
|
"""Benchmark adapter create/write/read cycle."""
|
|
|
|
def setup(self) -> None:
|
|
self.tmpdir = tempfile.mkdtemp(prefix="ca-bench-adapter-")
|
|
with open(os.path.join(self.tmpdir, "seed.txt"), "w") as f:
|
|
f.write("seed")
|
|
self.adapter = BuiltInSandboxStrategyAdapter(strategy_name="copy_on_write")
|
|
self.resource = Resource(
|
|
resource_id=_ulid("bench-adapter"),
|
|
name="bench-adapter",
|
|
resource_type_name="fs-directory",
|
|
classification=PhysVirt.PHYSICAL,
|
|
sandbox_strategy=SandboxStrategyEnum.COPY_ON_WRITE,
|
|
location=self.tmpdir,
|
|
capabilities=ResourceCapabilities(
|
|
readable=True,
|
|
writable=True,
|
|
sandboxable=True,
|
|
checkpointable=False,
|
|
),
|
|
)
|
|
|
|
def time_create_and_cleanup(self) -> None:
|
|
ref = self.adapter.create("bench-plan", self.resource)
|
|
self.adapter.cleanup(ref)
|
|
|
|
def time_write_read_cycle(self) -> None:
|
|
ref = self.adapter.create("bench-plan-wr", self.resource)
|
|
self.adapter.write(ref, "bench.txt", b"bench content")
|
|
self.adapter.read(ref, "bench.txt")
|
|
self.adapter.cleanup(ref)
|
|
|
|
def teardown(self) -> None:
|
|
import shutil
|
|
|
|
shutil.rmtree(self.tmpdir, ignore_errors=True)
|