Files
lingniu-vehicle-ingest/vehicle-data-platform/scripts/oneos-fixture.py
T
lingniu d6b957dfc8 feat: sync vehicle monitoring and accumulated platform updates
Add monitoring metrics, numeric sorting, report-time display, vehicle number labels, and map layout fixes. Include accumulated mileage, hydrogen, OneOS authentication, open platform, ingestion, deployment, and UI updates.

Exclude temporary files, generated reports, and credentials. Validate frontend 632 tests and production build, API packages, vehicle-map tests, and release installer tests. Gateway suite has one pre-existing date-sensitive identity throttling test failure reproduced on the parent commit.
2026-10-26 18:05:59 +08:00

97 lines
5.1 KiB
Python

#!/usr/bin/env python3
"""Build and run an isolated local platform + fake OneOS, without external services.
Requires installed Go/Node dependencies. No install, SSH, migration, cloud CLI,
external fetch or production configuration is used. Ctrl-C stops both children.
"""
import argparse
import json
import os
from pathlib import Path
import shutil
import signal
import subprocess
import tempfile
import time
import urllib.request
ROOT = Path(__file__).resolve().parents[1]
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--skip-web-build", action="store_true")
args = parser.parse_args()
run = Path(tempfile.mkdtemp(prefix="vehicle-oneos-local-"))
os.chmod(run, 0o700)
# Build tools need installed paths/cache, but no inherited service credentials.
clean = {key: os.environ[key] for key in ("PATH", "HOME", "TMPDIR") if key in os.environ}
clean.update({"GOPROXY": "off", "GOSUMDB": "off", "GOTOOLCHAIN": "local", "NO_UPDATE_NOTIFIER": "1"})
children, logs = [], []
try:
for name, package in (("fixture", "./cmd/oneos-local-fixture"), ("platform", "./cmd/platform-api")):
subprocess.run([shutil.which("go"), "build", "-o", str(run / name), package], cwd=ROOT / "apps/api", env=clean, check=True)
if not args.skip_web_build:
with (run / "web-build.log").open("w") as build_log:
subprocess.run([shutil.which("pnpm"), "build"], cwd=ROOT / "apps/web", env=clean, stdout=build_log, stderr=subprocess.STDOUT, check=True)
if not (ROOT / "apps/web/dist/index.html").is_file():
raise RuntimeError("local frontend build is missing")
config_file = run / "fixture.json"
fixture_log = (run / "fixture.log").open("w"); logs.append(fixture_log)
children.append(subprocess.Popen([str(run / "fixture"), "-config-file", str(config_file)], env=clean, stdout=fixture_log, stderr=subprocess.STDOUT))
deadline = time.monotonic() + 10
while not config_file.exists():
if children[-1].poll() is not None or time.monotonic() > deadline:
raise RuntimeError("local fixture failed to start; see fixture.log")
time.sleep(0.1)
fixture = json.loads(config_file.read_text())
api_env = dict(clean)
api_env.update({
"HTTP_ADDR": "127.0.0.1:20400", "DATA_MODE": "mock", "AUTH_MODE": "enforce",
"STATIC_DIR": str(ROOT / "apps/web/dist"), "EXPORT_DIR": str(run / "exports"),
"ONEOS_LOCAL_ONLY": "true", "ONEOS_AUTH_ENABLED": "true", "ONEOS_PASSWORD_ENABLED": "true",
"ONEOS_PROFILE_BASE_URL": fixture["baseURL"],
"ONEOS_PROFILE_ISSUER": fixture["issuer"], "ONEOS_PROFILE_ALLOWED_TENANT": fixture["tenantId"],
"ONEOS_PUBLIC_ORIGIN": fixture["publicOrigin"], "ONEOS_PASSWORD_CLIENT_ID": fixture["clientId"],
"ONEOS_PASSWORD_RSA_PUBLIC_KEY": fixture["publicKey"],
"ONEOS_LOGIN_TICKET_EXCHANGE_PATH": "/auth/inner/v1/sso/vehicle-platform/token-exchange",
"ONEOS_LOGIN_TICKET_SERVICE_TOKEN": fixture["serviceToken"],
"ONEOS_VEHICLE_SCOPE_PATH": "/asset/vehicle-platform/scope",
})
api_log = (run / "platform.log").open("w"); logs.append(api_log)
children.append(subprocess.Popen([str(run / "platform")], env=api_env, stdout=api_log, stderr=subprocess.STDOUT))
opener = urllib.request.build_opener(urllib.request.ProxyHandler({}))
deadline = time.monotonic() + 10
while True:
try:
with opener.open("http://127.0.0.1:20400/api/v2/auth/providers", timeout=1) as resp:
providers = json.load(resp)["data"]
if not providers["oneos"]["passwordEnabled"] or not providers["oneos"]["ssoEnabled"]:
raise RuntimeError("local shared-token authentication not ready")
break
except (OSError, ValueError, KeyError):
if children[-1].poll() is not None or time.monotonic() > deadline:
raise RuntimeError("local platform failed to start; see platform.log")
time.sleep(0.1)
print(json.dumps({"platform": fixture["publicOrigin"], "oneosFixture": fixture["baseURL"], "runDirectory": str(run), "fixtureConfig": str(config_file), "localOnly": True}), flush=True)
while all(child.poll() is None for child in children):
time.sleep(0.5)
raise RuntimeError("one of the local child processes exited")
except KeyboardInterrupt:
pass
finally:
for child in reversed(children):
if child.poll() is None:
child.terminate()
for child in children:
try: child.wait(timeout=5)
except subprocess.TimeoutExpired: child.kill(); child.wait()
for handle in logs: handle.close()
# Keep evidence and fixtures for local inspection; directory is mode 0700.
print(f"Local processes stopped. Local evidence: {run}", flush=True)
if __name__ == "__main__":
signal.signal(signal.SIGTERM, lambda *_: (_ for _ in ()).throw(KeyboardInterrupt()))
main()