update
This commit is contained in:
Executable
+198
@@ -0,0 +1,198 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
: "${PRE15_DUT:?PRE15_DUT is required}"
|
||||
: "${PRE15_ROOT:?PRE15_ROOT is required}"
|
||||
: "${PRE15_RUN_DIR:?PRE15_RUN_DIR is required}"
|
||||
: "${PRE15_LIB_DIR:?PRE15_LIB_DIR is required}"
|
||||
. "$PRE15_LIB_DIR/runner.sh"
|
||||
|
||||
gate=$PRE15_DUT/tests/pre15/gates/P15-005.sh
|
||||
tuple_oracle=$PRE15_DUT/tests/pre15/fixtures/B06-tuples.json
|
||||
ownership_oracle=$PRE15_DUT/tests/pre15/fixtures/B06-ownership.json
|
||||
artifacts=$PRE15_RUN_DIR/artifacts
|
||||
|
||||
for tool in cc python3 sha256sum; do
|
||||
command -v "$tool" >/dev/null 2>&1 || \
|
||||
pre15_infra_blocked "missing B06 host tool: $tool"
|
||||
done
|
||||
|
||||
pre15_record_fixture b06-gate "$gate"
|
||||
pre15_record_fixture b06-tuple-oracle "$tuple_oracle"
|
||||
pre15_record_fixture b06-ownership-oracle "$ownership_oracle"
|
||||
for source in internal.h data.c decompressor.c inode.c super.c xattr.c zdata.c zmap.c; do
|
||||
pre15_record_fixture "b06-$source" "$PRE15_DUT/src/$source"
|
||||
done
|
||||
|
||||
mkdir -p "$artifacts"
|
||||
pre15_target_reached
|
||||
|
||||
if "$gate" --worktree --oracle "$tuple_oracle" \
|
||||
--output "$artifacts/gate" >"$artifacts/gate.stdout" \
|
||||
2>"$artifacts/gate.stderr"; then
|
||||
:
|
||||
else
|
||||
pre15_dut_fail 'B06 G02 candidate replay failed'
|
||||
fi
|
||||
|
||||
if python3 - "$PRE15_ROOT" "$ownership_oracle" "$artifacts/gate" \
|
||||
"$artifacts/ownership-check.json" <<'PY'
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
root = Path(sys.argv[1])
|
||||
expected = json.loads(Path(sys.argv[2]).read_text(encoding="ascii"))
|
||||
gate_dir = Path(sys.argv[3])
|
||||
output = Path(sys.argv[4])
|
||||
result = json.loads((gate_dir / "result.json").read_text(encoding="ascii"))
|
||||
ownership = json.loads((gate_dir / "ownership.json").read_text(encoding="ascii"))
|
||||
|
||||
if result["status"] != "GO" or result["tuple_status"] != "PASS":
|
||||
raise SystemExit(f"candidate tuple result is not GO: {result!r}")
|
||||
if not result["object_mode"] or result["oracle_equal"] is not True:
|
||||
raise SystemExit(f"candidate did not replay the frozen object oracle: {result!r}")
|
||||
if ownership["status"] != "PASS" or ownership["failures"]:
|
||||
raise SystemExit(f"candidate ownership result failed: {ownership['failures']!r}")
|
||||
if ownership["consumers"] != expected["consumers"]:
|
||||
raise SystemExit("ownership consumer set changed")
|
||||
if ownership["direct_metadata_functions"] != expected["direct_metadata_functions"]:
|
||||
raise SystemExit("direct metadata consumer inventory changed")
|
||||
if ownership["helper_paths"]["paths"] != expected["helper_paths"]:
|
||||
raise SystemExit("actual helper lifecycle paths changed")
|
||||
|
||||
metric_order = expected["metric_order"]
|
||||
actual_metrics = {
|
||||
item["function"]: [item[field] for field in metric_order]
|
||||
for item in ownership["candidate_contract"]["function_metrics"]
|
||||
}
|
||||
if actual_metrics != expected["function_metrics"]:
|
||||
raise SystemExit("per-function ownership metrics changed")
|
||||
|
||||
|
||||
def extract_function(source: str, name: str) -> str:
|
||||
match = re.search(r"^" + re.escape(name) + r"\s*\(", source, re.MULTILINE)
|
||||
if not match:
|
||||
raise SystemExit(f"backend function missing: {name}")
|
||||
start = source.rfind("\n\n", 0, match.start()) + 2
|
||||
brace = source.find("{", match.end())
|
||||
depth = 0
|
||||
state = "code"
|
||||
index = brace
|
||||
while index < len(source):
|
||||
char = source[index]
|
||||
following = source[index + 1] if index + 1 < len(source) else ""
|
||||
if state == "code":
|
||||
if char == "/" and following == "*":
|
||||
state = "block"
|
||||
index += 2
|
||||
continue
|
||||
if char == "/" and following == "/":
|
||||
state = "line"
|
||||
index += 2
|
||||
continue
|
||||
if char == '"':
|
||||
state = "string"
|
||||
elif char == "'":
|
||||
state = "character"
|
||||
elif char == "{":
|
||||
depth += 1
|
||||
elif char == "}":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
return source[start : index + 1] + "\n"
|
||||
elif state == "block" and char == "*" and following == "/":
|
||||
state = "code"
|
||||
index += 2
|
||||
continue
|
||||
elif state == "line" and char == "\n":
|
||||
state = "code"
|
||||
elif state in {"string", "character"}:
|
||||
if char == "\\":
|
||||
index += 2
|
||||
continue
|
||||
if (state == "string" and char == '"') or (
|
||||
state == "character" and char == "'"
|
||||
):
|
||||
state = "code"
|
||||
index += 1
|
||||
raise SystemExit(f"unterminated backend function: {name}")
|
||||
|
||||
|
||||
backend_hashes = {}
|
||||
for key, frozen_hash in expected["freebsd_backend_function_sha256"].items():
|
||||
filename, function = key.split(":", 1)
|
||||
source = (root / "repo-pre-15" / "src" / filename).read_text(encoding="utf-8")
|
||||
current_hash = hashlib.sha256(
|
||||
extract_function(source, function).encode("utf-8")
|
||||
).hexdigest()
|
||||
backend_hashes[key] = current_hash
|
||||
if current_hash != frozen_hash:
|
||||
raise SystemExit(f"FreeBSD backend lifecycle changed: {key}")
|
||||
|
||||
internal_path = root / "repo-pre-15" / "src" / "internal.h"
|
||||
internal = internal_path.read_text(encoding="utf-8")
|
||||
match = re.search(
|
||||
r"^struct erofs_map_blocks \{\n.*?^\};\n",
|
||||
internal,
|
||||
re.MULTILINE | re.DOTALL,
|
||||
)
|
||||
if not match:
|
||||
raise SystemExit("missing legacy map tuple object")
|
||||
map_hash = hashlib.sha256(match.group(0).encode("utf-8")).hexdigest()
|
||||
if map_hash != expected["map_blocks_sha256"]:
|
||||
raise SystemExit("B07 map objectization leaked into B06")
|
||||
|
||||
required = [
|
||||
"struct erofs_buf {",
|
||||
"#define EROFS_BUF_INITIALIZER { .data = NULL, .release = NULL }",
|
||||
"void erofs_put_metabuf(struct erofs_buf *buf);",
|
||||
"int erofs_bread(struct erofs_sb_info *sbi, erofs_off_t off, size_t len, void **bufp);",
|
||||
"void erofs_brelse(void *buf);",
|
||||
]
|
||||
for marker in required:
|
||||
if marker not in internal:
|
||||
raise SystemExit(f"required B06/raw API marker missing: {marker}")
|
||||
if re.search(
|
||||
r"erofs_read_metadata\s*\([^;]*void\s*\*\*bufp\s*\)\s*;",
|
||||
internal,
|
||||
re.MULTILINE | re.DOTALL,
|
||||
):
|
||||
raise SystemExit("legacy metadata void-pointer API remains")
|
||||
for filename in ("dir.c", "namei.c"):
|
||||
text = (root / "repo-pre-15" / "src" / filename).read_text(encoding="utf-8")
|
||||
if "struct erofs_buf" in text or "erofs_put_metabuf" in text:
|
||||
raise SystemExit(f"raw directory consumer was objectized: {filename}")
|
||||
|
||||
summary = {
|
||||
"status": "PASS",
|
||||
"tuple_cases": result["case_count"],
|
||||
"tuple_oracle_equal": result["oracle_equal"],
|
||||
"ownership_paths": result["ownership_path_count"],
|
||||
"helper_paths": len(expected["helper_paths"]),
|
||||
"function_metrics": len(actual_metrics),
|
||||
"freebsd_backend_functions": len(backend_hashes),
|
||||
"map_blocks_sha256": map_hash,
|
||||
"qemu": result["qemu"],
|
||||
"full_feature_suite": result["full_feature_suite"],
|
||||
}
|
||||
with output.open("x", encoding="ascii") as stream:
|
||||
json.dump(summary, stream, ensure_ascii=True, indent=2, sort_keys=True)
|
||||
stream.write("\n")
|
||||
print("B06 ownership PASS tuples=14 paths=22 helper=5 functions=28")
|
||||
PY
|
||||
then
|
||||
:
|
||||
else
|
||||
pre15_dut_fail 'B06 ownership fixture comparison failed'
|
||||
fi
|
||||
|
||||
sha256sum "$artifacts/gate/result.json" "$artifacts/gate/tuples.json" \
|
||||
"$artifacts/gate/ownership.json" "$artifacts/ownership-check.json" \
|
||||
>"$artifacts/SHA256SUMS"
|
||||
printf 'B06 PASS explicit metadata ownership and frozen tuple replay\n'
|
||||
Reference in New Issue
Block a user