diff --git a/tests/test_communities/conftest.py b/tests/test_communities/conftest.py index bc6d31a..44ab5d2 100644 --- a/tests/test_communities/conftest.py +++ b/tests/test_communities/conftest.py @@ -1,6 +1,6 @@ import copy import os - +from thesis.proxies import current_service import pytest import yaml from flask_security import login_user @@ -47,8 +47,8 @@ from oarepo_communities.services.permissions.policy import ( CommunityDefaultWorkflowPermissions, ) -from tests.test_communities.utils import link_api2testclient - +from tests.test_communities.utils import link2testclient +from deepmerge import always_merger @pytest.fixture(scope="function") def sample_metadata_list(): @@ -545,8 +545,6 @@ def create_community(slug, community_owner, workflow="default"): return create_community - -# ----- from invenio_requests.customizations import RequestType from invenio_requests.proxies import current_requests @@ -557,58 +555,6 @@ def requests_service(app): return current_requests.requests_service - -@pytest.fixture() -def create_publish_request(requests_service): - """Request Factory fixture.""" - - def _create_request(identity, receiver, **kwargs): - """Create a request.""" - RequestType.allowed_receiver_ref_types = ["community"] - RequestType.needs_context = { - "community_permission_name": "can_publish", - } - # Need to use the service to get the id - item = requests_service.create( - identity=identity, - data={}, - request_type=RequestType, - receiver=receiver, - **kwargs, - ) - return item._request - - return _create_request - - -# ----- -from thesis.proxies import current_service - - -@pytest.fixture(scope="function") -def sample_draft(app, db, input_data, community): - input_data["community_id"] = community.id - draft_item = current_service.create(system_identity, input_data) - ThesisDraft.index.refresh() - return ThesisDraft.pid.resolve(draft_item.id, registered_only=False) - - -@pytest.fixture -def request_data_factory(): - def _request_data( - community_id, topic_type, topic_id, request_type, creator=None, payload=None - ): - input_data = { - "request_type": request_type, - "topic": {topic_type: topic_id}, - } - if payload: - input_data["payload"] = payload - return input_data - - return _request_data - - @pytest.fixture def ui_serialized_community_role(): def _ui_serialized_community(community_id): @@ -693,8 +639,8 @@ def get_request_type(): def _get_request_type(request_types_json, request_type): selected_entry = [ entry for entry in request_types_json if entry["type_id"] == request_type - ][0] - return selected_entry + ] + return selected_entry[0] if selected_entry else None return _get_request_type @@ -707,49 +653,102 @@ def get_request_link(get_request_type): def _create_request_from_link(request_types_json, request_type): selected_entry = get_request_type(request_types_json, request_type) - return selected_entry["links"]["actions"]["create"] + return selected_entry["links"]["actions"]["create"] if selected_entry else None return _create_request_from_link +@pytest.fixture() +def clear_babel_context(): + + # force babel reinitialization when language is switched + def _clear_babel_context(): + try: + from flask import g + from flask_babel import SimpleNamespace + + g._flask_babel = SimpleNamespace() + except ImportError: + return + + return _clear_babel_context + + +@pytest.fixture() +def request_type_additional_data(): + return {"publish_draft": {"payload": {"version": "1.0"}}} + + @pytest.fixture -def create_request_by_link(get_request_link): - def _create_request(client, record, request_type): +def create_request_by_link(get_request_link, request_type_additional_data): + def _create_request( + client, record, request_type, additional_data=None, **request_kwargs + ): + if additional_data is None: + additional_data = {} applicable_requests = client.get( - link_api2testclient(record.json["links"]["applicable-requests"]) + link2testclient(record.json["links"]["applicable-requests"]) ).json["hits"]["hits"] - create_link = link_api2testclient( + create_link = link2testclient( get_request_link(applicable_requests, request_type) ) - create_response = client.post(create_link) + if request_type in request_type_additional_data: + additional_data = always_merger.merge( + additional_data, request_type_additional_data[request_type] + ) + if not additional_data: + create_response = client.post(create_link, **request_kwargs) + else: + create_response = client.post( + create_link, json=additional_data, **request_kwargs + ) return create_response return _create_request + @pytest.fixture def submit_request_by_link(create_request_by_link): - def _submit_request(client, record, request_type): - create_response = create_request_by_link(client, record, request_type) + def _submit_request( + client, + record, + request_type, + create_additional_data=None, + submit_additional_data=None, + ): + create_response = create_request_by_link( + client, record, request_type, additional_data=create_additional_data + ) submit_response = client.post( - link_api2testclient(create_response.json["links"]["actions"]["submit"]) + link2testclient(create_response.json["links"]["actions"]["submit"]), + json=submit_additional_data, ) return submit_response return _submit_request +@pytest.fixture +def draft_in_community(): + def _draft_in_community(client, comm_id, custom_workflow=None): + if custom_workflow: + return client.post( + f"/communities/{comm_id}/thesis", + json={"parent": {"workflow": custom_workflow}}, + ) -@pytest.fixture() -def clear_babel_context(): + return client.post(f"/communities/{comm_id}/thesis", json={}) + return _draft_in_community - # force babel reinitialization when language is switched - def _clear_babel_context(): - try: - from flask import g - from flask_babel import SimpleNamespace +@pytest.fixture +def published_record_in_community(record_service, draft_in_community): + # skip the request approval + def _published_record_in_community(client, community_id, custom_workflow=None): + response = draft_in_community(client, community_id, custom_workflow) + record_item = record_service.publish(system_identity, response.json["id"]) + ret = client.get(f"/thesis/{record_item['id']}") + return ret + return _published_record_in_community - g._flask_babel = SimpleNamespace() - except ImportError: - return - return _clear_babel_context +# todo - idea - oarepo-pytest library or something for these fixtures so we don't have to redefine them each time? diff --git a/tests/test_communities/test_community_records.py b/tests/test_communities/test_community_records.py index 47c7f03..b144382 100644 --- a/tests/test_communities/test_community_records.py +++ b/tests/test_communities/test_community_records.py @@ -1,8 +1,5 @@ from thesis.records.api import ThesisDraft, ThesisRecord -from tests.test_communities.utils import published_record_in_community - - def test_create_record_in_community( logged_client, community_owner, @@ -45,6 +42,7 @@ def test_search( community_owner, community_reader, community_with_workflow_factory, + published_record_in_community, record_service, search_clear, ): @@ -53,12 +51,8 @@ def test_search( community_1 = community_with_workflow_factory("comm1", community_owner) community_2 = community_with_workflow_factory("comm2", community_owner) - record1 = published_record_in_community( - owner_client, community_1.id, record_service, community_owner - ) - record2 = published_record_in_community( - owner_client, community_2.id, record_service, community_owner - ) + record1 = published_record_in_community(owner_client, community_1.id) + record2 = published_record_in_community(owner_client, community_2.id) ThesisRecord.index.refresh() ThesisDraft.index.refresh() @@ -76,8 +70,8 @@ def test_search( assert len(response_draft1.json["hits"]["hits"]) == 1 assert len(response_draft2.json["hits"]["hits"]) == 1 - assert response_record1.json["hits"]["hits"][0]["id"] == record1["id"] - assert response_record2.json["hits"]["hits"][0]["id"] == record2["id"] + assert response_record1.json["hits"]["hits"][0]["id"] == record1.json["id"] + assert response_record2.json["hits"]["hits"][0]["id"] == record2.json["id"] # todo tests for search links @@ -88,6 +82,7 @@ def test_search_model( community_owner, community_reader, community_with_workflow_factory, + published_record_in_community, record_service, search_clear, ): @@ -96,12 +91,8 @@ def test_search_model( community_1 = community_with_workflow_factory("comm1", community_owner) community_2 = community_with_workflow_factory("comm2", community_owner) - record1 = published_record_in_community( - owner_client, community_1.id, record_service, community_owner - ) - record2 = published_record_in_community( - owner_client, community_2.id, record_service, community_owner - ) + record1 = published_record_in_community(owner_client, community_1.id) + record2 = published_record_in_community(owner_client, community_2.id) ThesisRecord.index.refresh() ThesisDraft.index.refresh() @@ -112,8 +103,8 @@ def test_search_model( assert len(response_record1.json["hits"]["hits"]) == 1 assert len(response_record2.json["hits"]["hits"]) == 1 - assert response_record1.json["hits"]["hits"][0]["id"] == record1["id"] - assert response_record2.json["hits"]["hits"][0]["id"] == record2["id"] + assert response_record1.json["hits"]["hits"][0]["id"] == record1.json["id"] + assert response_record2.json["hits"]["hits"][0]["id"] == record2.json["id"] def test_user_search( @@ -192,6 +183,7 @@ def test_search_links( community_owner, community_reader, community_with_workflow_factory, + published_record_in_community, record_service, search_clear, site_hostname="127.0.0.1:5000", @@ -201,9 +193,7 @@ def test_search_links( community_1 = community_with_workflow_factory("comm1", community_owner) for _ in range(30): - published_record_in_community( - owner_client, community_1.id, record_service, community_owner - ) + published_record_in_community(owner_client, community_1.id) ThesisRecord.index.refresh() def check_links(model_suffix): @@ -251,6 +241,7 @@ def test_search_ui_serialization( community_owner, community_reader, community_with_workflow_factory, + published_record_in_community, record_service, inviter, search_clear, @@ -262,12 +253,8 @@ def test_search_ui_serialization( community_2 = community_with_workflow_factory("comm2", community_owner) inviter("2", community_1.id, "reader") - record1 = published_record_in_community( - owner_client, community_1.id, record_service, community_owner - ) - record2 = published_record_in_community( - owner_client, community_2.id, record_service, community_owner - ) + record1 = published_record_in_community(owner_client, community_1.id) + record2 = published_record_in_community(owner_client, community_2.id) ThesisRecord.index.refresh() ThesisDraft.index.refresh() diff --git a/tests/test_communities/test_community_requests.py b/tests/test_communities/test_community_requests.py index 312d1c6..1e589a5 100644 --- a/tests/test_communities/test_community_requests.py +++ b/tests/test_communities/test_community_requests.py @@ -1,77 +1,21 @@ import pytest +from .utils import link2testclient from oarepo_communities.errors import ( CommunityAlreadyIncludedException, CommunityNotIncludedException, PrimaryCommunityException, ) -from tests.test_communities.utils import ( - _create_record_in_community, - published_record_in_community, -) REPO_NAME = "thesis" -# todo we should have unified framework for naming kwargs in permissions; it's chaos now -# ie. we "record", "parent", "community", "community_id" should always represent the same entity, not record=community record etc. -def link_api2testclient(api_link): - base_string = "https://127.0.0.1:5000/api/" - return api_link[len(base_string) - 1 :] - - def find_request_by_type(requests, type): for request in requests: if request["type"] == type: return request return None - -def _create_request( - creator_client, - community_id, - record_type, - record_id, - request_type, - request_data_func, - **kwargs, -): - request_data = request_data_func( - community_id, record_type, record_id, request_type, **kwargs - ) - create_response = creator_client.post("/requests/", json=request_data) - return create_response - - -def _submit_request( - creator_client, - community_id, - record_type, - record_id, - request_type, - request_data_func, - **kwargs, -): - create_response = _create_request( - creator_client, - community_id, - record_type, - record_id, - request_type, - request_data_func, - **kwargs, - ) - - submit_response = creator_client.post( - link_api2testclient(create_response.json["links"]["actions"]["submit"]) - ) - if submit_response.status == 400: - creator_client.post( - link_api2testclient(create_response.json["links"]["actions"]["submit"]) - ) - return submit_response - - def _accept_request( receiver_client, type, @@ -92,7 +36,7 @@ def _accept_request( if no_accept_link: assert "accept" not in request_dict["links"]["actions"] return None - accept_link = link_api2testclient(request_dict["links"]["actions"]["accept"]) + accept_link = link2testclient(request_dict["links"]["actions"]["accept"]) receiver_response = receiver_client.post(accept_link) return receiver_response @@ -120,21 +64,17 @@ def test_community_publish( community_owner, community_reader, community, - request_data_factory, - record_service, + draft_in_community, + submit_request_by_link, search_clear, ): reader_client = logged_client(community_reader) owner_client = logged_client(community_owner) - record_id = _create_record_in_community(reader_client, community.id).json["id"] - submit = _submit_request( - reader_client, - community.id, - "thesis_draft", - record_id, - "publish_draft", - request_data_factory, + record = draft_in_community(reader_client, community.id) + record_id = record.json["id"] + submit = submit_request_by_link( + reader_client, record, "publish_draft" ) _accept_request( reader_client, @@ -155,39 +95,34 @@ def test_community_publish( assert resp_record.status_code == 200 + def test_community_delete( logged_client, community_owner, community_reader, community, - request_data_factory, - record_service, + published_record_in_community, + submit_request_by_link, search_clear, ): reader_client = logged_client(community_reader) owner_client = logged_client(community_owner) - record_id = published_record_in_community( + record = published_record_in_community( reader_client, - community.id, - record_service, - community_owner, - )["id"] + community.id + ) + record_id = record.json["id"] - submit = _submit_request( - reader_client, - community.id, - "thesis", - record_id, - "delete_published_record", - request_data_factory, + submit = submit_request_by_link( + reader_client, record, "delete_published_record" ) _accept_request( reader_client, type="delete_published_record", record_id=record_id, no_accept_link=True, - ) # reader can accept the request + ) # reader can't accept the request accept_owner = _accept_request( owner_client, type="delete_published_record", record_id=record_id ) # owner can @@ -205,8 +140,8 @@ def test_community_migration( community_owner, community_reader, community_with_workflow_factory, - request_data_factory, - record_service, + published_record_in_community, + submit_request_by_link, inviter, search_clear, ): @@ -218,20 +153,13 @@ def test_community_migration( inviter, ) - record_id = published_record_in_community( - reader_client, community_1.id, record_service, community_owner - )["id"] - record_before = reader_client.get(f"/thesis/{record_id}") - - submit = _submit_request( - reader_client, - community_2.id, - "thesis", - record_id, - "initiate_community_migration", - request_data_factory, - payload={"community": str(community_2.id)}, + record = published_record_in_community( + reader_client, community_1.id ) + record_id = record.json["id"] + record_before = reader_client.get(f"/thesis/{record_id}") + submit = submit_request_by_link(reader_client, record, "initiate_community_migration", + create_additional_data={"payload":{"community": str(community_2.id)}}) _accept_request( reader_client, type="initiate_community_migration", @@ -264,8 +192,9 @@ def test_community_submission_secondary( community_reader, community_with_workflow_factory, inviter, - request_data_factory, - record_service, + published_record_in_community, + create_request_by_link, + submit_request_by_link, search_clear, ): reader_client, owner_client, community_1, community_2 = _init_env( @@ -275,31 +204,17 @@ def test_community_submission_secondary( community_with_workflow_factory, inviter, ) - record_id = published_record_in_community( - reader_client, community_1.id, record_service, community_owner - )["id"] + record = published_record_in_community( + reader_client, community_1.id + ) + record_id = record.json["id"] record_before = owner_client.get(f"/thesis/{record_id}") with pytest.raises(CommunityAlreadyIncludedException): - _create_request( - reader_client, - community_1.id, - "thesis", - record_id, - "secondary_community_submission", - request_data_factory, - payload={"community": str(community_1.id)}, - ) - - submit = _submit_request( - reader_client, - community_2.id, - "thesis", - record_id, - "secondary_community_submission", - request_data_factory, - payload={"community": str(community_2.id)}, - ) + create_request_by_link(reader_client, record, "secondary_community_submission", + additional_data={"payload": {"community": str(community_1.id)}}) + submit = submit_request_by_link(reader_client, record, "secondary_community_submission", + create_additional_data={"payload": {"community": str(community_2.id)}}) _accept_request( reader_client, type="secondary_community_submission", @@ -326,8 +241,10 @@ def test_remove_secondary( community_reader, community_with_workflow_factory, inviter, - request_data_factory, - record_service, + published_record_in_community, + create_request_by_link, + submit_request_by_link, + get_request_type, search_clear, ): reader_client, owner_client, community_1, community_2 = _init_env( @@ -338,52 +255,33 @@ def test_remove_secondary( inviter, ) - record_id = published_record_in_community( - reader_client, community_1.id, record_service, community_owner - )["id"] - - submit = _submit_request( - reader_client, - community_2.id, - "thesis", - record_id, - "secondary_community_submission", - request_data_factory, - payload={"community": str(community_2.id)}, + record = published_record_in_community( + reader_client, community_1.id ) + record_id = record.json["id"] + submit_request_by_link(reader_client, record, "secondary_community_submission", + create_additional_data={"payload": {"community": str(community_2.id)}}) accept_owner = _accept_request( owner_client, type="secondary_community_submission", record_id=record_id ) record_before = owner_client.get(f"/thesis/{record_id}") + # todo this should not work - it should not produce a link with pytest.raises(PrimaryCommunityException): - _create_request( - reader_client, - community_1.id, - "thesis", - record_id, - "remove_secondary_community", - request_data_factory, - payload={"community": str(community_1.id)}, - ) + create_request_by_link(reader_client, record, "remove_secondary_community", + additional_data={"payload": {"community": str(community_1.id)}}) - submit = _submit_request( - reader_client, - community_2.id, - "thesis", - record_id, - "remove_secondary_community", - request_data_factory, - payload={"community": str(community_2.id)}, - ) + + submit_request_by_link(reader_client, record, "remove_secondary_community", + create_additional_data={"payload": {"community": str(community_2.id)}}) _accept_request( reader_client, type="remove_secondary_community", record_id=record_id, no_accept_link=True, - ) # reader can accept the request + ) # reader can't accept the request accept_owner = _accept_request( owner_client, type="remove_secondary_community", record_id=record_id ) # owner can @@ -395,16 +293,14 @@ def test_remove_secondary( } assert set(record_after.json["parent"]["communities"]["ids"]) == {community_1.id} + # assert link is not present + applicable_requests = reader_client.get( + link2testclient(record.json["links"]["applicable-requests"]) + ).json["hits"]["hits"] + assert get_request_type(applicable_requests, "remove_secondary_community") is None with pytest.raises(CommunityNotIncludedException): - _create_request( - reader_client, - community_2.id, - "thesis", - record_id, - "remove_secondary_community", - request_data_factory, - payload={"community": str(community_2.id)}, - ) + reader_client.post(f"/thesis/{record_id}/requests/remove_secondary_community", + json={"payload": {"community": str(community_2.id)}}) def test_community_role_ui_serialization( @@ -412,25 +308,20 @@ def test_community_role_ui_serialization( community_owner, community_reader, community, - request_data_factory, - record_service, + draft_in_community, + submit_request_by_link, ui_serialized_community_role, search_clear, ): reader_client = logged_client(community_reader) owner_client = logged_client(community_owner) - record_id = _create_record_in_community(reader_client, community.id).json["id"] - - submit = _submit_request( - reader_client, - community.id, - "thesis_draft", - record_id, - "publish_draft", - request_data_factory, + record = draft_in_community( + reader_client, community.id ) + submit = submit_request_by_link(reader_client, record, "publish_draft") + def compare_result(result): assert result.items() >= ui_serialized_community_role(community.id).items() assert ( diff --git a/tests/test_communities/test_permissions.py b/tests/test_communities/test_permissions.py index f20d76f..2fd8743 100644 --- a/tests/test_communities/test_permissions.py +++ b/tests/test_communities/test_permissions.py @@ -4,9 +4,7 @@ from invenio_communities.proxies import current_communities from tests.test_communities.utils import ( - _create_record_in_community, - link_api2testclient, - published_record_in_community, + link2testclient, ) @@ -14,6 +12,7 @@ def test_disabled_endpoints( logged_client, community_owner, community_with_workflow_factory, + published_record_in_community, record_service, default_workflow_json, search_clear, @@ -28,12 +27,10 @@ def test_disabled_endpoints( draft = owner_client.post( f"/communities/{community_1.id}/thesis", json=default_workflow_json ).json - published_record = published_record_in_community( - owner_client, community_1.id, record_service, community_owner - ) + published_record = published_record_in_community(owner_client, community_1.id) publish = owner_client.post(f"/thesis/{draft['id']}/draft/actions/publish") - delete = owner_client.delete(f"/thesis/{published_record['id']}") + delete = owner_client.delete(f"/thesis/{published_record.json['id']}") assert publish.status_code == 403 assert delete.status_code == 403 @@ -61,6 +58,7 @@ def test_scenario_change( inviter, set_community_workflow, service_config, + draft_in_community, search_clear, ): owner_client = logged_client(community_owner) @@ -74,23 +72,23 @@ def test_scenario_change( inviter("2", community_1.id, "reader") inviter("2", community_2.id, "reader") - record1 = _create_record_in_community(owner_client, community_1.id) - record2 = _create_record_in_community(owner_client, community_2.id) - record4 = _create_record_in_community(reader_client, community_1.id) + record1 = draft_in_community(owner_client, community_1.id) + record2 = draft_in_community(owner_client, community_2.id) + record4 = draft_in_community(reader_client, community_1.id) request_should_be_allowed = owner_client.post( f"/thesis/{record1.json['id']}/draft/requests/publish_draft" ) submit = owner_client.post( - link_api2testclient( + link2testclient( request_should_be_allowed.json["links"]["actions"]["submit"] ) ) accept_should_be_denied = reader_client.post( - link_api2testclient(submit.json["links"]["actions"]["accept"]) + link2testclient(submit.json["links"]["actions"]["accept"]) ) accept = owner_client.post( - link_api2testclient(submit.json["links"]["actions"]["accept"]) + link2testclient(submit.json["links"]["actions"]["accept"]) ) assert accept_should_be_denied.status_code == 403 assert request_should_be_allowed.status_code == 201 @@ -109,8 +107,7 @@ def test_scenario_change( request_should_still_work = owner_client.post( f"/thesis/{record2.json['id']}/draft/requests/publish_draft" ) - # todo add workflow to marshmallow - record5 = _create_record_in_community(owner_client, community_1.id) + record5 = draft_in_community(owner_client, community_1.id) request_should_be_forbidden = owner_client.post( f"/thesis/{record5.json['id']}/draft/requests/publish_draft" ) @@ -180,6 +177,7 @@ def test_record_owners_in_default_record_community_needs( community_with_workflow_factory, inviter, remover, + draft_in_community, service_config, record_service, search_clear, @@ -196,12 +194,12 @@ def test_record_owners_in_default_record_community_needs( curator_client = logged_client(community_curator) - record1 = _create_record_in_community( + record1 = draft_in_community( curator_client, community_1.id, custom_workflow="record_owner_in_default_record_community", ) - record2 = _create_record_in_community( + record2 = draft_in_community( curator_client, community_2.id, custom_workflow="record_owner_in_default_record_community", @@ -233,6 +231,7 @@ def test_record_owners_in_record_community_needs( logged_client, community_with_workflow_factory, community_inclusion_service, + draft_in_community, inviter, remover, service_config, @@ -251,12 +250,12 @@ def test_record_owners_in_record_community_needs( curator_client = logged_client(community_curator) - record1 = _create_record_in_community( + record1 = draft_in_community( curator_client, community_1.id, custom_workflow="record_owner_in_record_community", ) - record2 = _create_record_in_community( + record2 = draft_in_community( curator_client, community_3.id, custom_workflow="record_owner_in_record_community", diff --git a/tests/test_communities/utils.py b/tests/test_communities/utils.py index 385927d..f7a38ae 100644 --- a/tests/test_communities/utils.py +++ b/tests/test_communities/utils.py @@ -1,23 +1,6 @@ from invenio_access.permissions import system_identity -def published_record_in_community(client, community_id, record_service, user): - # skip the request approval - response = _create_record_in_community(client, community_id) - record_item = record_service.publish(system_identity, response.json["id"]) - return record_item._obj - - -def _create_record_in_community(client, comm_id, custom_workflow=None): - if custom_workflow: - return client.post( - f"/communities/{comm_id}/thesis", - json={"parent": {"workflow": custom_workflow}}, - ) - - return client.post(f"/communities/{comm_id}/thesis", json={}) - - -def link_api2testclient(api_link): - base_string = "https://127.0.0.1:5000/api/" - return api_link[len(base_string) - 1 :] +def link2testclient(link, ui=False): + base_string = "https://127.0.0.1:5000/api/" if not ui else "https://127.0.0.1:5000/" + return link[len(base_string) - 1 :]