| 1 | """Lane-contract conformance: every lane, five checks, positive and negative.
|
| 2 |
|
| 3 | Parameterized (subTest) over lane_contract.LANE_TABLE. For each lane the
|
| 4 | valid synthetic rows (mirroring the lane's real emitters) must pass all five
|
| 5 | checks, and a crafted violation must fail each check that applies — negative
|
| 6 | tests prove the checks have teeth. The meta-test guarantees a new lane cannot
|
| 7 | ship without a LANE_TABLE entry.
|
| 8 | """
|
| 9 |
|
| 10 | from __future__ import annotations
|
| 11 |
|
| 12 | import copy
|
| 13 | import sys
|
| 14 | from pathlib import Path
|
| 15 |
|
| 16 | sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
|
| 17 |
|
| 18 | import unittest
|
| 19 |
|
| 20 | from oakbench import lane_contract, remotes, rows as oakbench_rows
|
| 21 | from oakbench.lane_contract import (
|
| 22 | DE_FACTO_LANES,
|
| 23 | LANE_TABLE,
|
| 24 | catalog_operations,
|
| 25 | check_catalog_membership,
|
| 26 | check_measurement_source,
|
| 27 | check_row_contract,
|
| 28 | check_skip_coherence,
|
| 29 | check_transport_purity,
|
| 30 | expected_lanes,
|
| 31 | )
|
| 32 |
|
| 33 |
|
| 34 | def sample_rows(lane: str) -> list[dict]:
|
| 35 | """Fresh deep copy so one subTest's mutation never leaks into another."""
|
| 36 | return copy.deepcopy(LANE_TABLE[lane].sample_rows_builder())
|
| 37 |
|
| 38 |
|
| 39 | def catalog_errors(contract: lane_contract.LaneContract, rows: list[dict]) -> list[str]:
|
| 40 | catalog = catalog_operations(contract.catalog_path) if contract.catalog_path else None
|
| 41 | return check_catalog_membership(
|
| 42 | rows,
|
| 43 | catalog,
|
| 44 | exempt_ops=contract.catalog_exempt_ops,
|
| 45 | exempt_prefixes=contract.catalog_exempt_prefixes,
|
| 46 | exempt_suffixes=contract.catalog_exempt_suffixes,
|
| 47 | )
|
| 48 |
|
| 49 |
|
| 50 | class LaneTableMetaTest(unittest.TestCase):
|
| 51 | """Adding a lane without a contract entry fails CI with a clear message."""
|
| 52 |
|
| 53 | def test_every_lane_has_a_contract_entry(self) -> None:
|
| 54 | missing = sorted(expected_lanes() - set(LANE_TABLE))
|
| 55 | self.assertEqual(
|
| 56 | missing,
|
| 57 | [],
|
| 58 | "New lane(s) without a LANE_TABLE entry in scripts/oakbench/lane_contract.py: "
|
| 59 | f"{missing}. Add one LaneContract per lane (see docs/new-lane-template.md) "
|
| 60 | "so row contracts, skip coherence, transport purity, measurement_source, "
|
| 61 | "and catalog membership stay machine-checked.",
|
| 62 | )
|
| 63 |
|
| 64 | def test_no_orphan_contract_entries(self) -> None:
|
| 65 | orphans = sorted(set(LANE_TABLE) - expected_lanes())
|
| 66 | self.assertEqual(
|
| 67 | orphans,
|
| 68 | [],
|
| 69 | f"LANE_TABLE entries for unknown lanes: {orphans}. Either add the lane to "
|
| 70 | "rows.LANES, list it in lane_contract.DE_FACTO_LANES, or delete the entry.",
|
| 71 | )
|
| 72 |
|
| 73 | def test_rows_lanes_all_validatable(self) -> None:
|
| 74 | # Every rows.py lane delegates to validate_rows under its own key.
|
| 75 | for lane in oakbench_rows.LANES:
|
| 76 | with self.subTest(lane=lane):
|
| 77 | self.assertEqual(LANE_TABLE[lane].validate_lane, lane)
|
| 78 |
|
| 79 | def test_de_facto_lanes_documented(self) -> None:
|
| 80 | self.assertEqual(set(DE_FACTO_LANES), {"netshape", "external", "agent_loop_hosted"})
|
| 81 | # netshape opts into the core key contract (netshape_bench.write_rows).
|
| 82 | self.assertEqual(LANE_TABLE["netshape"].validate_lane, "core")
|
| 83 | # external (tperf) rows are not bench rows; universal keys only.
|
| 84 | self.assertIsNone(LANE_TABLE["external"].validate_lane)
|
| 85 | self.assertTrue(LANE_TABLE["external"].universal_keys)
|
| 86 | # agent_loop_hosted rows are per-step hosted-loop rows; universal keys only.
|
| 87 | self.assertIsNone(LANE_TABLE["agent_loop_hosted"].validate_lane)
|
| 88 | self.assertIn("measurement_source", LANE_TABLE["agent_loop_hosted"].universal_keys)
|
| 89 |
|
| 90 |
|
| 91 | class ValidRowsPassAllChecksTest(unittest.TestCase):
|
| 92 | def test_all_lanes(self) -> None:
|
| 93 | for lane, contract in LANE_TABLE.items():
|
| 94 | rows = sample_rows(lane)
|
| 95 | with self.subTest(lane=lane, check="row_contract"):
|
| 96 | self.assertEqual(check_row_contract(rows, contract), [])
|
| 97 | with self.subTest(lane=lane, check="skip_coherence"):
|
| 98 | self.assertEqual(check_skip_coherence(rows), [])
|
| 99 | with self.subTest(lane=lane, check="transport_purity"):
|
| 100 | self.assertEqual(check_transport_purity(rows), [])
|
| 101 | with self.subTest(lane=lane, check="measurement_source"):
|
| 102 | self.assertEqual(
|
| 103 | check_measurement_source(
|
| 104 | rows, contract.allowed_sources, required=contract.source_required
|
| 105 | ),
|
| 106 | [],
|
| 107 | )
|
| 108 | with self.subTest(lane=lane, check="catalog_membership"):
|
| 109 | self.assertEqual(catalog_errors(contract, rows), [])
|
| 110 |
|
| 111 |
|
| 112 | class RowContractNegativeTest(unittest.TestCase):
|
| 113 | def test_missing_required_key_fails(self) -> None:
|
| 114 | for lane, contract in LANE_TABLE.items():
|
| 115 | with self.subTest(lane=lane):
|
| 116 | rows = sample_rows(lane)
|
| 117 | if contract.validate_lane is not None:
|
| 118 | victim = oakbench_rows.LANE_REQUIRED_KEYS[contract.validate_lane][0]
|
| 119 | else:
|
| 120 | victim = contract.universal_keys[0]
|
| 121 | del rows[0][victim]
|
| 122 | errors = check_row_contract(rows, contract)
|
| 123 | self.assertTrue(errors, f"deleting {victim!r} must fail the row contract")
|
| 124 | self.assertIn(victim, "\n".join(errors))
|
| 125 |
|
| 126 | def test_non_numeric_elapsed_fails(self) -> None:
|
| 127 | for lane, contract in LANE_TABLE.items():
|
| 128 | with self.subTest(lane=lane):
|
| 129 | rows = sample_rows(lane)
|
| 130 | rows[0]["elapsed_ms"] = "fast"
|
| 131 | self.assertTrue(check_row_contract(rows, contract))
|
| 132 |
|
| 133 |
|
| 134 | class SkipCoherenceNegativeTest(unittest.TestCase):
|
| 135 | def test_77_without_reason_fails(self) -> None:
|
| 136 | for lane in LANE_TABLE:
|
| 137 | with self.subTest(lane=lane):
|
| 138 | rows = sample_rows(lane)
|
| 139 | bad = copy.deepcopy(rows[0])
|
| 140 | bad["returncode"] = oakbench_rows.SKIP_RETURNCODE
|
| 141 | bad.pop("skipped", None)
|
| 142 | bad.pop("skip_reason", None)
|
| 143 | errors = check_skip_coherence(rows + [bad])
|
| 144 | self.assertTrue(any("skipped: true" in e for e in errors))
|
| 145 | self.assertTrue(any("skip_reason" in e for e in errors))
|
| 146 |
|
| 147 | def test_skipped_without_77_fails(self) -> None:
|
| 148 | for lane in LANE_TABLE:
|
| 149 | with self.subTest(lane=lane):
|
| 150 | rows = sample_rows(lane)
|
| 151 | bad = copy.deepcopy(rows[0])
|
| 152 | bad["returncode"] = 0
|
| 153 | bad["skipped"] = True
|
| 154 | bad["skip_reason"] = "half-marked skip"
|
| 155 | errors = check_skip_coherence(rows + [bad])
|
| 156 | self.assertTrue(any("requires returncode 77" in e for e in errors))
|
| 157 |
|
| 158 |
|
| 159 | class TransportPurityNegativeTest(unittest.TestCase):
|
| 160 | def test_mixed_transports_same_subject_scenario_operation_fail(self) -> None:
|
| 161 | for lane in LANE_TABLE:
|
| 162 | with self.subTest(lane=lane):
|
| 163 | rows = sample_rows(lane)
|
| 164 | a = copy.deepcopy(rows[0])
|
| 165 | b = copy.deepcopy(rows[0])
|
| 166 | a.update(
|
| 167 | remote_repo="x",
|
| 168 | remote_transport=remotes.TRANSPORT_NETWORK,
|
| 169 | remote_server="oak.space",
|
| 170 | )
|
| 171 | a.pop("netshape_profile", None)
|
| 172 | b.update(
|
| 173 | remote_repo="y",
|
| 174 | remote_transport=remotes.TRANSPORT_LOCAL_FILE,
|
| 175 | remote_server="local",
|
| 176 | )
|
| 177 | b.pop("netshape_profile", None)
|
| 178 | errors = check_transport_purity(rows + [a, b])
|
| 179 | self.assertTrue(any("transport mixing" in e for e in errors))
|
| 180 |
|
| 181 | def test_same_operation_different_subjects_is_legal(self) -> None:
|
| 182 | # Side-by-side files may hold one operation at different transports
|
| 183 | # for different subjects (publish_gate precedent).
|
| 184 | rows = sample_rows("core")
|
| 185 | a = {**copy.deepcopy(rows[0]), "subject": "git", "remote_repo": "x",
|
| 186 | "remote_transport": remotes.TRANSPORT_LOCAL_FILE, "remote_server": "local"}
|
| 187 | b = {**copy.deepcopy(rows[0]), "subject": "oak", "remote_repo": "y",
|
| 188 | "remote_transport": remotes.TRANSPORT_NETWORK, "remote_server": "oak.space"}
|
| 189 | self.assertEqual(check_transport_purity(rows + [a, b]), [])
|
| 190 |
|
| 191 | def test_remote_row_without_transport_fails(self) -> None:
|
| 192 | rows = sample_rows("core")
|
| 193 | bad = copy.deepcopy(rows[0])
|
| 194 | bad["remote_repo"] = "oak/bench-tmp"
|
| 195 | bad.pop("remote_transport", None)
|
| 196 | errors = check_transport_purity(rows + [bad])
|
| 197 | self.assertTrue(any("without remote_transport" in e for e in errors))
|
| 198 |
|
| 199 | def test_unknown_transport_fails(self) -> None:
|
| 200 | rows = sample_rows("core")
|
| 201 | bad = copy.deepcopy(rows[0])
|
| 202 | bad.update(remote_repo="x", remote_transport="carrier_pigeon", remote_server="loft")
|
| 203 | errors = check_transport_purity(rows + [bad])
|
| 204 | self.assertTrue(any("unknown transport" in e for e in errors))
|
| 205 |
|
| 206 | def test_shaped_row_without_profile_fails(self) -> None:
|
| 207 | rows = sample_rows("netshape")
|
| 208 | bad = copy.deepcopy(rows[0])
|
| 209 | bad["netshape_profile"] = ""
|
| 210 | errors = check_transport_purity([bad])
|
| 211 | self.assertTrue(any("netshape_profile" in e for e in errors))
|
| 212 |
|
| 213 |
|
| 214 | class MeasurementSourceNegativeTest(unittest.TestCase):
|
| 215 | def test_off_list_source_fails_or_lane_is_exempt(self) -> None:
|
| 216 | for lane, contract in LANE_TABLE.items():
|
| 217 | with self.subTest(lane=lane):
|
| 218 | rows = sample_rows(lane)
|
| 219 | rows[0]["measurement_source"] = "made_up_source"
|
| 220 | errors = check_measurement_source(
|
| 221 | rows, contract.allowed_sources, required=contract.source_required
|
| 222 | )
|
| 223 | if contract.allowed_sources is None:
|
| 224 | # Encoded reality: agent/contention nest their sources in
|
| 225 | # metric blocks; mount/netshape carry none. The top-level
|
| 226 | # check is exempt for them, by the table, not by accident.
|
| 227 | self.assertEqual(errors, [])
|
| 228 | else:
|
| 229 | self.assertTrue(any("made_up_source" in e for e in errors))
|
| 230 |
|
| 231 | def test_required_source_missing_fails(self) -> None:
|
| 232 | contract = LANE_TABLE["external"]
|
| 233 | rows = sample_rows("external")
|
| 234 | del rows[0]["measurement_source"]
|
| 235 | errors = check_measurement_source(rows, contract.allowed_sources, required=True)
|
| 236 | self.assertTrue(any("missing required measurement_source" in e for e in errors))
|
| 237 |
|
| 238 |
|
| 239 | class CatalogMembershipNegativeTest(unittest.TestCase):
|
| 240 | def test_off_catalog_operation_fails_or_lane_is_exempt(self) -> None:
|
| 241 | for lane, contract in LANE_TABLE.items():
|
| 242 | with self.subTest(lane=lane):
|
| 243 | rows = sample_rows(lane)
|
| 244 | bad = copy.deepcopy(rows[0])
|
| 245 | bad["operation"] = "made.up.operation"
|
| 246 | errors = catalog_errors(contract, rows + [bad])
|
| 247 | if contract.catalog_path is None:
|
| 248 | # Encoded reality: workflow/contention/agent/task-loop/
|
| 249 | # netshape/external declare no operation catalog today.
|
| 250 | self.assertEqual(errors, [])
|
| 251 | else:
|
| 252 | self.assertTrue(any("made.up.operation" in e for e in errors))
|
| 253 |
|
| 254 | def test_catalogs_parse_and_are_nonempty(self) -> None:
|
| 255 | for lane, contract in LANE_TABLE.items():
|
| 256 | if contract.catalog_path is None:
|
| 257 | continue
|
| 258 | with self.subTest(lane=lane):
|
| 259 | ops = catalog_operations(contract.catalog_path)
|
| 260 | self.assertTrue(ops, f"{contract.catalog_path} parsed to an empty catalog")
|
| 261 | self.assertTrue(all("." in op or op.isidentifier() for op in ops), ops)
|
| 262 |
|
| 263 | def test_core_catalog_contains_known_operations(self) -> None:
|
| 264 | ops = catalog_operations(LANE_TABLE["core"].catalog_path)
|
| 265 | for op in ("repo.init", "status.clean", "merge.conflict"):
|
| 266 | self.assertIn(op, ops)
|
| 267 |
|
| 268 | def test_exemptions_are_documented_reality_not_wildcards(self) -> None:
|
| 269 | # The core exemption families mirror bench.py's own diagnostic-row
|
| 270 | # exclusions (average_by_subject); keep them in sync deliberately.
|
| 271 | core = LANE_TABLE["core"]
|
| 272 | self.assertIn("proc.spawn", core.catalog_exempt_ops)
|
| 273 | self.assertIn("remote.", core.catalog_exempt_prefixes)
|
| 274 | mount = LANE_TABLE["mount"]
|
| 275 | self.assertIn("acquire.", mount.catalog_exempt_prefixes)
|
| 276 |
|
| 277 |
|
| 278 | class SampleRowsMirrorRealEmittersTest(unittest.TestCase):
|
| 279 | """Spot-check the synthetic rows against the real emitters' fixed points
|
| 280 | so the table cannot drift into testing an imaginary suite."""
|
| 281 |
|
| 282 | def test_core_sample_passes_rows_py_directly(self) -> None:
|
| 283 | self.assertEqual(oakbench_rows.validate_rows(sample_rows("core"), "core"), [])
|
| 284 |
|
| 285 | def test_netshape_sample_carries_shaped_pipe_identity(self) -> None:
|
| 286 | for row in sample_rows("netshape"):
|
| 287 | self.assertEqual(row["remote_transport"], remotes.TRANSPORT_NETWORK_SHAPED)
|
| 288 | self.assertTrue(row["netshape_profile"])
|
| 289 | self.assertTrue(row["remote_server"])
|
| 290 |
|
| 291 | def test_netshape_shaped_rows_compare_legally_same_pipe_only(self) -> None:
|
| 292 | rows = sample_rows("netshape")
|
| 293 | self.assertTrue(remotes.shaped_comparison_legal(rows[0], rows[1]))
|
| 294 | other_pipe = {**rows[1], "netshape_profile": "wan-80ms"}
|
| 295 | self.assertFalse(remotes.shaped_comparison_legal(rows[0], other_pipe))
|
| 296 |
|
| 297 | def test_external_sample_matches_tperf_runner_source_label(self) -> None:
|
| 298 | import tperf_runner
|
| 299 |
|
| 300 | self.assertEqual(
|
| 301 | LANE_TABLE["external"].allowed_sources,
|
| 302 | frozenset({tperf_runner.MEASUREMENT_SOURCE}),
|
| 303 | )
|
| 304 | for row in sample_rows("external"):
|
| 305 | self.assertEqual(row["measurement_source"], tperf_runner.MEASUREMENT_SOURCE)
|
| 306 |
|
| 307 | def test_skip_rows_present_in_lanes_that_emit_them(self) -> None:
|
| 308 | for lane in ("core", "workflow", "mount", "platform", "netshape"):
|
| 309 | with self.subTest(lane=lane):
|
| 310 | skips = [r for r in sample_rows(lane) if r.get("skipped")]
|
| 311 | self.assertTrue(skips, f"{lane} sample must include a skip row")
|
| 312 | for row in skips:
|
| 313 | self.assertEqual(row["returncode"], oakbench_rows.SKIP_RETURNCODE)
|
| 314 | self.assertTrue(str(row["skip_reason"]).strip())
|
| 315 |
|
| 316 |
|
| 317 | if __name__ == "__main__":
|
| 318 | unittest.main()
|