Files
crank/tests/unit/test_check_metrics_boundaries.py
T

117 lines
5.5 KiB
Python

import subprocess
import tempfile
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
CHECKER = ROOT / "scripts" / "check-metrics-boundaries.py"
class MetricsBoundaryTests(unittest.TestCase):
def run_checker(self, root: Path, *paths: str) -> subprocess.CompletedProcess[str]:
return subprocess.run(
["python3", str(CHECKER), "--root", str(root), "--files", *paths],
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=False,
)
def test_rejects_direct_alias_import_reexport_and_wrapper_bypasses(self) -> None:
cases = {
"direct.rs": 'metrics::counter!("bad").increment(1);',
"alias.rs": 'use metrics as m; m::counter!("bad").increment(1);',
"import.rs": 'use metrics::counter; counter!("bad").increment(1);',
"reexport.rs": 'pub use metrics::histogram;',
"absolute.rs": '::metrics::gauge!("bad").set(1.0);',
"wrapper.rs": 'macro_rules! bad { () => { metrics::counter!("bad") } }',
}
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
paths = []
for name, content in cases.items():
path = root / "apps" / "demo" / "src" / name
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(content, encoding="utf-8")
paths.append(str(path.relative_to(root)))
result = self.run_checker(root, *paths)
self.assertNotEqual(result.returncode, 0)
for name in cases:
self.assertIn(name, result.stderr)
self.assertNotIn(str(root), result.stderr)
def test_allows_typed_facade_and_narrow_observability_adapter(self) -> None:
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
product = root / "apps" / "demo" / "src" / "main.rs"
adapter = root / "crates" / "crank-observability" / "src" / "instrumentation.rs"
product.parent.mkdir(parents=True)
adapter.parent.mkdir(parents=True)
product.write_text("crank_metrics::record_cache_outcome(value);", encoding="utf-8")
adapter.write_text("metrics::describe_counter!(definition.name, definition.description);", encoding="utf-8")
result = self.run_checker(root, str(product.relative_to(root)), str(adapter.relative_to(root)))
self.assertEqual(result.returncode, 0, result.stderr)
def test_adapter_allowance_does_not_hide_later_declaration(self) -> None:
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
path = root / "crates/crank-observability/src/instrumentation.rs"
path.parent.mkdir(parents=True)
path.write_text(
'metrics::describe_counter!("ok", "ok");\nmetrics::counter!("bad").increment(1);',
encoding="utf-8",
)
result = self.run_checker(root, str(path.relative_to(root)))
self.assertNotEqual(result.returncode, 0)
def test_ignores_comments_and_strings_but_not_src_tests_directory(self) -> None:
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
harmless = root / "apps/demo/src/harmless.rs"
production = root / "apps/demo/src/tests/production.rs"
harmless.parent.mkdir(parents=True)
production.parent.mkdir(parents=True)
harmless.write_text(
'// metrics::counter!("comment")\nconst TEXT: &str = r#"metrics::gauge!(\"string\")"#;',
encoding="utf-8",
)
production.write_text('metrics::counter!("bad");', encoding="utf-8")
allowed = self.run_checker(root, str(harmless.relative_to(root)))
rejected = self.run_checker(root, str(production.relative_to(root)))
self.assertEqual(allowed.returncode, 0, allowed.stderr)
self.assertNotEqual(rejected.returncode, 0)
def test_rejects_raw_recorder_api_and_empty_explicit_handoff(self) -> None:
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
path = root / "apps/demo/src/raw.rs"
path.parent.mkdir(parents=True)
path.write_text("Recorder::register_counter(key, metadata);", encoding="utf-8")
self.assertNotEqual(
self.run_checker(root, str(path.relative_to(root))).returncode, 0
)
self.assertNotEqual(self.run_checker(root).returncode, 0)
def test_explicit_missing_traversal_and_symlink_fail_closed(self) -> None:
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
outside = root.parent / "metrics-boundary-outside.rs"
outside.write_text('metrics::counter!("bad");', encoding="utf-8")
try:
for path in ["missing.rs", "../metrics-boundary-outside.rs"]:
result = self.run_checker(root, path)
self.assertNotEqual(result.returncode, 0)
target = root / "target.rs"
target.write_text("", encoding="utf-8")
link = root / "link.rs"
link.symlink_to(target)
result = self.run_checker(root, "link.rs")
self.assertNotEqual(result.returncode, 0)
finally:
outside.unlink(missing_ok=True)
if __name__ == "__main__":
unittest.main()