583e6b7ea2
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 14s
CI / build (pull_request) Successful in 16s
CI / quality (pull_request) Successful in 17s
CI / security (pull_request) Successful in 36s
CI / typecheck (pull_request) Successful in 54s
CI / unit_tests (pull_request) Successful in 2m39s
CI / integration_tests (pull_request) Successful in 3m10s
CI / docker (pull_request) Successful in 40s
CI / coverage (pull_request) Successful in 5m0s
CI / lint (push) Successful in 14s
CI / build (push) Successful in 15s
CI / quality (push) Successful in 16s
CI / security (push) Successful in 34s
CI / typecheck (push) Successful in 35s
CI / benchmark-regression (push) Has been skipped
CI / unit_tests (push) Successful in 2m23s
CI / docker (push) Successful in 38s
CI / integration_tests (push) Successful in 3m8s
CI / coverage (push) Successful in 5m10s
CI / benchmark-publish (push) Successful in 16m26s
CI / benchmark-regression (pull_request) Successful in 30m12s
Implement spec-mandated Layer 4 Predictive Error Prevention system: - ErrorPattern domain model with pattern text, historical failures, preventive checks, frequency tracking, and keyword-based matching. - ErrorPatternRepository with in-memory CRUD + context-matching query. - ErrorPatternService with record_failure(), match_patterns(), and get_statistics() methods. - Wire into plan execution via plan_lifecycle_service pre-execution hook. - Add error pattern statistics to CLI diagnostics output. Behave BDD: 11 scenarios covering recording, matching, formatting, stats. Robot Framework: 3 integration smoke tests. ASV benchmarks: pattern matching performance. ISSUES CLOSED: #571
234 lines
5.9 KiB
Python
234 lines
5.9 KiB
Python
"""ASV benchmarks for the semantic validation service.
|
|
|
|
Measures the performance of:
|
|
- Individual rule checks (syntax, import, reference, cycle, misuse, symbol)
|
|
- Rule registry operations (register, lookup, list)
|
|
- Validation cache operations (put, get, compute_hash)
|
|
- Service orchestration (check_file, as_pipeline_results)
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
_SRC = str(Path(__file__).resolve().parents[1] / "src")
|
|
if _SRC not in sys.path:
|
|
sys.path.insert(0, _SRC)
|
|
|
|
from cleveragents.application.services.semantic_validation_rules import ( # noqa: E402
|
|
APIMisuseRule,
|
|
BrokenReferenceRule,
|
|
DuplicateImportRule,
|
|
MissingImportRule,
|
|
MissingSymbolRule,
|
|
SemanticCheckResult,
|
|
SemanticValidationSeverity,
|
|
SyntaxCheckRule,
|
|
)
|
|
from cleveragents.application.services.semantic_validation_service import ( # noqa: E402
|
|
SemanticValidationCache,
|
|
SemanticValidationService,
|
|
create_default_registry,
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Fixtures
|
|
# ---------------------------------------------------------------------------
|
|
|
|
VALID_PYTHON = """\
|
|
import os
|
|
import sys
|
|
import json
|
|
|
|
x = 10
|
|
|
|
def hello():
|
|
return x
|
|
|
|
class Greeter:
|
|
def greet(self):
|
|
return hello()
|
|
|
|
def compute():
|
|
return x + 1
|
|
"""
|
|
|
|
LARGE_PYTHON = VALID_PYTHON * 50 # ~800 lines
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Rule benchmark suites
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class SyntaxCheckRuleSuite:
|
|
"""Benchmarks for SyntaxCheckRule."""
|
|
|
|
timeout = 60
|
|
|
|
def setup(self) -> None:
|
|
self.rule = SyntaxCheckRule()
|
|
self.source = VALID_PYTHON
|
|
self.large = LARGE_PYTHON
|
|
|
|
def time_syntax_check_small(self) -> None:
|
|
self.rule.check(self.source, "test.py")
|
|
|
|
def time_syntax_check_large(self) -> None:
|
|
self.rule.check(self.large, "test.py")
|
|
|
|
|
|
class MissingImportRuleSuite:
|
|
"""Benchmarks for MissingImportRule."""
|
|
|
|
timeout = 60
|
|
|
|
def setup(self) -> None:
|
|
self.rule = MissingImportRule()
|
|
self.source = VALID_PYTHON
|
|
|
|
def time_import_check(self) -> None:
|
|
self.rule.check(self.source, "test.py")
|
|
|
|
|
|
class BrokenReferenceRuleSuite:
|
|
"""Benchmarks for BrokenReferenceRule."""
|
|
|
|
timeout = 60
|
|
|
|
def setup(self) -> None:
|
|
self.rule = BrokenReferenceRule()
|
|
self.source = VALID_PYTHON
|
|
|
|
def time_reference_check(self) -> None:
|
|
self.rule.check(self.source, "test.py")
|
|
|
|
|
|
class APIMisuseRuleSuite:
|
|
"""Benchmarks for APIMisuseRule."""
|
|
|
|
timeout = 60
|
|
|
|
def setup(self) -> None:
|
|
self.rule = APIMisuseRule()
|
|
self.source = VALID_PYTHON
|
|
|
|
def time_api_misuse_check(self) -> None:
|
|
self.rule.check(self.source, "test.py")
|
|
|
|
|
|
class DuplicateImportRuleSuite:
|
|
"""Benchmarks for DuplicateImportRule."""
|
|
|
|
timeout = 60
|
|
|
|
def setup(self) -> None:
|
|
self.rule = DuplicateImportRule()
|
|
self.source = VALID_PYTHON
|
|
|
|
def time_duplicate_import_check(self) -> None:
|
|
self.rule.check(self.source, "test.py")
|
|
|
|
|
|
class MissingSymbolRuleSuite:
|
|
"""Benchmarks for MissingSymbolRule."""
|
|
|
|
timeout = 60
|
|
|
|
def setup(self) -> None:
|
|
self.rule = MissingSymbolRule()
|
|
self.source = VALID_PYTHON
|
|
|
|
def time_symbol_check(self) -> None:
|
|
self.rule.check(self.source, "test.py")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Registry benchmarks
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class RegistrySuite:
|
|
"""Benchmarks for SemanticRuleRegistry."""
|
|
|
|
timeout = 60
|
|
|
|
def setup(self) -> None:
|
|
self.registry = create_default_registry()
|
|
|
|
def time_list_rules(self) -> None:
|
|
self.registry.list_rules()
|
|
|
|
def time_lookup_rule(self) -> None:
|
|
self.registry.get("syntax_error")
|
|
|
|
def time_all_rules(self) -> None:
|
|
self.registry.all_rules()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Cache benchmarks
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class CacheSuite:
|
|
"""Benchmarks for SemanticValidationCache."""
|
|
|
|
timeout = 60
|
|
|
|
def setup(self) -> None:
|
|
self.cache = SemanticValidationCache()
|
|
self.result = SemanticCheckResult(
|
|
passed=True,
|
|
message="ok",
|
|
severity=SemanticValidationSeverity.INFO,
|
|
)
|
|
self.cache.put("rule", "hash1", self.result)
|
|
|
|
def time_compute_hash(self) -> None:
|
|
SemanticValidationCache.compute_hash(VALID_PYTHON)
|
|
|
|
def time_cache_get_hit(self) -> None:
|
|
self.cache.get("rule", "hash1")
|
|
|
|
def time_cache_get_miss(self) -> None:
|
|
self.cache.get("rule", "missing")
|
|
|
|
def time_cache_put(self) -> None:
|
|
self.cache.put("rule", "hash2", self.result)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Service benchmarks
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class ServiceSuite:
|
|
"""Benchmarks for SemanticValidationService orchestration."""
|
|
|
|
timeout = 120
|
|
|
|
def setup(self) -> None:
|
|
self.service = SemanticValidationService()
|
|
self.source = VALID_PYTHON
|
|
self.large = LARGE_PYTHON
|
|
|
|
def time_check_file_small(self) -> None:
|
|
# Clear cache to measure full check cost
|
|
self.service.cache.clear()
|
|
self.service.check_file(self.source, "test.py")
|
|
|
|
def time_check_file_large(self) -> None:
|
|
self.service.cache.clear()
|
|
self.service.check_file(self.large, "test.py")
|
|
|
|
def time_check_file_cached(self) -> None:
|
|
# First call populates cache, second uses it
|
|
self.service.check_file(self.source, "test.py")
|
|
self.service.check_file(self.source, "test.py")
|
|
|
|
def time_pipeline_results(self) -> None:
|
|
self.service.cache.clear()
|
|
self.service.as_pipeline_results(self.source, "test.py")
|