assertions.py 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. """Post-session deterministic assertions for drill scenarios."""
  2. from __future__ import annotations
  3. import os
  4. import subprocess
  5. from dataclasses import dataclass
  6. from pathlib import Path
  7. from drill.verifier import CriterionResult
  8. @dataclass
  9. class AssertionResult:
  10. command: str
  11. passed: bool
  12. exit_code: int
  13. stdout: str
  14. stderr: str
  15. def to_criterion_result(self) -> CriterionResult:
  16. evidence = f"exit code {self.exit_code}"
  17. if self.stdout:
  18. evidence += f"\nstdout: {self.stdout}"
  19. if self.stderr:
  20. evidence += f"\nstderr: {self.stderr}"
  21. return CriterionResult(
  22. criterion=f"[assertion] {self.command}",
  23. verdict="pass" if self.passed else "fail",
  24. evidence=evidence,
  25. rationale="Deterministic assertion " + ("passed" if self.passed else "failed"),
  26. source="assertion",
  27. )
  28. def run_verify_assertions(
  29. assertions: list[str],
  30. results_dir: Path,
  31. workdir: Path,
  32. *,
  33. timeout_seconds: int = 10,
  34. ) -> list[AssertionResult]:
  35. bin_dir = Path(__file__).parent.parent / "bin"
  36. env = {
  37. **os.environ,
  38. "DRILL_WORKDIR": str(workdir),
  39. "PATH": f"{bin_dir}:{os.environ.get('PATH', '')}",
  40. }
  41. results: list[AssertionResult] = []
  42. for cmd in assertions:
  43. try:
  44. proc = subprocess.run(
  45. ["bash", "-c", cmd],
  46. cwd=results_dir,
  47. capture_output=True,
  48. text=True,
  49. env=env,
  50. timeout=timeout_seconds,
  51. )
  52. results.append(
  53. AssertionResult(
  54. command=cmd,
  55. passed=proc.returncode == 0,
  56. exit_code=proc.returncode,
  57. stdout=proc.stdout.strip(),
  58. stderr=proc.stderr.strip(),
  59. )
  60. )
  61. except subprocess.TimeoutExpired:
  62. results.append(
  63. AssertionResult(
  64. command=cmd,
  65. passed=False,
  66. exit_code=124,
  67. stdout="",
  68. stderr=f"Timed out after {timeout_seconds}s",
  69. )
  70. )
  71. except Exception as e:
  72. results.append(
  73. AssertionResult(
  74. command=cmd,
  75. passed=False,
  76. exit_code=-1,
  77. stdout="",
  78. stderr=str(e),
  79. )
  80. )
  81. return results