generated from coulomb/repo-seed
CMIS compliance fixture integration and optional OpenCMIS TCK harness boundary
This commit is contained in:
@@ -26,3 +26,15 @@ The first target is a selected Browser Binding subset:
|
||||
Mutation groups should only be enabled for `governed-authoring` or
|
||||
`compat-tck` profiles after the policy and audit gates are implemented.
|
||||
|
||||
Harness files:
|
||||
|
||||
- `tck-subset-map.json` maps engine capability groups to selected OpenCMIS TCK
|
||||
groups and known gaps.
|
||||
- `tck-result-template.json` is the compact result capture format for optional
|
||||
TCK runs. Results should be stored outside the default repo history unless
|
||||
they document an intentional compatibility baseline.
|
||||
|
||||
Default `pytest` does not execute Java/Maven. It validates the map and result
|
||||
template so the optional harness does not drift away from the implemented
|
||||
profiles and fixtures.
|
||||
|
||||
|
||||
28
tests/cmis/opencmis-tck/tck-result-template.json
Normal file
28
tests/cmis/opencmis-tck/tck-result-template.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"run": {
|
||||
"tool": "Apache Chemistry OpenCMIS TCK",
|
||||
"tool_version": "1.1.0",
|
||||
"profile": "compat-tck",
|
||||
"repository_id": "kontextual-compat-tck",
|
||||
"browser_url": "http://127.0.0.1:8000/cmis/compat-tck/browser",
|
||||
"started_at": null,
|
||||
"finished_at": null
|
||||
},
|
||||
"summary": {
|
||||
"passed": 0,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"known_gap": 0
|
||||
},
|
||||
"groups": [
|
||||
{
|
||||
"capability_group": "repository-type",
|
||||
"tck_group": "RepositoryInfoTestGroup",
|
||||
"status": "not_run",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"capability_gaps": []
|
||||
}
|
||||
|
||||
66
tests/cmis/opencmis-tck/tck-subset-map.json
Normal file
66
tests/cmis/opencmis-tck/tck-subset-map.json
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"tck": {
|
||||
"name": "Apache Chemistry OpenCMIS TCK",
|
||||
"version": "1.1.0",
|
||||
"artifact": "org.apache.chemistry.opencmis:chemistry-opencmis-test-tck:1.1.0",
|
||||
"execution": "optional"
|
||||
},
|
||||
"target": {
|
||||
"profile": "compat-tck",
|
||||
"repository_id": "kontextual-compat-tck",
|
||||
"browser_url": "http://127.0.0.1:8000/cmis/compat-tck/browser"
|
||||
},
|
||||
"groups": [
|
||||
{
|
||||
"capability_group": "repository-type",
|
||||
"tck_groups": ["RepositoryInfoTestGroup", "TypesTestGroup"],
|
||||
"expected": "selected-pass"
|
||||
},
|
||||
{
|
||||
"capability_group": "navigation",
|
||||
"tck_groups": ["NavigationTestGroup"],
|
||||
"expected": "selected-pass"
|
||||
},
|
||||
{
|
||||
"capability_group": "object-content",
|
||||
"tck_groups": ["ObjectServiceTestGroup", "ContentStreamTestGroup"],
|
||||
"expected": "selected-pass"
|
||||
},
|
||||
{
|
||||
"capability_group": "versioning",
|
||||
"tck_groups": ["VersioningTestGroup"],
|
||||
"expected": "partial-pass",
|
||||
"known_gaps": ["private_working_copy"]
|
||||
},
|
||||
{
|
||||
"capability_group": "discovery-query",
|
||||
"tck_groups": ["QueryTestGroup"],
|
||||
"expected": "partial-pass",
|
||||
"known_gaps": ["full_cmis_sql_joins"]
|
||||
},
|
||||
{
|
||||
"capability_group": "relationships",
|
||||
"tck_groups": ["RelationshipTestGroup"],
|
||||
"expected": "selected-pass"
|
||||
},
|
||||
{
|
||||
"capability_group": "acl-policy",
|
||||
"tck_groups": ["AclTestGroup", "PolicyTestGroup"],
|
||||
"expected": "partial-pass",
|
||||
"known_gaps": ["apply_policy", "remove_policy"]
|
||||
},
|
||||
{
|
||||
"capability_group": "change-log",
|
||||
"tck_groups": ["ChangeLogTestGroup"],
|
||||
"expected": "selected-pass"
|
||||
},
|
||||
{
|
||||
"capability_group": "retention-renditions-bulk",
|
||||
"tck_groups": ["RenditionsTestGroup", "BulkUpdateTestGroup"],
|
||||
"expected": "skip",
|
||||
"known_gaps": ["retention_hold_mutation", "bulk_update_properties", "rendition_streams"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
122
tests/cmis/test_cmis_fixture_integration.py
Normal file
122
tests/cmis/test_cmis_fixture_integration.py
Normal file
@@ -0,0 +1,122 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from kontextual_engine import (
|
||||
Actor,
|
||||
ActorType,
|
||||
CMISAccessPoint,
|
||||
CMISAccessProfile,
|
||||
CMISAction,
|
||||
OperationContext,
|
||||
)
|
||||
|
||||
|
||||
pytestmark = pytest.mark.cmis
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
FIXTURE_PATH = ROOT / "examples" / "cmis" / "capability-fixtures.json"
|
||||
TCK_MAP_PATH = ROOT / "tests" / "cmis" / "opencmis-tck" / "tck-subset-map.json"
|
||||
TCK_RESULT_TEMPLATE = ROOT / "tests" / "cmis" / "opencmis-tck" / "tck-result-template.json"
|
||||
|
||||
ACTION_MAP = {
|
||||
"create_document": CMISAction.CREATE_DOCUMENT,
|
||||
"update_properties": CMISAction.UPDATE_PROPERTIES,
|
||||
"delete_object": CMISAction.DELETE_OBJECT,
|
||||
"set_content_stream": CMISAction.SET_CONTENT_STREAM,
|
||||
}
|
||||
|
||||
|
||||
def _catalog() -> dict:
|
||||
return json.loads(FIXTURE_PATH.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def _tck_map() -> dict:
|
||||
return json.loads(TCK_MAP_PATH.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def _profiles() -> dict[str, CMISAccessProfile]:
|
||||
return {
|
||||
profile.name: profile
|
||||
for profile in (
|
||||
CMISAccessProfile.readonly_browser(),
|
||||
CMISAccessProfile.governed_authoring(),
|
||||
CMISAccessProfile.admin_export(),
|
||||
CMISAccessProfile.compat_tck(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def _context(actor_type: ActorType = ActorType.HUMAN) -> OperationContext:
|
||||
return OperationContext.create(
|
||||
Actor.create(actor_type, actor_id=f"fixture-{actor_type.value}"),
|
||||
correlation_id="corr-cmis-fixture-integration",
|
||||
)
|
||||
|
||||
|
||||
def test_fixture_profiles_match_implemented_access_profiles() -> None:
|
||||
catalog = _catalog()
|
||||
implemented = _profiles()
|
||||
|
||||
assert set(catalog["profiles"]) == set(implemented)
|
||||
for profile_name, fixture in catalog["profiles"].items():
|
||||
profile = implemented[profile_name]
|
||||
assert profile.binding.value == fixture["binding"]
|
||||
assert profile.allow_mutations is fixture["mutations"]
|
||||
assert [item.value for item in profile.visible_sensitivities] == fixture["visibility"]
|
||||
assert [item.value for item in profile.denied_sensitivities] == fixture["deny"]
|
||||
|
||||
|
||||
def test_fixture_mutation_expectations_match_profile_decisions() -> None:
|
||||
catalog = _catalog()
|
||||
implemented = _profiles()
|
||||
|
||||
for profile_name, expectations in catalog["profile_expectations"].items():
|
||||
profile = implemented[profile_name]
|
||||
context = _context(
|
||||
ActorType.SERVICE_ACCOUNT if profile.required_actor_types else ActorType.HUMAN
|
||||
)
|
||||
for action_name in expectations.get("must_authorize_actions", []):
|
||||
assert profile.decide_action(ACTION_MAP[action_name], context).allowed is True
|
||||
for action_name in expectations.get("must_reject_actions", []):
|
||||
assert profile.decide_action(ACTION_MAP[action_name], context).allowed is False
|
||||
|
||||
|
||||
def test_every_fixture_profile_has_a_browser_access_point_shape() -> None:
|
||||
for profile in _profiles().values():
|
||||
access_point = CMISAccessPoint(
|
||||
access_point_id=profile.name,
|
||||
repository_id=f"kontextual-{profile.name}",
|
||||
profile=profile,
|
||||
base_path=f"/cmis/{profile.name}/browser",
|
||||
)
|
||||
serialized = access_point.to_dict()
|
||||
|
||||
assert serialized["base_path"] == f"/cmis/{profile.name}/browser"
|
||||
assert serialized["repository_id"] == f"kontextual-{profile.name}"
|
||||
assert serialized["profile"]["binding"] == "browser"
|
||||
|
||||
|
||||
def test_optional_opencmis_tck_map_covers_fixture_capability_groups() -> None:
|
||||
catalog = _catalog()
|
||||
tck_map = _tck_map()
|
||||
fixture_groups = {group["id"] for group in catalog["capability_groups"]}
|
||||
mapped_groups = {group["capability_group"] for group in tck_map["groups"]}
|
||||
|
||||
assert tck_map["tck"]["execution"] == "optional"
|
||||
assert tck_map["target"]["profile"] == "compat-tck"
|
||||
assert mapped_groups == fixture_groups
|
||||
assert all(group["tck_groups"] for group in tck_map["groups"])
|
||||
|
||||
|
||||
def test_optional_tck_result_template_can_capture_gap_mapping() -> None:
|
||||
template = json.loads(TCK_RESULT_TEMPLATE.read_text(encoding="utf-8"))
|
||||
|
||||
assert template["run"]["profile"] == "compat-tck"
|
||||
assert template["summary"] == {"passed": 0, "failed": 0, "skipped": 0, "known_gap": 0}
|
||||
assert "capability_gaps" in template
|
||||
assert template["groups"][0]["status"] == "not_run"
|
||||
|
||||
Reference in New Issue
Block a user