Skip to content

Commit

Permalink
Merge branch 'main' into wip/fix-create-doap-for-class
Browse files Browse the repository at this point in the history
  • Loading branch information
jnussbaum authored Oct 25, 2024
2 parents 14146b1 + 19fbef8 commit 51c7bee
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 70 deletions.
31 changes: 17 additions & 14 deletions tests/test_ap_set.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
from typing import Any
from unittest.mock import Mock
from unittest.mock import patch

import pytest

from dsp_permissions_scripts.ap import ap_set
from dsp_permissions_scripts.ap.ap_model import ApValue
from dsp_permissions_scripts.ap.ap_set import create_new_ap_on_server
from dsp_permissions_scripts.models import group

PROJ_IRI = "http://rdfh.ch/projects/QykAkmHJTPS7ervbGynSHw"
PROJ_SHORTCODE = "0000"


@pytest.fixture
def create_new_ap_request() -> dict[str, Any]:
return {
"forGroup": "http://www.knora.org/ontology/knora-admin#Creator",
# surprisingly, it also works with "knora-admin:Creator", without context.
"forProject": "http://rdfh.ch/projects/QykAkmHJTPS7ervbGynSHw",
"forProject": PROJ_IRI,
"hasPermissions": [
{"additionalInformation": None, "name": "ProjectResourceCreateAllPermission", "permissionCode": None}
],
Expand All @@ -26,27 +29,27 @@ def create_new_ap_response() -> dict[str, Any]:
return {
"administrative_permission": {
"iri": "http://rdfh.ch/permissions/4123/8WIp72-IQeKjwL5y7cpNPQ",
"forProject": "http://rdfh.ch/projects/QykAkmHJTPS7ervbGynSHw",
"forProject": PROJ_IRI,
"forGroup": "http://www.knora.org/ontology/knora-admin#Creator",
"hasPermissions": [{"name": "ProjectResourceCreateAllPermission"}],
}
}


def test_create_new_ap_on_server(create_new_ap_request: dict[str, Any], create_new_ap_response: dict[str, Any]) -> None:
ap_set.get_proj_iri_and_onto_iris_by_shortcode = Mock( # type: ignore[attr-defined]
return_value=("http://rdfh.ch/projects/QykAkmHJTPS7ervbGynSHw", None)
)
ap_set.create_ap_from_admin_route_object = Mock() # type: ignore[attr-defined]
dsp_client = Mock()
dsp_client.post = Mock(return_value=create_new_ap_response)
@patch("dsp_permissions_scripts.ap.ap_set.get_proj_iri_and_onto_iris_by_shortcode", return_value=(PROJ_IRI, None))
@patch("dsp_permissions_scripts.ap.ap_set.create_ap_from_admin_route_object")
def test_create_new_ap_on_server(
create_ap_from_admin_route_object: Mock,
get_proj_iri_and_onto_iris_by_shortcode: Mock, # noqa: ARG001
create_new_ap_request: dict[str, Any],
create_new_ap_response: dict[str, Any],
) -> None:
dsp_client = Mock(post=Mock(return_value=create_new_ap_response))
_ = create_new_ap_on_server(
forGroup=group.CREATOR,
shortcode="0000",
shortcode=PROJ_SHORTCODE,
hasPermissions=[ApValue("ProjectResourceCreateAllPermission")],
dsp_client=dsp_client,
)
dsp_client.post.assert_called_once_with("/admin/permissions/ap", data=create_new_ap_request)
ap_set.create_ap_from_admin_route_object.assert_called_once_with( # type: ignore[attr-defined]
create_new_ap_response["administrative_permission"]
)
create_ap_from_admin_route_object.assert_called_once_with(create_new_ap_response["administrative_permission"])
84 changes: 41 additions & 43 deletions tests/test_oap_get.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from typing import Any
from unittest.mock import Mock
from unittest.mock import patch
from urllib.parse import quote

import pytest
from pytest_unordered import unordered

from dsp_permissions_scripts.models import group
from dsp_permissions_scripts.models.scope import PermissionScope
from dsp_permissions_scripts.oap import oap_get
from dsp_permissions_scripts.oap.oap_get import KB_RESCLASSES
from dsp_permissions_scripts.oap.oap_get import _get_oap_of_one_resource
from dsp_permissions_scripts.oap.oap_get import _get_oaps_of_one_kb_resclass
Expand All @@ -19,6 +19,11 @@
from dsp_permissions_scripts.oap.oap_model import ValueOap
from dsp_permissions_scripts.utils.dsp_client import DspClient

# ruff: noqa: PT019

_GET_OAPS_OF_SPECIFIED_KB_RESCLASSES = "dsp_permissions_scripts.oap.oap_get._get_oaps_of_specified_kb_resclasses"
_ENRICH_WITH_VALUE_OAPS = "dsp_permissions_scripts.oap.oap_get._enrich_with_value_oaps"


@pytest.fixture
def resource() -> dict[str, Any]:
Expand Down Expand Up @@ -373,8 +378,7 @@ def test_get_oap_of_one_resource_some_classes_some_values(resource: dict[str, An

class Test_get_oaps_of_one_kb_resclass:
def test_get_oaps_of_one_kb_resclass_0_results(self) -> None:
dsp_client = Mock(spec=DspClient)
dsp_client.get = Mock(side_effect=[{}])
dsp_client = Mock(spec=DspClient, get=Mock(side_effect=[{}]))
res = _get_oaps_of_one_kb_resclass(dsp_client, "proj_iri", "resclass")
assert res == []
assert len(dsp_client.get.call_args_list) == 1
Expand All @@ -385,8 +389,7 @@ def test_get_oaps_of_one_kb_resclass_0_results(self) -> None:
assert quote("OFFSET 0", safe="") in called_route

def test_get_oaps_of_one_kb_resclass_1_result(self, gravsearch_1_link_obj: dict[str, Any]) -> None:
dsp_client = Mock(spec=DspClient)
dsp_client.get = Mock(side_effect=[gravsearch_1_link_obj])
dsp_client = Mock(spec=DspClient, get=Mock(side_effect=[gravsearch_1_link_obj]))
res = _get_oaps_of_one_kb_resclass(dsp_client, "proj_iri", "resclass")
expected = Oap(
resource_oap=ResourceOap(
Expand All @@ -401,8 +404,7 @@ def test_get_oaps_of_one_kb_resclass_4_results_on_2_pages(
self,
gravsearch_4_link_objs_on_2_pages: list[dict[str, Any]],
) -> None:
dsp_client = Mock(spec=DspClient)
dsp_client.get = Mock(side_effect=gravsearch_4_link_objs_on_2_pages)
dsp_client = Mock(spec=DspClient, get=Mock(side_effect=gravsearch_4_link_objs_on_2_pages))
res = _get_oaps_of_one_kb_resclass(dsp_client, "proj_iri", "resclass")
expected_scope = PermissionScope.create(CR=[group.PROJECT_ADMIN], D=[group.PROJECT_MEMBER])
expected_res_oaps = [
Expand All @@ -421,64 +423,64 @@ def test_get_oaps_of_one_kb_resclass_4_results_on_2_pages(
assert quote("OFFSET 1", safe="") in called_route_2


@patch(_GET_OAPS_OF_SPECIFIED_KB_RESCLASSES, side_effect=[["res_only_oap_1", "res_only_oap_2"]])
@patch(_ENRICH_WITH_VALUE_OAPS, side_effect=[["enriched_oap_1", "enriched_oap_2"]])
class Test_get_oaps_of_kb_resclasses:
def test_get_oaps_of_kb_resclasses_all_resclasses_all_values(self) -> None:
oap_get._get_oaps_of_specified_kb_resclasses = Mock(side_effect=[["res_only_oap_1", "res_only_oap_2"]])
oap_get._enrich_with_value_oaps = Mock(side_effect=[["enriched_oap_1", "enriched_oap_2"]])
def test_get_oaps_of_kb_resclasses_all_resclasses_all_values(
self, _enrich_with_value_oaps: Mock, _get_oaps_of_specified_kb_resclasses: Mock
) -> None:
dsp_client = Mock(spec=DspClient)
oap_config = OapRetrieveConfig(
retrieve_resources="all",
retrieve_values="all",
)
_ = get_oaps_of_kb_resclasses(dsp_client, "proj_iri", oap_config)
oap_get._get_oaps_of_specified_kb_resclasses.assert_called_once_with(dsp_client, "proj_iri", KB_RESCLASSES)
oap_get._enrich_with_value_oaps.assert_called_once_with(dsp_client, ["res_only_oap_1", "res_only_oap_2"])
_get_oaps_of_specified_kb_resclasses.assert_called_once_with(dsp_client, "proj_iri", KB_RESCLASSES)
_enrich_with_value_oaps.assert_called_once_with(dsp_client, ["res_only_oap_1", "res_only_oap_2"])

def test_get_oaps_of_kb_resclasses_all_resclasses_specified_values(self) -> None:
oap_get._get_oaps_of_specified_kb_resclasses = Mock(side_effect=[["res_only_oap_1", "res_only_oap_2"]])
oap_get._enrich_with_value_oaps = Mock(side_effect=[["enriched_oap_1", "enriched_oap_2"]])
def test_get_oaps_of_kb_resclasses_all_resclasses_specified_values(
self, _enrich_with_value_oaps: Mock, _get_oaps_of_specified_kb_resclasses: Mock
) -> None:
dsp_client = Mock(spec=DspClient)
oap_config = OapRetrieveConfig(
retrieve_resources="all",
retrieve_values="specified_props",
specified_props=["onto:prop_1", "onto:prop_2"],
)
_ = get_oaps_of_kb_resclasses(dsp_client, "proj_iri", oap_config)
oap_get._get_oaps_of_specified_kb_resclasses.assert_called_once_with(dsp_client, "proj_iri", KB_RESCLASSES)
oap_get._enrich_with_value_oaps.assert_called_once_with(
_get_oaps_of_specified_kb_resclasses.assert_called_once_with(dsp_client, "proj_iri", KB_RESCLASSES)
_enrich_with_value_oaps.assert_called_once_with(
dsp_client, ["res_only_oap_1", "res_only_oap_2"], ["onto:prop_1", "onto:prop_2"]
)

def test_get_oaps_of_kb_resclasses_all_resclasses_no_values(self) -> None:
oap_get._get_oaps_of_specified_kb_resclasses = Mock(side_effect=[["res_only_oap_1", "res_only_oap_2"]])
oap_get._enrich_with_value_oaps = Mock(side_effect=[["enriched_oap_1", "enriched_oap_2"]])
def test_get_oaps_of_kb_resclasses_all_resclasses_no_values(
self, _enrich_with_value_oaps: Mock, _get_oaps_of_specified_kb_resclasses: Mock
) -> None:
dsp_client = Mock(spec=DspClient)
oap_config = OapRetrieveConfig(
retrieve_resources="all",
retrieve_values="none",
)
_ = get_oaps_of_kb_resclasses(dsp_client, "proj_iri", oap_config)
oap_get._get_oaps_of_specified_kb_resclasses.assert_called_once_with(dsp_client, "proj_iri", KB_RESCLASSES)
oap_get._enrich_with_value_oaps.assert_not_called()
_get_oaps_of_specified_kb_resclasses.assert_called_once_with(dsp_client, "proj_iri", KB_RESCLASSES)
_enrich_with_value_oaps.assert_not_called()

def test_get_oaps_of_kb_resclasses_some_resclasses_all_values(self) -> None:
oap_get._get_oaps_of_specified_kb_resclasses = Mock(side_effect=[["res_only_oap_1", "res_only_oap_2"]])
oap_get._enrich_with_value_oaps = Mock(side_effect=[["enriched_oap_1", "enriched_oap_2"]])
def test_get_oaps_of_kb_resclasses_some_resclasses_all_values(
self, _enrich_with_value_oaps: Mock, _get_oaps_of_specified_kb_resclasses: Mock
) -> None:
dsp_client = Mock(spec=DspClient)
oap_config = OapRetrieveConfig(
retrieve_resources="specified_res_classes",
specified_res_classes=["knora-api:Region", "custom-onto:foo"],
retrieve_values="all",
)
_ = get_oaps_of_kb_resclasses(dsp_client, "proj_iri", oap_config)
oap_get._get_oaps_of_specified_kb_resclasses.assert_called_once_with(
dsp_client, "proj_iri", ["knora-api:Region"]
)
oap_get._enrich_with_value_oaps.assert_called_once_with(dsp_client, ["res_only_oap_1", "res_only_oap_2"])
_get_oaps_of_specified_kb_resclasses.assert_called_once_with(dsp_client, "proj_iri", ["knora-api:Region"])
_enrich_with_value_oaps.assert_called_once_with(dsp_client, ["res_only_oap_1", "res_only_oap_2"])

def test_get_oaps_of_kb_resclasses_some_resclasses_some_values(self) -> None:
oap_get._get_oaps_of_specified_kb_resclasses = Mock(side_effect=[["res_only_oap_1", "res_only_oap_2"]])
oap_get._enrich_with_value_oaps = Mock(side_effect=[["enriched_oap_1", "enriched_oap_2"]])
def test_get_oaps_of_kb_resclasses_some_resclasses_some_values(
self, _enrich_with_value_oaps: Mock, _get_oaps_of_specified_kb_resclasses: Mock
) -> None:
dsp_client = Mock(spec=DspClient)
oap_config = OapRetrieveConfig(
retrieve_resources="specified_res_classes",
Expand All @@ -487,24 +489,20 @@ def test_get_oaps_of_kb_resclasses_some_resclasses_some_values(self) -> None:
specified_props=["onto:prop_1", "onto:prop_2"],
)
_ = get_oaps_of_kb_resclasses(dsp_client, "proj_iri", oap_config)
oap_get._get_oaps_of_specified_kb_resclasses.assert_called_once_with(
dsp_client, "proj_iri", ["knora-api:Region"]
)
oap_get._enrich_with_value_oaps.assert_called_once_with(
_get_oaps_of_specified_kb_resclasses.assert_called_once_with(dsp_client, "proj_iri", ["knora-api:Region"])
_enrich_with_value_oaps.assert_called_once_with(
dsp_client, ["res_only_oap_1", "res_only_oap_2"], ["onto:prop_1", "onto:prop_2"]
)

def test_get_oaps_of_kb_resclasses_some_resclasses_no_values(self) -> None:
oap_get._get_oaps_of_specified_kb_resclasses = Mock(side_effect=[["res_only_oap_1", "res_only_oap_2"]])
oap_get._enrich_with_value_oaps = Mock(side_effect=[["enriched_oap_1", "enriched_oap_2"]])
def test_get_oaps_of_kb_resclasses_some_resclasses_no_values(
self, _enrich_with_value_oaps: Mock, _get_oaps_of_specified_kb_resclasses: Mock
) -> None:
dsp_client = Mock(spec=DspClient)
oap_config = OapRetrieveConfig(
retrieve_resources="specified_res_classes",
specified_res_classes=["knora-api:Region", "custom-onto:foo"],
retrieve_values="none",
)
_ = get_oaps_of_kb_resclasses(dsp_client, "proj_iri", oap_config)
oap_get._get_oaps_of_specified_kb_resclasses.assert_called_once_with(
dsp_client, "proj_iri", ["knora-api:Region"]
)
oap_get._enrich_with_value_oaps.assert_not_called()
_get_oaps_of_specified_kb_resclasses.assert_called_once_with(dsp_client, "proj_iri", ["knora-api:Region"])
_enrich_with_value_oaps.assert_not_called()
39 changes: 26 additions & 13 deletions tests/test_oap_update_iris.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from typing import Any
from unittest.mock import Mock
from unittest.mock import patch

import pytest

from dsp_permissions_scripts.models.errors import InvalidIRIError
from dsp_permissions_scripts.models.group import PROJECT_ADMIN
from dsp_permissions_scripts.models.scope import PermissionScope
from dsp_permissions_scripts.oap import update_iris
from dsp_permissions_scripts.oap.oap_model import ValueOap
from dsp_permissions_scripts.oap.update_iris import IRIUpdater
from dsp_permissions_scripts.oap.update_iris import ResourceIRIUpdater
Expand Down Expand Up @@ -94,14 +94,17 @@ def test_factory_with_invalid_iri() -> None:
IRIUpdater.from_string(inv, dsp_client)


def test_ResourceIRIUpdater(res_dict_2_props: dict[str, Any]) -> None:
@patch("dsp_permissions_scripts.oap.update_iris.update_permissions_for_resource")
def test_ResourceIRIUpdater(
update_permissions_for_resource: Mock,
res_dict_2_props: dict[str, Any],
) -> None:
dsp_client = Mock(spec_set=DspClient, get=Mock(return_value=res_dict_2_props))
update_iris.update_permissions_for_resource = Mock() # type: ignore[attr-defined]
new_scope = PermissionScope.create(D=[PROJECT_ADMIN])
res_iri = "http://rdfh.ch/4123/2ETqDXKeRrS5JSd6TxFO5g"
IRIUpdater.from_string(res_iri, dsp_client).update_iri(new_scope)
dsp_client.get.assert_called_once_with("/v2/resources/http%3A%2F%2Frdfh.ch%2F4123%2F2ETqDXKeRrS5JSd6TxFO5g")
update_iris.update_permissions_for_resource.assert_called_once_with( # type: ignore[attr-defined]
update_permissions_for_resource.assert_called_once_with(
resource_iri=res_iri,
lmd=res_dict_2_props["knora-api:lastModificationDate"],
resource_type=res_dict_2_props["@type"],
Expand All @@ -111,9 +114,12 @@ def test_ResourceIRIUpdater(res_dict_2_props: dict[str, Any]) -> None:
)


def test_ValueIRIUpdater_2_props(res_dict_2_props: dict[str, Any]) -> None:
@patch("dsp_permissions_scripts.oap.update_iris.update_permissions_for_value")
def test_ValueIRIUpdater_2_props(
update_permissions_for_value: Mock,
res_dict_2_props: dict[str, Any],
) -> None:
dsp_client = Mock(spec_set=DspClient, get=Mock(return_value=res_dict_2_props))
update_iris.update_permissions_for_value = Mock() # type: ignore[attr-defined]
val_oap = ValueOap(
scope=PermissionScope.create(D=[PROJECT_ADMIN]),
property="testonto:hasOtherText",
Expand All @@ -123,17 +129,20 @@ def test_ValueIRIUpdater_2_props(res_dict_2_props: dict[str, Any]) -> None:
)
IRIUpdater.from_string(val_oap.value_iri, dsp_client).update_iri(val_oap.scope)
dsp_client.get.assert_called_once_with("/v2/resources/http%3A%2F%2Frdfh.ch%2F4123%2FQDdiwk_3Rk--N2dzsSPOdw")
update_iris.update_permissions_for_value.assert_called_once_with( # type: ignore[attr-defined]
update_permissions_for_value.assert_called_once_with(
value=val_oap,
resource_type=res_dict_2_props["@type"],
context=res_dict_2_props["@context"] | {"knora-admin": KNORA_ADMIN_ONTO_NAMESPACE},
dsp_client=dsp_client,
)


def test_ValueIRIUpdater_2_vals(res_dict_2_vals: dict[str, Any]) -> None:
@patch("dsp_permissions_scripts.oap.update_iris.update_permissions_for_value")
def test_ValueIRIUpdater_2_vals(
update_permissions_for_value: Mock,
res_dict_2_vals: dict[str, Any],
) -> None:
dsp_client = Mock(spec_set=DspClient, get=Mock(return_value=res_dict_2_vals))
update_iris.update_permissions_for_value = Mock() # type: ignore[attr-defined]
val_oap = ValueOap(
scope=PermissionScope.create(D=[PROJECT_ADMIN]),
property="testonto:hasSimpleText",
Expand All @@ -143,22 +152,26 @@ def test_ValueIRIUpdater_2_vals(res_dict_2_vals: dict[str, Any]) -> None:
)
IRIUpdater.from_string(val_oap.value_iri, dsp_client).update_iri(val_oap.scope)
dsp_client.get.assert_called_once_with("/v2/resources/http%3A%2F%2Frdfh.ch%2F4123%2FQDdiwk_3Rk--N2dzsSPOdw")
update_iris.update_permissions_for_value.assert_called_once_with( # type: ignore[attr-defined]
update_permissions_for_value.assert_called_once_with(
value=val_oap,
resource_type=res_dict_2_vals["@type"],
context=res_dict_2_vals["@context"] | {"knora-admin": KNORA_ADMIN_ONTO_NAMESPACE},
dsp_client=dsp_client,
)


def test_ValueIRIUpdater_invalid_iri(res_dict_2_vals: dict[str, Any], caplog: pytest.LogCaptureFixture) -> None:
@patch("dsp_permissions_scripts.oap.update_iris.update_permissions_for_value")
def test_ValueIRIUpdater_invalid_iri(
update_permissions_for_value: Mock,
res_dict_2_vals: dict[str, Any],
caplog: pytest.LogCaptureFixture,
) -> None:
"""test what happens if a value IRI is provided that is not part of the current resource"""
dsp_client = Mock(spec_set=DspClient, get=Mock(return_value=res_dict_2_vals))
update_iris.update_permissions_for_value = Mock() # type: ignore[attr-defined]
val_iri = "http://rdfh.ch/4123/QDdiwk_3Rk--N2dzsSPOdw/values/eD0ii5mIS9y18M6fMy1Fkw"
IRIUpdater.from_string(val_iri, dsp_client).update_iri(PermissionScope.create(D=[PROJECT_ADMIN]))
dsp_client.get.assert_called_once_with("/v2/resources/http%3A%2F%2Frdfh.ch%2F4123%2FQDdiwk_3Rk--N2dzsSPOdw")
update_iris.update_permissions_for_value.assert_not_called() # type: ignore[attr-defined]
update_permissions_for_value.assert_not_called()
assert len(caplog.records) == 1
log_msg_expected = f"Could not find value {val_iri} in resource http://rdfh.ch/4123/QDdiwk_3Rk--N2dzsSPOdw"
assert caplog.records[0].message == log_msg_expected

0 comments on commit 51c7bee

Please sign in to comment.