feat: add typed error message templates and stable replay snapshots

This commit is contained in:
2026-09-24 15:05:08 +08:00
parent 2041e7f661
commit 6e3f025aad
32 changed files with 1570 additions and 99 deletions

View File

@@ -0,0 +1,59 @@
#!/usr/bin/env python3
"""Test template replay against an isolated, bounded local Redis container."""
import argparse
import datetime
import json
import os
from pathlib import Path
import subprocess
import time
ROOT = Path(__file__).resolve().parents[1]
def run(args, **kwargs):
return subprocess.run(args, check=True, capture_output=True, text=True, **kwargs).stdout.strip()
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--report", type=Path, default=ROOT / "performance/errorParamsRedis.json")
args = parser.parse_args()
started = time.monotonic()
container = run(["docker", "run", "--pull=never", "--rm", "-d", "--cpus", "1", "--memory", "128m",
"--pids-limit", "64", "-p", "127.0.0.1::6379", "redis:7-alpine",
"redis-server", "--save", "", "--appendonly", "no", "--maxmemory", "64mb",
"--maxmemory-policy", "noeviction"])
print("Started isolated Redis (1 CPU, 128 MiB); loopback only", flush=True)
try:
image = run(["docker", "inspect", "--format", "{{.Image}}", container])
address = run(["docker", "port", container, "6379/tcp"])
for _ in range(30):
try:
if run(["docker", "exec", container, "redis-cli", "ping"]) == "PONG":
break
except subprocess.CalledProcessError:
pass
time.sleep(0.1)
else:
raise RuntimeError("Redis did not become ready")
env = dict(os.environ, GO_OMNI_REDIS_TEST_ADDR=address)
output = run(["go", "test", "-race", "-count=1", "-json", "-timeout=120s",
"./middleware/redis"], cwd=ROOT, env=env, timeout=150)
events = [json.loads(line) for line in output.splitlines() if line.startswith("{")]
passed = [e["Test"] for e in events if e.get("Action") == "pass" and "Test" in e]
skipped = [e["Test"] for e in events if e.get("Action") == "skip" and "Test" in e]
assert "TestTemplateErrorRedisReplay" in passed and not skipped, (passed, skipped)
args.report.write_text(json.dumps({
"passed": True, "image": image, "timestamp": datetime.datetime.now(datetime.timezone.utc).isoformat(),
"goVersion": run(["go", "version"]), "durationSeconds": round(time.monotonic() - started, 2),
"passedTests": passed, "skippedTests": skipped,
"checks": ["templateReplay", "int64CodePrecisionThroughLua", "catalogChangeKeepsSnapshot",
"noPersistedCauseOrParams", "http200Failure", "dataNull", "oneBusinessExecution"],
"cpuLimit": 1, "memoryMiB": 128, "loopbackOnly": True,
}, ensure_ascii=False, indent=2) + "\n")
print("PASS isolated Redis template replay and shared store regressions", flush=True)
finally:
run(["docker", "rm", "-f", container])
print("Temporary Redis container removed", flush=True)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,80 @@
#!/usr/bin/env python3
"""Install the released CLI in a fresh cache, then test its generated consumer.
The fixture tests typed message templates, runtime parameters, HTTP 200 business failures,
OpenAPI examples, fixed errors and regeneration protection. Only local temporary resources
are used; the framework and CLI are fetched from the specified remote version.
"""
import argparse
import hashlib
import json
import os
from pathlib import Path
import re
import subprocess
import tempfile
import time
ROOT = Path(__file__).resolve().parents[1]
MODULE = "git.yuntuo.hk/k2safe/go-omni"
def run(args, cwd, env, timeout=300):
result = subprocess.run([str(arg) for arg in args], cwd=cwd, env=env,
capture_output=True, text=True, timeout=timeout)
output = re.sub(r"https://[^/@\s]+:[^/@\s]+@", "https://", result.stdout + result.stderr)
if result.returncode:
raise RuntimeError(f"{args[0]} failed ({result.returncode}):\n{output}")
return output
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--version", required=True)
parser.add_argument("--report", type=Path, default=ROOT / "performance/errorParamsRemote.json")
args = parser.parse_args()
if not re.fullmatch(r"v\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?", args.version):
parser.error("a fixed release version is required")
env = {k: v for k, v in os.environ.items() if not k.startswith("GO_OMNI_")}
env.update(GOWORK="off", GOFLAGS="", GOPRIVATE="git.yuntuo.hk", GONOSUMDB="git.yuntuo.hk")
start = time.monotonic()
with tempfile.TemporaryDirectory(prefix="goOmniErrorParamsRelease-") as directory:
temp = Path(directory)
(temp / "bin").mkdir()
env.update(GOBIN=str(temp / "bin"), GOMODCACHE=str(temp / "modcache"))
print(f"Installing CLI {args.version} in an empty module cache", flush=True)
run(["go", "install", MODULE + "/cmd/go-omni@" + args.version], temp, env)
cli = temp / "bin/go-omni"
run([cli, "api", "validate", "--api", ROOT / "examples/contracts/errorParams.api"], temp, env)
env.update(GO_OMNI_SCAFFOLD_INTEGRATION="1", GO_OMNI_RELEASE_CLI=str(cli), GO_OMNI_RELEASE_VERSION=args.version)
print("Testing remote typed error generation, parameter failures and raw responses", flush=True)
output = run(["go", "test", "-race", "-count=1", "-json", "-timeout=180s",
"./cmd/go-omni/apigen", "-run", "^TestErrorParamsConsumer$"], ROOT, env)
events = [json.loads(line) for line in output.splitlines() if line.startswith("{")]
passed = [e["Test"] for e in events if e.get("Action") == "pass" and "Test" in e]
assert passed == ["TestErrorParamsConsumer"], output
evidence = "".join(e.get("Output", "") for e in events)
checksum = re.search(r"checksum (h1:\S+); no local replace", evidence)
assert checksum, "consumer did not verify its remote dependency"
report = {
"passed": True, "frameworkVersion": args.version, "frameworkSum": checksum.group(1),
"freshModuleCache": True, "noLocalReplace": True,
"durationSeconds": round(time.monotonic() - start, 2),
"checks": ["remoteCLIInstall", "errorCatalogValidation", "generatedErrorConstructors",
"http200BusinessFailure", "openAPIConcreteExampleAndParameters", "typedParameterOrder",
"companyAndRemarkMessages", "runtimeAndGeneratedAgreement", "missingAndWrongParameterFallback",
"concurrentIsolation", "fixedErrorCompatibility", "perErrorHTTPStatus",
"causeNotExposed", "rawSuccessAndWrappedFailure",
"earlyMiddlewareCatalog", "handwrittenFilesPreserved", "generatedConsumerRaceTests",
"fixedRemoteModuleChecksum"],
"sourceHashes": {name: hashlib.sha256((ROOT / name).read_bytes()).hexdigest() for name in
("scripts/verifyErrorParamsRelease.py", "cmd/go-omni/apigen/errorParams_test.go", "cmd/go-omni/apigen/errorCatalog_test.go",
"examples/contracts/errorParams.api",
"cmd/go-omni/apigen/testdata/errorParams/consumer_test.go")},
}
args.report.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n")
print(f"PASS remote error template contract {args.version}; temporary files removed", flush=True)
if __name__ == "__main__":
main()