Skip to content

Commit

Permalink
api_tests.share overhaul
Browse files Browse the repository at this point in the history
  • Loading branch information
aaxelb committed Aug 9, 2023
1 parent 7972ac8 commit 1e41e28
Show file tree
Hide file tree
Showing 11 changed files with 257 additions and 364 deletions.
95 changes: 79 additions & 16 deletions api/share/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,23 @@

from celery.exceptions import Retry
from django.apps import apps
import requests

from framework.celery_tasks import app as celery_app
from framework.celery_tasks.handlers import enqueue_task
from framework.sentry import log_exception
from osf.metadata.tools import pls_send_trove_indexcard, pls_delete_trove_indexcard
from osf.metadata.osf_gathering import osf_iri
from osf.metadata.tools import pls_gather_metadata_file
from website import settings


logger = logging.getLogger(__name__)


def shtrove_ingest_url():
return f'{settings.SHARE_URL}api/v3/ingest'


def is_qa_resource(resource):
"""
QA puts tags and special titles on their project to stop them from appearing in the search results. This function
Expand Down Expand Up @@ -46,29 +52,35 @@ def update_share(resource):
enqueue_task(task__update_share.s(_osfguid_value))


def do_update_share(osfguid: str):
logger.debug('%s.do_update_share("%s")', __name__, osfguid)
_guid_instance = apps.get_model('osf.Guid').load(osfguid)
if _guid_instance is None:
raise ValueError(f'unknown osfguid "{osfguid}"')
_resource = _guid_instance.referent
_response = (
pls_delete_trove_indexcard(_resource)
if _should_delete_indexcard(_resource)
else pls_send_trove_indexcard(_resource)
)
return _response


@celery_app.task(bind=True, max_retries=4, acks_late=True)
def task__update_share(self, guid: str, **kwargs):
def task__update_share(self, guid: str):
"""
This function updates share takes Preprints, Projects and Registrations.
:param self:
:param guid:
:return:
"""
_guid_instance = apps.get_model('osf.Guid').load(guid)
if _guid_instance is None:
raise ValueError(f'unknown osfguid "{guid}"')
resource = _guid_instance.referent
resp = (
pls_delete_trove_indexcard(resource)
if _should_delete_indexcard(resource)
else pls_send_trove_indexcard(resource)
)
resp = do_update_share(guid)
try:
resp.raise_for_status()
except Exception as e:
if self.request.retries == self.max_retries:
log_exception()
elif resp.status_code >= 500 and settings.USE_CELERY:
elif resp.status_code >= 500:
try:
self.retry(
exc=e,
Expand All @@ -82,13 +94,64 @@ def task__update_share(self, guid: str, **kwargs):
return resp


def pls_send_trove_indexcard(osf_item):
_iri = osf_iri(osf_item)
if not _iri:
raise ValueError(f'could not get iri for {osf_item}')
_metadata_record = pls_gather_metadata_file(osf_item, 'turtle')
return requests.post(
shtrove_ingest_url(),
params={
'focus_iri': _iri,
'record_identifier': _shtrove_record_identifier(osf_item),
},
headers={
'Content-Type': _metadata_record.mediatype,
**_shtrove_auth_headers(osf_item),
},
data=_metadata_record.serialized_metadata,
)


def pls_delete_trove_indexcard(osf_item):
return requests.delete(
shtrove_ingest_url(),
params={
'record_identifier': _shtrove_record_identifier(osf_item),
},
headers=_shtrove_auth_headers(osf_item),
)


def _shtrove_record_identifier(osf_item):
return osf_item.guids.values_list('_id', flat=True).first()


def _shtrove_auth_headers(osf_item):
_nonfile_item = (
osf_item.target
if hasattr(osf_item, 'target')
else osf_item
)
_access_token = (
_nonfile_item.provider.access_token
if getattr(_nonfile_item, 'provider', None) and _nonfile_item.provider.access_token
else settings.SHARE_API_TOKEN
)
return {'Authorization': f'Bearer {_access_token}'}


def _should_delete_indexcard(osf_item):
if getattr(osf_item, 'is_deleted', False) or getattr(osf_item, 'deleted', None):
return True
# if it quacks like BaseFileNode, look at .target instead
_possibly_private_item = getattr(osf_item, 'target', None) or osf_item
_containing_item = getattr(osf_item, 'target', None)
if _containing_item:
return _should_delete_indexcard(_containing_item)
return (
not _is_item_public(_possibly_private_item)
or getattr(_possibly_private_item, 'is_spam', False)
or is_qa_resource(_possibly_private_item)
not _is_item_public(osf_item)
or getattr(osf_item, 'is_spam', False)
or is_qa_resource(osf_item)
)


Expand Down
22 changes: 11 additions & 11 deletions api_tests/providers/test_reindex_provider.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from unittest import mock

import pytest
import json

from django.core.management import call_command

Expand Down Expand Up @@ -35,16 +36,15 @@ def registration(self, registration_provider):
def user(self):
return AuthUserFactory()

def test_reindex_provider_preprint(self, mock_share, preprint_provider, preprint):
call_command('reindex_provider', f'--providers={preprint_provider._id}')
data = json.loads(mock_share.calls[-1].request.body)
@pytest.fixture()
def mock_update_share(self):
with mock.patch('osf.management.commands.reindex_provider.update_share') as _mock_update_share:
yield _mock_update_share

assert any(graph for graph in data['data']['attributes']['data']['@graph']
if graph['@type'] == preprint_provider.share_publish_type.lower())
def test_reindex_provider_preprint(self, mock_update_share, preprint_provider, preprint):
call_command('reindex_provider', f'--providers={preprint_provider._id}')
assert mock_update_share.called_once_with(preprint)

def test_reindex_provider_registration(self, mock_share, registration_provider, registration):
def test_reindex_provider_registration(self, mock_update_share, registration_provider, registration):
call_command('reindex_provider', f'--providers={registration_provider._id}')
data = json.loads(mock_share.calls[-1].request.body)

assert any(graph for graph in data['data']['attributes']['data']['@graph']
if graph['@type'] == registration_provider.share_publish_type.lower())
assert mock_update_share.called_once_with(registration)
Empty file added api_tests/share/__init__.py
Empty file.
27 changes: 27 additions & 0 deletions api_tests/share/_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import contextlib
from urllib.parse import urlsplit

from django.http import QueryDict

from website import settings as website_settings


@contextlib.contextmanager
def expect_ingest_request(mock_share, osfguid, *, token=None, delete=False, count=1):
mock_share._calls.reset()
yield
assert len(mock_share.calls) == count
for _call in mock_share.calls:
assert_ingest_request(_call.request, osfguid, token=token, delete=delete)


def assert_ingest_request(request, expected_osfguid, *, token=None, delete=False):
_querydict = QueryDict(urlsplit(request.path_url).query)
assert _querydict['record_identifier'] == expected_osfguid
if delete:
assert request.method == 'DELETE'
else:
assert request.method == 'POST'
assert _querydict['focus_iri'] == f'{website_settings.DOMAIN}{expected_osfguid}'
_token = token or website_settings.SHARE_API_TOKEN
assert request.headers['Authorization'] == f'Bearer {_token}'
Loading

0 comments on commit 1e41e28

Please sign in to comment.