89 lines
3.4 KiB
Python
Executable File
89 lines
3.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Smoke-test the modules3p bridge without touching the system."""
|
|
import json
|
|
import subprocess
|
|
import os
|
|
import sys
|
|
|
|
BRIDGE = os.path.join(os.path.dirname(__file__), "..", "bridge", "modules3p.py")
|
|
BRIDGE = os.path.abspath(BRIDGE)
|
|
|
|
def run(args):
|
|
r = subprocess.run(["python3", BRIDGE, *args], capture_output=True, text=True)
|
|
out = None
|
|
if r.stdout:
|
|
try:
|
|
out = json.loads(r.stdout)
|
|
except json.JSONDecodeError:
|
|
out = r.stdout
|
|
return r.returncode, out, r.stderr
|
|
|
|
failures = 0
|
|
checks = 0
|
|
|
|
# 1. catalog returns a list and each entry has the mandatory fields
|
|
rc, cat, _ = run(["catalog"])
|
|
assert rc == 0, f"catalog rc={rc}"
|
|
assert isinstance(cat, list) and len(cat) >= 10, f"catalog len={len(cat)}"
|
|
mandatory = {"id", "name", "blurb", "license", "author", "source", "category", "kind", "install_spec"}
|
|
for e in cat:
|
|
checks += 1
|
|
missing = mandatory - set(e.keys())
|
|
assert not missing, f"entry {e.get('id')} missing fields: {missing}"
|
|
print(f"[ok] catalog: {len(cat)} entries, all have mandatory fields")
|
|
|
|
# 2. status returns installed/missing_deps booleans
|
|
rc, st, _ = run(["status"])
|
|
assert st is not None and isinstance(st, list), f"status returned non-list: {st}"
|
|
assert len(st) == len(cat), f"status len={len(st)} != catalog len={len(cat)}"
|
|
for e in st:
|
|
checks += 1
|
|
assert "installed" in e and "missing_deps" in e, f"status entry missing fields: {e}"
|
|
print(f"[ok] status: {len(st)} entries with installed + missing_deps")
|
|
|
|
# 3. preflight for every catalog entry
|
|
for e in cat:
|
|
checks += 1
|
|
rc, pf, _ = run(["preflight", e["id"]])
|
|
assert rc == 0, f"preflight {e['id']} rc={rc} stderr={_}"
|
|
assert pf["ok"], f"preflight {e['id']} not ok: {pf}"
|
|
# The disclosure MUST contain license + author + source + install plan
|
|
assert pf["license"] == e["license"], f"license mismatch for {e['id']}"
|
|
assert pf["author"] == e["author"]
|
|
assert pf["source"] == e["source"]
|
|
assert isinstance(pf["install_plan"], list) and len(pf["install_plan"]) >= 1
|
|
assert "credit_line" in pf and e["license"] in pf["credit_line"]
|
|
print(f"[ok] preflight: every catalog entry returns license + credit + install_plan BEFORE pull")
|
|
|
|
# 4. install WITHOUT --accept-license is refused for every entry
|
|
for e in cat:
|
|
checks += 1
|
|
rc, r, _ = run(["install", e["id"]])
|
|
# rc=1 because ok=false, but the JSON should be valid
|
|
try:
|
|
d = json.loads(r) if isinstance(r, str) else r
|
|
except Exception:
|
|
d = None
|
|
# Some entries might already be installed and return ok=true; that's fine.
|
|
# We only care that NOT-installed entries refuse without --accept-license.
|
|
if d and d.get("status") == "already-installed":
|
|
continue
|
|
assert d and d.get("ok") is False and d.get("error") == "license-not-accepted", \
|
|
f"install {e['id']} without --accept-license should refuse; got: {d}"
|
|
print(f"[ok] install: every non-installed entry refuses without --accept-license=1")
|
|
|
|
# 5. unknown id returns ok=false
|
|
rc, r, _ = run(["preflight", "does-not-exist"])
|
|
checks += 1
|
|
assert r["ok"] is False and "unknown" in r["error"]
|
|
print(f"[ok] preflight: unknown id returns ok=false")
|
|
|
|
# 6. audit returns a list (path may not exist — that's fine)
|
|
rc, a, _ = run(["audit"])
|
|
checks += 1
|
|
assert a["ok"] and "records" in a and isinstance(a["records"], list)
|
|
print(f"[ok] audit: returns {len(a['records'])} records from {a['path']}")
|
|
|
|
print(f"\nALL {checks} CHECKS PASSED")
|
|
sys.exit(failures)
|