Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle exception while distributer not availble #219

Merged
merged 20 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 37 additions & 12 deletions dmci/distributors/pycsw_dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,7 @@ def _insert(self):
)
xml += self._translate()
xml += b"</csw:Insert></csw:Transaction>"
resp = requests.post(self._conf.csw_service_url, headers=headers, data=xml)
status = self._get_transaction_status(self.TOTAL_INSERTED, resp)
logger.debug("Insert status: " + str(status) + ". With response: " + resp.text)
return status, resp.text
return self._post_request(headers, xml, "insert", self.TOTAL_INSERTED)

def _update(self):
"""Update current entry.
Expand All @@ -120,10 +117,7 @@ def _update(self):
)
xml += self._translate()
xml += b"</csw:Update></csw:Transaction>"
resp = requests.post(self._conf.csw_service_url, headers=headers, data=xml)
status = self._get_transaction_status(self.TOTAL_UPDATED, resp)
logger.debug("Update status: " + str(status) + ". With response: " + resp.text)
return status, resp.text
return self._post_request(headers, xml, "update", self.TOTAL_UPDATED)

def _delete(self):
"""Delete entry with a specified metadata_id."""
Expand Down Expand Up @@ -153,10 +147,7 @@ def _delete(self):
' </csw:Delete>'
'</csw:Transaction>'
) % identifier
resp = requests.post(self._conf.csw_service_url, headers=headers, data=xml_as_string)
status = self._get_transaction_status(self.TOTAL_DELETED, resp)
logger.debug("Delete status: " + str(status) + ". With response: " + resp.text)
return status, resp.text
return self._post_request(headers, xml_as_string, "delete", self.TOTAL_DELETED)

def _get_transaction_status(self, key, resp):
"""Check response status, read response text, and get status.
Expand Down Expand Up @@ -255,4 +246,38 @@ def _read_response_text(self, key, text):

return status

def _post_request(self, headers, xml, cmd, key):
shamlymajeed marked this conversation as resolved.
Show resolved Hide resolved
"""Send an HTTP POST request to pyCSW using a Transaction.

Parameters
----------
headers : dict
Headers to be included in the request.
xml : str
XML data to be sent in the request body.
cmd : str
Description of the command being executed.
mortenwh marked this conversation as resolved.
Show resolved Hide resolved
key : str
Key specifying the type of transaction: 'total_inserted', 'total_updated',
or 'total_deleted'.

Returns
-------
tuple of (bool, str)
A tuple containing a boolean indicating whether the transaction succeeded (True) or
failed (False), and a string providing additional information about the transaction
status or error message.
"""
try:
resp = requests.post(self._conf.csw_service_url, headers=headers, data=xml)
except Exception as e:
logger.error(str(e))
return False, (
"%s: service unavailable. Failed to %s." %
(self._conf.csw_service_url, cmd)
)
status = self._get_transaction_status(key, resp)
logger.debug(cmd + " status: " + str(status) + ". With response: " + resp.text)
return status, resp.text

# END Class PyCSWDist
51 changes: 28 additions & 23 deletions dmci/distributors/solr_dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,32 +101,37 @@ def _add(self):

"""Check if document already exsists. Then we throw error and don't index."""
isIndexed = self.mysolr.get_dataset(newdoc['id'])
if isIndexed['doc'] is not None and self._cmd == DistCmd.INSERT:
msg = "Document already exists in index, %s" % newdoc['metadata_identifier']
logger.error(msg)
return False, msg

if 'related_dataset' in newdoc:
logger.debug("Child dataset with id: %s",
newdoc['metadata_identifier'])
logger.debug("Child dataset's parent's id is: %s",
newdoc['related_dataset'])
parentid = newdoc['related_dataset_id']
status, msg = self.mysolr.update_parent(
parentid,
fail_on_missing=self._conf.fail_on_missing_parent
)
if status:
status, msg = self._index_record(
newdoc, add_thumbnail=False, level=2)
if isIndexed is not None:
if isIndexed['doc'] is not None and self._cmd == DistCmd.INSERT:
msg = "Document already exists in index, %s" % newdoc['metadata_identifier']
logger.error(msg)
return False, msg

if 'related_dataset' in newdoc:
logger.debug("Child dataset with id: %s",
newdoc['metadata_identifier'])
logger.debug("Child dataset's parent's id is: %s",
newdoc['related_dataset'])
parentid = newdoc['related_dataset_id']
status, msg = self.mysolr.update_parent(
parentid,
fail_on_missing=self._conf.fail_on_missing_parent
)
if status:
status, msg = self._index_record(
newdoc, add_thumbnail=False, level=2)
else:
return status, msg
else:
return status, msg
logger.debug("Parent/Level-1 - dataset - %s",
newdoc['metadata_identifier'])
status, msg = self._index_record(
newdoc, add_thumbnail=False, level=1)
else:
logger.debug("Parent/Level-1 - dataset - %s",
newdoc['metadata_identifier'])
status, msg = self._index_record(
newdoc, add_thumbnail=False, level=1)

msg = "Failed to insert dataset in SolR."
logger.error(msg)
return False, msg
return status, msg

def _index_record(self, newdoc, add_thumbnail=False, level=1):
Expand Down
12 changes: 11 additions & 1 deletion tests/test_api/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,17 @@ def testApiApp_InsertUpdateRequests(client, monkeypatch):
b"The following jobs were skipped: C\n"
)

# END Test testApiApp_InsertRequests
# Data is valid, distribute OK.
with monkeypatch.context() as mp:

mp.setattr("dmci.api.app.Worker.validate", lambda *a: (True, "", MOCK_XML))
mp.setattr("dmci.api.app.Worker.distribute", lambda *a: (
True, True, [], [], [], []))
response = client.post("/v1/insert", data=MOCK_XML)
assert response.status_code == 200
assert response.data == (b"Everything is OK\n")

# END Test testApiApp_InsertUpdateRequests


@pytest.mark.api
Expand Down
31 changes: 29 additions & 2 deletions tests/test_dist/test_pycsw_dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import os
import pytest
import requests
from tools import causeException

from lxml import etree

Expand Down Expand Up @@ -62,7 +63,6 @@ def testDistPyCSW_Run(tmpUUID):
@pytest.mark.dist
def testDistPyCSW_Insert(monkeypatch, mockXml, mockXslt):
"""Test insert commands via run()."""

# Insert returns True
with monkeypatch.context() as mp:
mp.setattr(PyCSWDist, "_translate", lambda *a: b"<xml />")
Expand All @@ -81,11 +81,22 @@ def testDistPyCSW_Insert(monkeypatch, mockXml, mockXslt):
"dmci.distributors.pycsw_dist.requests.post", lambda *a, **k: mockResp
)
mp.setattr(PyCSWDist, "_get_transaction_status", lambda *a: False)

tstPyCSW = PyCSWDist("insert", xml_file=mockXml)
tstPyCSW._conf.mmd_xsl_path = mockXslt
assert tstPyCSW.run() == (False, "Mock response")

# END Test testDistPyCSW_Insert
# Insert returns False if the http post request fails
with monkeypatch.context() as mp:
mp.setattr(
"dmci.distributors.pycsw_dist.requests.post", causeException)
tstPyCSW = PyCSWDist("insert", xml_file=mockXml)
assert tstPyCSW.run() == (
False,
"http://localhost: service unavailable. Failed to insert."
)

# END Test testDistPyCSW_Insert


@pytest.mark.dist
Expand Down Expand Up @@ -121,6 +132,16 @@ def testDistPyCSW_Update(monkeypatch, mockXml, mockXslt, tmpUUID):
tstPyCSW._conf.mmd_xsl_path = mockXslt
assert tstPyCSW.run() == (False, "Mock response")

# Update returns False if the http post request fails
with monkeypatch.context() as mp:
mp.setattr(
"dmci.distributors.pycsw_dist.requests.post", causeException)
tstPyCSW = PyCSWDist("update", xml_file=mockXml)
assert tstPyCSW.run() == (
False,
"http://localhost: service unavailable. Failed to update."
)

# END Test testDistPyCSW_Update


Expand Down Expand Up @@ -154,6 +175,12 @@ def testDistPyCSW_Delete(monkeypatch, mockXml, tmpUUID):
res = PyCSWDist("delete", metadata_UUID=tmpUUID, worker=mockWorker).run()
assert res == (False, "Mock response")

# Delete returns False if http post request fails
with monkeypatch.context() as mp:
mp.setattr(
"dmci.distributors.pycsw_dist.requests.post", causeException)
res = PyCSWDist("delete", metadata_UUID=tmpUUID, worker=mockWorker).run()
assert res == (False, "http://localhost: service unavailable. Failed to delete.")

# END Test testDistPyCSW_Delete

Expand Down
30 changes: 30 additions & 0 deletions tests/test_dist/test_solr_dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,21 @@ def tosolr(self, *args, **kwargs):
return solr_formatted


class MockFailIndexMMD:
def __init__(self, *args, **kwargs):
pass

def get_dataset(self, *args, **kwargs):
is_indexed = None
return is_indexed

def index_record(self, *args, **kwargs):
return True, 'test'

def update_parent(self, *args, **kwargs):
return True, "Test successful update message"


class mockResp:
text = "Mock response"
status_code = 200
Expand Down Expand Up @@ -166,6 +181,21 @@ def testDistSolR_AddSuccessful(mockXml, monkeypatch):
)


@pytest.mark.dist
def testDistSolR_AddFailsWithConnectionFailure(mockXml, monkeypatch):
""" Test that the add function fails when failed to make connection with solr"""
with monkeypatch.context() as mp:
mp.setattr("dmci.distributors.solr_dist.MMD4SolR",
lambda *args, **kwargs: MockMMD4SolR(*args, **kwargs))
mp.setattr("dmci.distributors.solr_dist.IndexMMD",
lambda *args, **kwargs: MockFailIndexMMD(*args, **kwargs))

# Initialise object, and check that it validates
tstDist = SolRDist("insert", xml_file=mockXml)
assert tstDist.is_valid()
assert tstDist._add() == (False, "Failed to insert dataset in SolR.")


def testDistSolR_AddSuccessfulWithRelatedDataset(mockXml, monkeypatch):
""" Test that the _add function successfully completes with the
correct return message.
Expand Down
Loading