70 lines
3.5 KiB
Python
70 lines
3.5 KiB
Python
import json
|
|
import os
|
|
from pathlib import Path
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import time
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
import business_acceptance as evidence
|
|
from business_batching import module_batches
|
|
import run_business_acceptance as runner
|
|
|
|
|
|
class BusinessEfficiencyTests(unittest.TestCase):
|
|
def test_modules_share_one_batch_but_distinct_build_targets_do_not(self):
|
|
ids = [f"case-{i:02}" for i in range(24)]
|
|
self.assertEqual(list(module_batches(ids, {})), [ids])
|
|
contract = {"build": {"target": "main"}, "buildOverrides": {ids[0]: {"target": "other"}}}
|
|
batches = list(module_batches(ids, contract))
|
|
self.assertEqual(batches, [[ids[0]], ids[1:]])
|
|
self.assertTrue(all(len(group)<=8 for group in module_batches(ids, contract, 8)))
|
|
|
|
def test_hash_cache_detects_changed_contents_without_manual_clear(self):
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
file = Path(directory) / "artifact"
|
|
file.write_bytes(b"first")
|
|
original_stat = file.stat()
|
|
first = evidence.digest(file)
|
|
hits = evidence.digest.cache_info().hits
|
|
self.assertEqual(evidence.digest(file), first)
|
|
self.assertGreater(evidence.digest.cache_info().hits, hits)
|
|
file.write_bytes(b"other")
|
|
os.utime(file, ns=(original_stat.st_atime_ns, original_stat.st_mtime_ns))
|
|
self.assertNotEqual(evidence.digest(file), first)
|
|
evidence.digest.cache_clear()
|
|
|
|
def test_shared_reuse_report_is_loaded_once_without_revalidating_each_id(self):
|
|
rows = [{"id": f"id-{i}"} for i in range(24)]
|
|
ids = {row["id"] for row in rows}
|
|
entries = {key: {"evidencePath": "proof.json"} for key in ids}
|
|
report = {"command": ["node", "case.mjs"], "caseInputs": {"files": {}},
|
|
"results": [{"capabilityId": key} for key in ids]}
|
|
cache = {}
|
|
with patch.object(runner, "read", return_value=report) as read, \
|
|
patch.object(runner, "accepted_ids", side_effect=AssertionError("already verified IDs must not be checked repeatedly")):
|
|
for row in rows:
|
|
self.assertIsNotNone(runner.reusable_reports([row], report["command"], report["caseInputs"], {}, {},
|
|
entries=entries, reports=cache, verified_ids=ids))
|
|
self.assertEqual(read.call_count, 1)
|
|
|
|
def test_timeout_releases_owned_descendant_and_preserves_diagnostics(self):
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
root = Path(directory)
|
|
# The child would write a marker after the runner has timed out.
|
|
child = "import time; from pathlib import Path; time.sleep(2); Path('orphan').write_text('bad')"
|
|
program = "import subprocess,sys,time; subprocess.Popen([sys.executable,'-c'," + repr(child) + "]); print('native-start',flush=True); print('native-error',file=sys.stderr,flush=True); time.sleep(30)"
|
|
with patch.object(runner, "ROOT", root):
|
|
with self.assertRaises(subprocess.TimeoutExpired) as caught:
|
|
runner.execute_case([sys.executable, "-c", program], dict(os.environ, FREECAD_BUSINESS_TIMEOUT_SECONDS="1"))
|
|
self.assertIn("native-start", caught.exception.output)
|
|
self.assertIn("native-error", caught.exception.stderr)
|
|
time.sleep(1.4)
|
|
self.assertFalse((root / "orphan").exists())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|