generated from coulomb/repo-seed
Scoped CMIS workspace folders with create, list, parent, path lookup, delete, and delete-tree behavior
This commit is contained in:
@@ -90,6 +90,7 @@ def test_cmis_browser_binding_routes_are_advertised_in_openapi(cmis_client) -> N
|
||||
assert "/cmis/{access_point_id}/browser/query" in paths
|
||||
assert "/cmis/{access_point_id}/browser/relationships" in paths
|
||||
assert "/cmis/{access_point_id}/browser/changes" in paths
|
||||
assert "/cmis/{access_point_id}/browser/folder" in paths
|
||||
|
||||
|
||||
def test_cmis_repository_info_and_type_definitions(cmis_client) -> None:
|
||||
@@ -117,6 +118,10 @@ def test_cmis_repository_info_and_type_definitions(cmis_client) -> None:
|
||||
"/cmis/readonly-browser/browser/root",
|
||||
params={"cmisselector": "policies"},
|
||||
).json()
|
||||
root_object = cmis_client.get(
|
||||
"/cmis/readonly-browser/browser/root",
|
||||
params={"cmisselector": "object"},
|
||||
).json()
|
||||
|
||||
assert access_points["count"] == 4
|
||||
assert repository["repositoryId"] == "kontextual-readonly-browser"
|
||||
@@ -133,6 +138,11 @@ def test_cmis_repository_info_and_type_definitions(cmis_client) -> None:
|
||||
assert "propertyDefinitions" in browser_type_definition
|
||||
assert browser_type_descendants[0]["children"] == []
|
||||
assert root_policies == []
|
||||
assert root_object["properties"]["kontextual:filingSource"]["value"] == "root"
|
||||
assert root_object["properties"]["kontextual:workspaceFolder"]["value"] is False
|
||||
assert "kontextual:assetId" in browser_type_definition["propertyDefinitions"]
|
||||
assert browser_type_definition["propertyDefinitions"]["kontextual:topics"]["cardinality"] == "multi"
|
||||
assert "cmis:path" in browser_type_definition["propertyDefinitions"]
|
||||
assert {item["base_type_id"] for item in types["items"]} >= {
|
||||
"cmis:document",
|
||||
"cmis:folder",
|
||||
@@ -244,13 +254,115 @@ def test_cmis_governed_authoring_routes_allow_selected_mutations(cmis_client) ->
|
||||
assert deleted.json()["lifecycle"] == "delete_requested"
|
||||
|
||||
|
||||
def test_cmis_browser_binding_create_folder_action_creates_workspace_folder(cmis_client) -> None:
|
||||
created = cmis_client.post(
|
||||
"/cmis/compat-tck/browser/root",
|
||||
data={
|
||||
"cmisaction": "createFolder",
|
||||
"propertyId[0]": "cmis:objectTypeId",
|
||||
"propertyValue[0]": "cmis:folder",
|
||||
"propertyId[1]": "cmis:name",
|
||||
"propertyValue[1]": "Action Workspace",
|
||||
},
|
||||
)
|
||||
folder = created.json()
|
||||
folder_id = folder["properties"]["cmis:objectId"]["value"]
|
||||
root_children = cmis_client.get(
|
||||
"/cmis/compat-tck/browser/root",
|
||||
params={"cmisselector": "children"},
|
||||
).json()
|
||||
fetched = cmis_client.get(
|
||||
"/cmis/compat-tck/browser/root",
|
||||
params={"cmisselector": "object", "objectId": folder_id},
|
||||
).json()
|
||||
parent = cmis_client.get(
|
||||
"/cmis/compat-tck/browser/root",
|
||||
params={"cmisselector": "parent", "objectId": folder_id},
|
||||
).json()
|
||||
document = cmis_client.post(
|
||||
"/cmis/compat-tck/browser/root",
|
||||
params={"objectId": folder_id},
|
||||
data={
|
||||
"cmisaction": "createDocument",
|
||||
"propertyId[0]": "cmis:objectTypeId",
|
||||
"propertyValue[0]": "cmis:document",
|
||||
"propertyId[1]": "cmis:name",
|
||||
"propertyValue[1]": "Multipart Document",
|
||||
},
|
||||
files={"content": ("multipart.txt", b"Multipart content", "text/plain")},
|
||||
)
|
||||
document_path = document.json()["properties"]["cmis:path"]["value"]
|
||||
fetched_document_by_path = cmis_client.get(
|
||||
"/cmis/compat-tck/browser/root",
|
||||
params={"cmisselector": "object", "path": document_path},
|
||||
).json()
|
||||
document_parents = cmis_client.get(
|
||||
"/cmis/compat-tck/browser/root",
|
||||
params={"cmisselector": "parents", "objectId": document.json()["properties"]["cmis:objectId"]["value"]},
|
||||
).json()
|
||||
fetched_folder_by_path = cmis_client.get(
|
||||
"/cmis/compat-tck/browser/root",
|
||||
params={"cmisselector": "object", "path": "/Action Workspace"},
|
||||
).json()
|
||||
deleted_tree = cmis_client.post(
|
||||
"/cmis/compat-tck/browser/root",
|
||||
data={"cmisaction": "deleteTree", "objectId": folder_id},
|
||||
)
|
||||
root_children_after_delete = cmis_client.get(
|
||||
"/cmis/compat-tck/browser/root",
|
||||
params={"cmisselector": "children"},
|
||||
).json()
|
||||
fetched_after_delete = cmis_client.get(
|
||||
"/cmis/compat-tck/browser/root",
|
||||
params={"cmisselector": "object", "objectId": folder_id},
|
||||
)
|
||||
deleted = cmis_client.post(
|
||||
"/cmis/compat-tck/browser",
|
||||
data={"cmisaction": "delete", "objectId": folder_id},
|
||||
)
|
||||
|
||||
assert created.status_code == 200
|
||||
assert folder["properties"]["cmis:name"]["value"] == "Action Workspace"
|
||||
assert folder["properties"]["kontextual:workspaceFolder"]["value"] is True
|
||||
assert folder["allowableActions"]["canDeleteTree"] is True
|
||||
assert any(item["object"]["properties"]["cmis:objectId"]["value"] == folder_id for item in root_children["objects"])
|
||||
assert fetched["properties"]["cmis:path"]["value"] == "/Action Workspace"
|
||||
assert parent["properties"]["cmis:objectId"]["value"] == "cmis-root"
|
||||
assert document.status_code == 200
|
||||
assert document.json()["properties"]["cmis:name"]["value"] == "Multipart Document"
|
||||
assert document.json()["properties"]["cmis:contentStreamLength"]["value"] == 17
|
||||
assert document.json()["properties"]["cmis:isLatestVersion"]["value"] is True
|
||||
assert document.json()["properties"]["cmis:secondaryObjectTypeIds"]["value"] == []
|
||||
assert document.json()["allowableActions"]["canGetFolderParent"] is False
|
||||
assert document_path == "/Action Workspace/Multipart Document"
|
||||
assert fetched_document_by_path["properties"]["cmis:name"]["value"] == "Multipart Document"
|
||||
assert document_parents[0]["object"]["properties"]["cmis:path"]["value"] == "/Action Workspace"
|
||||
assert fetched_folder_by_path["properties"]["cmis:objectId"]["value"] == folder_id
|
||||
assert deleted_tree.json()["failedToDelete"] == []
|
||||
assert all(
|
||||
item["object"]["properties"]["cmis:objectId"]["value"] != folder_id
|
||||
for item in root_children_after_delete["objects"]
|
||||
)
|
||||
assert fetched_after_delete.status_code == 404
|
||||
assert deleted.status_code == 404
|
||||
|
||||
|
||||
def test_cmis_readonly_route_rejects_mutation(cmis_client) -> None:
|
||||
response = cmis_client.post(
|
||||
"/cmis/readonly-browser/browser/document",
|
||||
json={"asset_id": "asset-api-readonly-denied", "name": "Denied"},
|
||||
)
|
||||
folder_response = cmis_client.post(
|
||||
"/cmis/readonly-browser/browser/root",
|
||||
data={
|
||||
"cmisaction": "createFolder",
|
||||
"propertyId[0]": "cmis:name",
|
||||
"propertyValue[0]": "Denied Folder",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 403
|
||||
assert folder_response.status_code == 403
|
||||
|
||||
|
||||
def test_cmis_rejects_unsupported_standard_property_update_with_diagnostics(cmis_client) -> None:
|
||||
|
||||
@@ -190,6 +190,58 @@ def test_runtime_cmis_governed_authoring_allows_selected_mutations(cmis_runtime)
|
||||
assert "CMIS object not found" in str(exc_info.value)
|
||||
|
||||
|
||||
def test_runtime_cmis_compat_profile_supports_workspace_folder_lifecycle(cmis_runtime) -> None:
|
||||
runtime, context = cmis_runtime
|
||||
|
||||
folder = runtime.cmis_create_folder(
|
||||
"compat-tck",
|
||||
{"name": "TCK Workspace", "properties": {"cmis:objectTypeId": "cmis:folder"}},
|
||||
context,
|
||||
)
|
||||
folder_object_id = folder["object_id"]
|
||||
root_children = runtime.cmis_children("compat-tck", context)
|
||||
fetched = runtime.cmis_object("compat-tck", folder_object_id, context)
|
||||
parents = runtime.cmis_object_parents("compat-tck", folder_object_id, context)
|
||||
document = runtime.cmis_create_document(
|
||||
"compat-tck",
|
||||
{
|
||||
"name": "Workspace Document",
|
||||
"folder_id": folder_object_id,
|
||||
"content": "Workspace content",
|
||||
"media_type": "text/plain",
|
||||
},
|
||||
context,
|
||||
)
|
||||
folder_children = runtime.cmis_children("compat-tck", context, folder_id=folder_object_id)
|
||||
document_by_path = runtime.cmis_object_by_path("compat-tck", "/TCK Workspace/Workspace Document", context)
|
||||
document_parents = runtime.cmis_object_parents("compat-tck", document["object_id"], context)
|
||||
|
||||
assert folder["path"] == "/TCK Workspace"
|
||||
assert folder["properties"]["kontextual:workspaceFolder"] is True
|
||||
assert folder_object_id in {item["object_id"] for item in root_children["objects"]}
|
||||
assert fetched["properties"]["cmis:path"] == "/TCK Workspace"
|
||||
assert parents["parents"][0]["object_id"] == "cmis-root"
|
||||
assert document["path"] == "/TCK Workspace/Workspace Document"
|
||||
assert document["properties"]["cmis:path"] == "/TCK Workspace/Workspace Document"
|
||||
assert document_by_path["object_id"] == document["object_id"]
|
||||
assert document_parents["count"] == 1
|
||||
assert document_parents["parents"][0]["properties"]["cmis:path"] == "/TCK Workspace"
|
||||
assert document["object_id"] in {item["object_id"] for item in folder_children["objects"]}
|
||||
|
||||
with pytest.raises(Exception) as exc_info:
|
||||
runtime.cmis_delete_object("compat-tck", folder_object_id, {}, context)
|
||||
assert "CMIS folder is not empty" in str(exc_info.value)
|
||||
|
||||
deleted_tree = runtime.cmis_delete_tree("compat-tck", folder_object_id, {}, context)
|
||||
root_children_after_delete = runtime.cmis_children("compat-tck", context)
|
||||
|
||||
assert deleted_tree["failedToDelete"] == []
|
||||
assert folder_object_id not in {item["object_id"] for item in root_children_after_delete["objects"]}
|
||||
with pytest.raises(Exception) as exc_info:
|
||||
runtime.cmis_object("compat-tck", folder_object_id, context)
|
||||
assert "CMIS folder not found" in str(exc_info.value)
|
||||
|
||||
|
||||
def test_runtime_cmis_rejects_unsupported_standard_property_updates(cmis_runtime) -> None:
|
||||
runtime, context = cmis_runtime
|
||||
|
||||
@@ -216,6 +268,15 @@ def test_runtime_cmis_readonly_profile_rejects_mutations(cmis_runtime) -> None:
|
||||
|
||||
assert "CMIS operation denied" in str(exc_info.value)
|
||||
|
||||
with pytest.raises(Exception) as exc_info:
|
||||
runtime.cmis_create_folder(
|
||||
"readonly-browser",
|
||||
{"name": "Denied Folder"},
|
||||
context,
|
||||
)
|
||||
|
||||
assert "CMIS operation denied" in str(exc_info.value)
|
||||
|
||||
|
||||
def test_runtime_cmis_acl_projection_and_redaction(cmis_runtime) -> None:
|
||||
runtime, context = cmis_runtime
|
||||
|
||||
Reference in New Issue
Block a user