generated from coulomb/repo-seed
chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-05-07: - update .custodian-brief.md for open-cmis-tck
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import http.client
|
||||
import json
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import unittest
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
from pathlib import Path
|
||||
@@ -10,6 +13,9 @@ from tempfile import TemporaryDirectory
|
||||
from guide_board.discovery import discover_extensions
|
||||
from guide_board.execution import run_assessment
|
||||
from guide_board.planning import build_run_plan, validate_assessment_profile
|
||||
from guide_board.retention import build_trend_summary
|
||||
from guide_board.service import ServiceHandle, start_service
|
||||
from open_cmis_tck.profile import validate_cmis_profile_config
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
@@ -44,6 +50,37 @@ class OpenCmisTckExtensionTests(unittest.TestCase):
|
||||
self.assertEqual(plan["extension_snapshots"][0]["path"], str(ROOT))
|
||||
self.assertEqual(len(plan["ordered_steps"]), 3)
|
||||
|
||||
def test_validates_cmis_profile_config_with_actionable_diagnostics(self) -> None:
|
||||
target = json.loads(
|
||||
(ROOT / "profiles" / "targets" / "kontextual-cmis-compat.json").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
)
|
||||
assessment = json.loads(
|
||||
(ROOT / "profiles" / "assessments" / "cmis-browser-baseline.json").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
)
|
||||
|
||||
diagnostics = validate_cmis_profile_config(target, assessment)
|
||||
|
||||
self.assertEqual(diagnostics["status"], "valid")
|
||||
self.assertEqual(
|
||||
diagnostics["cmis_config"]["browser_binding_url"],
|
||||
"http://127.0.0.1:8000/cmis/compat-tck/browser",
|
||||
)
|
||||
self.assertEqual(diagnostics["cmis_config"]["repository_id"], "compat-tck")
|
||||
self.assertEqual(diagnostics["cmis_config"]["auth_mode"], "anonymous")
|
||||
|
||||
broken = dict(target)
|
||||
broken["endpoints"] = []
|
||||
broken_diagnostics = validate_cmis_profile_config(broken, assessment)
|
||||
self.assertEqual(broken_diagnostics["status"], "invalid")
|
||||
self.assertIn(
|
||||
"Add one endpoint with binding 'cmis-browser'",
|
||||
broken_diagnostics["diagnostics"][0]["message"],
|
||||
)
|
||||
|
||||
def test_runs_cmis_preflight_against_local_endpoint(self) -> None:
|
||||
server = HTTPServer(("127.0.0.1", 0), _CmisHandler)
|
||||
thread = threading.Thread(target=server.serve_forever)
|
||||
@@ -88,6 +125,11 @@ class OpenCmisTckExtensionTests(unittest.TestCase):
|
||||
evidence[0]["facts"]["repository_ids"],
|
||||
["local-test-repository"],
|
||||
)
|
||||
posture = {
|
||||
item["requirement_ref"]: item["status"]
|
||||
for item in evidence[0]["facts"]["capability_posture"]
|
||||
}
|
||||
self.assertEqual(posture["cmis.repository-info"], "supported")
|
||||
self.assertEqual(len(package["artifact_manifest"]), 2)
|
||||
self.assertTrue(
|
||||
(
|
||||
@@ -103,6 +145,60 @@ class OpenCmisTckExtensionTests(unittest.TestCase):
|
||||
thread.join(timeout=5)
|
||||
server.server_close()
|
||||
|
||||
def test_preflight_accepts_unsupported_optional_capability_as_known_gap(self) -> None:
|
||||
server = HTTPServer(("127.0.0.1", 0), _CmisHandler)
|
||||
thread = threading.Thread(target=server.serve_forever)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
try:
|
||||
with TemporaryDirectory() as temporary_directory:
|
||||
temp_root = Path(temporary_directory)
|
||||
target_path = temp_root / "target.json"
|
||||
assessment_path = temp_root / "assessment.json"
|
||||
_write_target(target_path, server.server_port, "local-cmis-query-gap")
|
||||
target = json.loads(target_path.read_text(encoding="utf-8"))
|
||||
target["declared_capabilities"].append("cmis.query")
|
||||
target["known_gaps"].append(
|
||||
{
|
||||
"id": "query-not-targeted",
|
||||
"requirement_refs": ["cmis.query"],
|
||||
"reason": "The local fixture deliberately reports no query support.",
|
||||
"status": "unsupported_by_design",
|
||||
}
|
||||
)
|
||||
target_path.write_text(json.dumps(target), encoding="utf-8")
|
||||
_write_assessment(
|
||||
assessment_path,
|
||||
"local-cmis-known-gap",
|
||||
"local-cmis-query-gap",
|
||||
[],
|
||||
None,
|
||||
)
|
||||
|
||||
result = run_assessment(
|
||||
CORE_ROOT,
|
||||
target_path,
|
||||
assessment_path,
|
||||
temp_root / "run",
|
||||
[ROOT],
|
||||
)
|
||||
evidence = json.loads(
|
||||
(Path(result["run_dir"]) / "normalized" / "evidence.json").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
)["evidence"]
|
||||
posture = {
|
||||
item["requirement_ref"]: item["status"]
|
||||
for item in evidence[0]["facts"]["capability_posture"]
|
||||
}
|
||||
|
||||
self.assertEqual(result["status"], "completed")
|
||||
self.assertEqual(posture["cmis.query"], "expected_gap")
|
||||
finally:
|
||||
server.shutdown()
|
||||
thread.join(timeout=5)
|
||||
server.server_close()
|
||||
|
||||
def test_runs_cmis_tck_command_wrapper_boundary(self) -> None:
|
||||
server = HTTPServer(("127.0.0.1", 0), _CmisHandler)
|
||||
thread = threading.Thread(target=server.serve_forever)
|
||||
@@ -163,6 +259,144 @@ class OpenCmisTckExtensionTests(unittest.TestCase):
|
||||
thread.join(timeout=5)
|
||||
server.server_close()
|
||||
|
||||
def test_runs_configured_tck_command_and_normalizes_json_results(self) -> None:
|
||||
server = HTTPServer(("127.0.0.1", 0), _CmisHandler)
|
||||
thread = threading.Thread(target=server.serve_forever)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
try:
|
||||
with TemporaryDirectory() as temporary_directory:
|
||||
temp_root = Path(temporary_directory)
|
||||
target_path = temp_root / "target.json"
|
||||
assessment_path = temp_root / "assessment.json"
|
||||
fake_tck = temp_root / "fake_tck.py"
|
||||
fake_tck.write_text(
|
||||
"\n".join(
|
||||
[
|
||||
"import json",
|
||||
"print(json.dumps({",
|
||||
" 'tests': [",
|
||||
" {'id': 'repository-info', 'status': 'pass'},",
|
||||
" {'id': 'type-definitions', 'status': 'pass'}",
|
||||
" ]",
|
||||
"}))",
|
||||
]
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
_write_target(target_path, server.server_port, "local-cmis-configured-tck")
|
||||
_write_assessment(
|
||||
assessment_path,
|
||||
"local-cmis-configured-tck",
|
||||
"local-cmis-configured-tck",
|
||||
["repository-type"],
|
||||
None,
|
||||
{
|
||||
"requires_java_maven": False,
|
||||
"repository_id": "local-test-repository",
|
||||
"command": [
|
||||
sys.executable,
|
||||
str(fake_tck),
|
||||
"--url",
|
||||
"{browser_url}",
|
||||
"--repository",
|
||||
"{repository_id}",
|
||||
"--group",
|
||||
"{check_group}",
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
result = run_assessment(
|
||||
CORE_ROOT,
|
||||
target_path,
|
||||
assessment_path,
|
||||
temp_root / "run",
|
||||
[ROOT],
|
||||
)
|
||||
run_dir = Path(result["run_dir"])
|
||||
evidence = json.loads(
|
||||
(run_dir / "normalized" / "evidence.json").read_text(encoding="utf-8")
|
||||
)["evidence"]
|
||||
retention = json.loads(
|
||||
(run_dir / "retention-summary.json").read_text(encoding="utf-8")
|
||||
)
|
||||
trend = build_trend_summary(temp_root)
|
||||
|
||||
self.assertEqual(result["status"], "completed")
|
||||
self.assertEqual(evidence[1]["result"], "pass")
|
||||
self.assertEqual(evidence[1]["facts"]["normalizer"], "json-cases")
|
||||
self.assertEqual(evidence[1]["facts"]["result_counts"], {"pass": 2})
|
||||
self.assertTrue(
|
||||
(
|
||||
run_dir
|
||||
/ "artifacts"
|
||||
/ "open-cmis-tck"
|
||||
/ "tck"
|
||||
/ "repository-type"
|
||||
/ "stdout.log"
|
||||
).exists()
|
||||
)
|
||||
self.assertEqual(retention["summary"]["status"], "completed")
|
||||
self.assertGreaterEqual(retention["summary"]["artifact_count"], 4)
|
||||
self.assertEqual(trend["run_count"], 1)
|
||||
finally:
|
||||
server.shutdown()
|
||||
thread.join(timeout=5)
|
||||
server.server_close()
|
||||
|
||||
def test_guide_board_service_runs_cmis_extension(self) -> None:
|
||||
server = HTTPServer(("127.0.0.1", 0), _CmisHandler)
|
||||
thread = threading.Thread(target=server.serve_forever)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
service = start_service(CORE_ROOT, [ROOT], host="127.0.0.1", port=0)
|
||||
try:
|
||||
with TemporaryDirectory() as temporary_directory:
|
||||
temp_root = Path(temporary_directory)
|
||||
target_path = temp_root / "target.json"
|
||||
assessment_path = temp_root / "assessment.json"
|
||||
_write_target(target_path, server.server_port, "local-cmis-service")
|
||||
_write_assessment(
|
||||
assessment_path,
|
||||
"local-cmis-service",
|
||||
"local-cmis-service",
|
||||
[],
|
||||
None,
|
||||
)
|
||||
|
||||
extensions = _request_json(service, "GET", "/extensions")
|
||||
self.assertIn(
|
||||
"open-cmis-tck",
|
||||
[extension["id"] for extension in extensions["extensions"]],
|
||||
)
|
||||
|
||||
job = _request_json(
|
||||
service,
|
||||
"POST",
|
||||
"/runs",
|
||||
{
|
||||
"target": str(target_path),
|
||||
"assessment": str(assessment_path),
|
||||
"output_dir": str(temp_root / "service-run"),
|
||||
},
|
||||
expected_status=202,
|
||||
)
|
||||
status = _wait_for_job(service, job["job_id"])
|
||||
reports = _request_json(service, "GET", f"/runs/{job['job_id']}/reports")
|
||||
|
||||
self.assertEqual(status["status"], "succeeded")
|
||||
self.assertEqual(status["result"]["status"], "completed")
|
||||
self.assertEqual(
|
||||
reports["assessment_package"]["json"]["extensions"][0]["id"],
|
||||
"open-cmis-tck",
|
||||
)
|
||||
finally:
|
||||
service.stop()
|
||||
server.shutdown()
|
||||
thread.join(timeout=5)
|
||||
server.server_close()
|
||||
|
||||
def test_preflight_failure_blocks_downstream_checks(self) -> None:
|
||||
with TemporaryDirectory() as temporary_directory:
|
||||
temp_root = Path(temporary_directory)
|
||||
@@ -259,7 +493,14 @@ def _write_assessment(
|
||||
target_id: str,
|
||||
check_groups: list[str],
|
||||
waiver_ref: str | None,
|
||||
opencmis_policy: dict[str, object] | None = None,
|
||||
) -> None:
|
||||
runtime_policy: dict[str, object] = {
|
||||
"offline": False,
|
||||
"timeout_seconds": 15,
|
||||
}
|
||||
if opencmis_policy is not None:
|
||||
runtime_policy["opencmis_tck"] = opencmis_policy
|
||||
path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
@@ -278,10 +519,7 @@ def _write_assessment(
|
||||
"summary_days": 365,
|
||||
"raw_artifact_days": 0,
|
||||
},
|
||||
"runtime_policy": {
|
||||
"offline": False,
|
||||
"timeout_seconds": 15,
|
||||
},
|
||||
"runtime_policy": runtime_policy,
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
@@ -316,6 +554,42 @@ def _write_command_waiver(path: Path, target_id: str) -> None:
|
||||
)
|
||||
|
||||
|
||||
def _request_json(
|
||||
service: ServiceHandle,
|
||||
method: str,
|
||||
path: str,
|
||||
payload: dict[str, object] | None = None,
|
||||
expected_status: int = 200,
|
||||
) -> dict[str, object]:
|
||||
connection = http.client.HTTPConnection(service.host, service.port, timeout=5)
|
||||
body = None
|
||||
headers = {}
|
||||
if payload is not None:
|
||||
body = json.dumps(payload).encode("utf-8")
|
||||
headers["Content-Type"] = "application/json"
|
||||
try:
|
||||
connection.request(method, path, body=body, headers=headers)
|
||||
response = connection.getresponse()
|
||||
data = response.read().decode("utf-8")
|
||||
finally:
|
||||
connection.close()
|
||||
if response.status != expected_status:
|
||||
raise AssertionError(f"expected HTTP {expected_status}, got {response.status}: {data}")
|
||||
value = json.loads(data)
|
||||
if not isinstance(value, dict):
|
||||
raise AssertionError(f"expected JSON object response, got {type(value).__name__}")
|
||||
return value
|
||||
|
||||
|
||||
def _wait_for_job(service: ServiceHandle, job_id: str) -> dict[str, object]:
|
||||
for _ in range(50):
|
||||
status = _request_json(service, "GET", f"/runs/{job_id}")
|
||||
if status["status"] in {"succeeded", "failed"}:
|
||||
return status
|
||||
time.sleep(0.05)
|
||||
raise AssertionError(f"job did not finish: {job_id}")
|
||||
|
||||
|
||||
class _CmisHandler(BaseHTTPRequestHandler):
|
||||
def do_GET(self) -> None:
|
||||
body = json.dumps(
|
||||
@@ -324,7 +598,13 @@ class _CmisHandler(BaseHTTPRequestHandler):
|
||||
"repositoryId": "local-test-repository",
|
||||
"repositoryName": "Local Test Repository",
|
||||
"cmisVersionSupported": "1.1",
|
||||
"capabilities": {},
|
||||
"capabilities": {
|
||||
"capabilityACL": "discover",
|
||||
"capabilityChanges": "none",
|
||||
"capabilityGetDescendants": True,
|
||||
"capabilityGetFolderTree": True,
|
||||
"capabilityQuery": "none",
|
||||
},
|
||||
}
|
||||
}
|
||||
).encode("utf-8")
|
||||
|
||||
Reference in New Issue
Block a user