Example #1
0
    def test_convert_to_edifact(self):
        TEST_DIR = os.path.dirname(os.path.abspath(__file__))

        expected_file_path = Path(TEST_DIR) / "edifact.txt"
        expected_edifact_interchange = FileUtilities.get_file_string(expected_file_path)

        incoming_file_path = Path(TEST_DIR) / "patient-register-birth.json"
        patient_register_json = FileUtilities.get_file_dict(incoming_file_path)

        outgoing_adaptor = OutgoingAdaptor(operation_dict)
        (sender, recipient, interchange_seq_no, edifact_interchange) = outgoing_adaptor.convert_to_edifact(
            patient_register_json)

        pretty_edifact_interchange = "'\n".join(edifact_interchange.split("'"))
        self.assertEqual(pretty_edifact_interchange, expected_edifact_interchange)
    def test_payload_id_matches_manifest_id(self):
        with self.subTest("Incorrect manifest occurrences returns 500 error"):
            dictionary = {
                'action': "urn:nhs-itk:services:201005:SendNHS111Report",
                'service': "urn:nhs-itk:services:201005:SendNHS111Report",
                'manifestCount': "2",
                'manifests': [{"id": 'one'}, {'id': 'one'}],
                'payloadCount': "2",
                'payloads': [{"id": 'one'}, {'id': "two"}]
            }
            expected = FileUtilities.get_file_string(
                str(self.expectedXmlFileDir / 'payloadID_does_not_match_manifestID.xml'))

            msg = self.builder.build_message(dictionary)
            message_handler = MessageHandler(msg)

            self.assertEqual(message_handler.error_flag, True)
            XmlUtilities.assert_xml_equal_utf_8(expected, message_handler.get_response())

        with self.subTest("Incorrect manifest occurrences returns 500 error"):
            dictionary = {
                'action': "urn:nhs-itk:services:201005:SendNHS111Report",
                'service': "urn:nhs-itk:services:201005:SendNHS111Report",
                'manifestCount': "2",
                'manifests': [{"id": 'one'}, {'id': "two"}],
                'payloadCount': "2",
                'payloads': [{"id": 'one'}, {'id': "two"}]
            }

            msg = self.builder.build_message(dictionary)
            message_handler = MessageHandler(msg)

            self.assertEqual(message_handler.error_flag, False)
            XmlUtilities.assert_xml_equal_utf_8(self.success_response, message_handler.get_response())
    def test_manifest_payload_count(self):
        with self.subTest("Mismatched counts: 500 response"):
            counts = {
                'action': "urn:nhs-itk:services:201005:SendNHS111Report",
                'service': "urn:nhs-itk:services:201005:SendNHS111Report",
                'manifestCount': "1",
                'manifests': [{"id": 'one'}],
                'payloadCount': "2",
                'payloads': [{"id": 'one'}, {'id': "two"}]
            }

            expected = FileUtilities.get_file_string(
                str(self.expectedXmlFileDir / 'manifest_not_equal_to_payload_count.xml'))

            msg = self.builder.build_message(counts)
            message_handler = MessageHandler(msg)

            self.assertEqual(message_handler.error_flag, True)
            XmlUtilities.assert_xml_equal_utf_8(expected, message_handler.get_response())

        with self.subTest("Equal counts: 200 response"):
            counts = {
                'action': "urn:nhs-itk:services:201005:SendNHS111Report",
                'service': "urn:nhs-itk:services:201005:SendNHS111Report",
                'manifestCount': "2",
                'manifests': [{"id": 'one'}, {"id": "two"}],
                'payloadCount': "2",
                'payloads': [{"id": 'one'}, {'id': "two"}]
            }

            msg = self.builder.build_message(counts)
            message_handler = MessageHandler(msg)

            self.assertEqual(message_handler.error_flag, False)
            XmlUtilities.assert_xml_equal_utf_8(self.success_response, message_handler.get_response())
    def test_action_not_matching_service(self):
        with self.subTest("Two differing services result in a 500 error"):
            service_dict = {'action': "urn:nhs-itk:services:201005:SendNHS111Report-v2-0-ThisDoesNotMatchBelow",
                            'service': "urn:nhs-itk:services:201005:SendNHS111Report-Bad_Service-ThisDoesNotMatchAbove",
                            'manifestCount': 0,
                            'payloadCount': 0
                            }

            expected = FileUtilities.get_file_string(
                str(self.expectedXmlFileDir / 'invalid_action_service_values_response.xml'))

            msg = self.builder.build_message(service_dict)
            message_handler = MessageHandler(msg)

            self.assertEqual(message_handler.error_flag, True)
            XmlUtilities.assert_xml_equal_utf_8(expected, message_handler.get_response())

        with self.subTest("Two services which are the same should return 200 code"):
            service_dict = {'action': "urn:nhs-itk:services:201005:SendNHS111Report",
                            'service': "urn:nhs-itk:services:201005:SendNHS111Report",
                            'manifestCount': 0,
                            'payloadCount': 0
                            }

            msg = self.builder.build_message(service_dict)
            message_handler = MessageHandler(msg)

            self.assertEqual(message_handler.error_flag, False)
            XmlUtilities.assert_xml_equal_utf_8(self.success_response, message_handler.get_response())
Example #5
0
    async def test_soap_error_request_is_non_retriable(self):
        self.setup_mock_work_description()
        self._setup_routing_mock()

        self.mock_ebxml_request_envelope.return_value.serialize.return_value = (
            MESSAGE_ID, {}, SERIALIZED_MESSAGE)

        response = mock.MagicMock()
        response.code = 500
        response.headers = {'Content-Type': 'text/xml'}
        # a non retriable soap 300 error code
        response.body = FileUtilities.get_file_string(
            Path(self.test_message_dir) /
            'soapfault_response_single_error_300.xml')
        self.mock_transmission_adaptor.make_request.return_value = test_utilities.awaitable(
            response)

        with mock.patch(
                'utilities.config.get_config',
                return_value='localhost/reliablemessaging/queryrequest'):
            status, message, _ = await self.workflow.handle_outbound_message(
                None, MESSAGE_ID, CORRELATION_ID, INTERACTION_DETAILS, PAYLOAD,
                None)

        self.mock_transmission_adaptor.make_request.assert_called_once()
    async def test_retry_interval_contract_property_is_invalid(self):
        self.setup_mock_work_description()
        self._setup_routing_mock()

        self.mock_routing_reliability.get_reliability.return_value = test_utilities.awaitable(
            {
                workflow.common_asynchronous.MHS_RETRY_INTERVAL:
                MHS_RETRY_INTERVAL_INVALID_VAL,
                workflow.common_asynchronous.MHS_RETRIES: MHS_RETRY_VAL
            })

        self.mock_ebxml_request_envelope.return_value.serialize.return_value = (
            MESSAGE_ID, {}, SERIALIZED_MESSAGE)

        message = FileUtilities.get_file_string(
            Path(self.test_message_dir) /
            'soapfault_response_single_error.xml')

        response = httpclient.HTTPResponse
        response.code = 500
        response.body = message
        response.headers = {'Content-Type': 'text/xml'}

        self.mock_transmission_adaptor.make_request.return_value = test_utilities.awaitable(
            response)

        status, message, _ = await self.workflow.handle_outbound_message(
            None, MESSAGE_ID, CORRELATION_ID, INTERACTION_DETAILS, PAYLOAD,
            None)

        self.assertEqual(500, status)
        self.assertTrue('Error when converting retry interval' in message)
        self.assertEqual(
            [mock.call(MessageStatus.OUTBOUND_MESSAGE_PREPARATION_FAILED)],
            self.mock_work_description.set_outbound_status.call_args_list)
    def test_parse_message(self):
        with self.subTest("A valid request containing a payload"):
            message = FileUtilities.get_file_string(
                str(message_dir / "ebxml_request.msg"))
            expected_values_with_payload = expected_values(
                message=EXPECTED_MESSAGE)

            extracted_values = self.parser.parse_message(
                MULTIPART_MIME_HEADERS, message)

            self.assertEqual(expected_values_with_payload, extracted_values)

        with self.subTest("An invalid multi-part MIME message"):
            message = FileUtilities.get_file_string(
                str(message_dir / "ebxml_request_no_header.msg"))

            with (self.assertRaises(EbXmlParsingError)):
                self.parser.parse_message(MULTIPART_MIME_HEADERS, message)

        with self.subTest(
                "A valid request that does not contain the optional payload MIME part"
        ):
            message = FileUtilities.get_file_string(
                str(message_dir / "ebxml_request_no_payload.msg"))
            expected_values_with_no_payload = expected_values()

            extracted_values = self.parser.parse_message(
                MULTIPART_MIME_HEADERS, message)

            self.assertEqual(expected_values_with_no_payload, extracted_values)

        with self.subTest(
                "A valid request containing an additional MIME part"):
            message = FileUtilities.get_file_string(
                str(message_dir / "ebxml_request_additional_attachment.msg"))
            expected_values_with_payload = expected_values(
                message=EXPECTED_MESSAGE)

            extracted_values = self.parser.parse_message(
                MULTIPART_MIME_HEADERS, message)

            self.assertEqual(expected_values_with_payload, extracted_values)

        with self.subTest("An message that is not a multi-part MIME message"):
            with (self.assertRaises(EbXmlParsingError)):
                self.parser.parse_message(
                    {CONTENT_TYPE_HEADER_NAME: "text/plain"}, "A message")
    def test_covert_to_fhir(self):
        """
        Test when the operation is for a birth registration
        """
        TEST_DIR = os.path.dirname(os.path.abspath(__file__))

        expected_file_path = Path(TEST_DIR) / "patient-register-birth-approval.json"
        patient_register_approval_json = FileUtilities.get_file_dict(expected_file_path)

        incoming_file_path = Path(TEST_DIR) / "edifact.txt"
        incoming_interchange_raw = FileUtilities.get_file_string(incoming_file_path)

        incoming_adaptor = IncomingAdaptor(reference_dict)
        op_defs = incoming_adaptor.convert_to_fhir(incoming_interchange_raw)

        op_def_to_compare = op_defs[0][2]
        compare(op_def_to_compare, patient_register_approval_json)
    def test_parse_message_with_no_values(self):
        message = FileUtilities.get_file_string(
            str(message_dir / "ebxml_header_empty.xml"))

        extracted_values = self.parser.parse_message(MULTIPART_MIME_HEADERS,
                                                     message)

        self.assertEqual({}, extracted_values)
Example #10
0
    def test_multiple_errors(self):
        message = FileUtilities.get_file_string(
            self.message_dir / 'ebxml_response_error_multiple.xml')
        response = handle_ebxml_error(200, {'Content-Type': 'text/xml'},
                                      message)[1]

        self.assertIn('501319:Unknown eb:CPAId', response)
        self.assertIn('501320:Unknown something else', response)
        self.assertIn('errorType=ebxml_error', response)
    def test_parse_message(self):
        message = FileUtilities.get_file_string(
            str(message_dir / "ebxml_header.xml"))
        expected_values_without_message = expected_values()

        extracted_values = self.parser.parse_message(MULTIPART_MIME_HEADERS,
                                                     message)

        self.assertEqual(expected_values_without_message, extracted_values)
    def test_should_return_error_when_required_details_tag_is_missing(self):
        input_xml = FileUtilities.get_file_string(
            str(self.xmlFileDir / 'missingAttribute.xml'))
        parsed_data = self.gp_summary_upload_templator.parse_response(
            input_xml)

        self.assertEqual(
            parsed_data['error'],
            'Failed to parse all the necessary elements from xml returned from MHS'
        )
    def test_should_return_error_when_there_is_a_bad_attribute_format(self):
        input_xml = FileUtilities.get_file_string(
            str(self.xmlFileDir / 'badAttributeParse.xml'))
        parsed_data = self.gp_summary_upload_templator.parse_response(
            input_xml)

        self.assertEqual(
            parsed_data['error'],
            'Failed to parse all the necessary elements from xml returned from MHS'
        )
    def test_python_dictionary_example(self):
        """
        Basic test to demonstrate passing a python dict to the interface instead of a json file
        """
        expected_string = FileUtilities.get_file_string(
            str(Path(ROOT_DIR) / 'scr/tests/test_xmls/cleanSummaryUpdate.xml'))
        from scr.tests.hashes.basic_dict import input_hash

        render = self.summaryCareRecord.populate_template(input_hash)
        XmlUtilities.assert_xml_equal(expected_string, render)
Example #15
0
    def test_post(self, mock_get_uuid, mock_get_timestamp):
        mock_get_uuid.return_value = "5BB171D4-53B2-4986-90CF-428BE6D157F5"
        mock_get_timestamp.return_value = "2012-03-15T06:51:08Z"
        expected_ack_response = FileUtilities.get_file_string(
            str(self.message_dir / EXPECTED_RESPONSE_FILE))
        request_body = FileUtilities.get_file_string(
            str(self.message_dir / REQUEST_FILE))
        mock_callback = Mock()
        self.callbacks[REF_TO_MESSAGE_ID] = mock_callback

        ack_response = self.fetch("/",
                                  method="POST",
                                  body=request_body,
                                  headers=CONTENT_TYPE_HEADERS)

        self.assertEqual(ack_response.code, 200)
        self.assertEqual(ack_response.headers["Content-Type"], "text/xml")
        XmlUtilities.assert_xml_equal(expected_ack_response, ack_response.body)
        mock_callback.assert_called_with(EXPECTED_MESSAGE)
    def test_empty_hash(self):
        """
        Tests the contents are empty when a completely blank hash is provided
        """
        expected_xml_file_path = str(self.xmlFileDir / 'EmptyHash.xml')
        hash_file_path = str(self.hashFileDir / 'EmptyHash.json')

        expected_string = FileUtilities.get_file_string(expected_xml_file_path)
        render = self.summaryCareRecord.populate_template_with_file(
            hash_file_path)
        XmlUtilities.assert_xml_equal(expected_string, render)
    def test_empty_html(self):
        """
        A test for an empty human readable content value
        """
        expected_xml_file_path = str(self.xmlFileDir /
                                     'EmptyHtmlGpSummaryUpdate.xml')
        hash_file_path = str(self.hashFileDir / 'emptyHtmlHash.json')

        expected_string = FileUtilities.get_file_string(expected_xml_file_path)
        render = self.summaryCareRecord.populate_template_with_file(
            hash_file_path)
        XmlUtilities.assert_xml_equal(expected_string, render)
    def test_extended_html(self):
        """
        Uses a larger set of Html for the human readable contents
        """
        expected_xml_file_path = str(self.xmlFileDir /
                                     'SummaryUpdateExtendedContents.xml')
        hash_file_path = str(self.hashFileDir / 'extendedHTMLhash.json')

        expected_string = FileUtilities.get_file_string(expected_xml_file_path)
        render = self.summaryCareRecord.populate_template_with_file(
            hash_file_path)
        XmlUtilities.assert_xml_equal(expected_string, render)
    def test_basic(self):
        """
        A basic test using the clean summary update from the spine tests
        """
        expected_xml_file_path = str(self.xmlFileDir /
                                     'cleanSummaryUpdate.xml')
        hash_file_path = str(self.hashFileDir / 'hash16UK05.json')

        expected_string = FileUtilities.get_file_string(expected_xml_file_path)
        render = self.summaryCareRecord.populate_template_with_file(
            hash_file_path)
        XmlUtilities.assert_xml_equal(expected_string, render)
 def test_json_string_example(self):
     """
     Basic example showing how a json string can be passed to the interface
     """
     expected_string = FileUtilities.get_file_string(
         str(self.xmlFileDir / 'cleanSummaryUpdate.xml'))
     json_file = str(self.hashFileDir / 'hash16UK05.json')
     with open(json_file) as file:
         data = file.read()  # Reads file contents into a string
         render = self.summaryCareRecord.populate_template_with_json_string(
             data)
         XmlUtilities.assert_xml_equal(expected_string, render)
Example #21
0
    def test_post_no_callback(self):
        # If there is no callback registered for the message ID the response is in reference to, an HTTP 500 should be
        # returned.
        request_body = FileUtilities.get_file_string(
            str(self.message_dir / REQUEST_FILE))

        response = self.fetch("/",
                              method="POST",
                              body=request_body,
                              headers=CONTENT_TYPE_HEADERS)

        self.assertEqual(response.code, 500)
    def test_build_message(self, mock_get_uuid, mock_get_timestamp):
        mock_get_uuid.return_value = MOCK_UUID
        mock_get_timestamp.return_value = "2012-03-15T06:51:08Z"
        expected_message = FileUtilities.get_file_string(
            str(self.expected_message_dir / EXPECTED_EBXML))

        message_id, message = self.builder.build_message({
            FROM_PARTY_ID:
            "TESTGEN-201324",
            TO_PARTY_ID:
            "YEA-0000806",
            CPA_ID:
            "S1001A1630",
            CONVERSATION_ID:
            "79F49A34-9798-404C-AEC4-FD38DD81C138",
            SERVICE:
            "urn:nhs:names:services:pdsquery",
            ACTION:
            "QUPA_IN000006UK02",
            DUPLICATE_ELIMINATION:
            True,
            ACK_REQUESTED:
            True,
            ACK_SOAP_ACTOR:
            "urn:oasis:names:tc:ebxml-msg:actor:toPartyMSH",
            SYNC_REPLY:
            True,
            MESSAGE:
            '<QUPA_IN000006UK02 xmlns="urn:hl7-org:v3"></QUPA_IN000006UK02>'
        })

        # Pystache does not convert line endings to LF in the same way as Python does when loading the example from
        # file, so normalize the line endings of both strings
        normalized_expected_message = FileUtilities.normalize_line_endings(
            expected_message)
        normalized_message = FileUtilities.normalize_line_endings(message)

        self.assertEqual(MOCK_UUID, message_id)
        self.assertEqual(normalized_expected_message, normalized_message)
    def test_replacementOf(self):
        """
        Note: this is not a valid xml instance
        This is to demonstrate the condition aspect of the replacementOf partial,
        this partial doesnt appear in the previous tests but here a list with a single
        element is used to show how conditionals are used in mustache
        """
        expected_xml_file_path = str(self.xmlFileDir / 'replacementOf.xml')
        hash_file_path = str(self.hashFileDir / 'replacementOfhash.json')

        expected_string = FileUtilities.get_file_string(expected_xml_file_path)
        render = self.summaryCareRecord.populate_template_with_file(
            hash_file_path)
        XmlUtilities.assert_xml_equal(expected_string, render)
Example #24
0
def get_asid():
    """ Looks up the asid from the environment settings

    The asid should be set in the 'Environment variables' section of the Run/Debug Configurations
        if this is not set, it will read from 'asid.txt' (excluded from the repo)
        or default to '123456789012' if 'asid.txt' is not found
    """
    try:
        asid_file = str(Path(ROOT_DIR) / "data/certs/asid.txt")
        asid = FileUtilities.get_file_string(asid_file)
    except:
        asid = None

    return os.environ.get('INTEGRATION_TEST_ASID', asid)
    def test_multipleReplacementOf(self):
        """
        Note: THIS IS NOT A VALID XML INSTANCE
        This test is build purely for demonstrating having a variable number of occurrences of
        a partial in mustache, it does not conform to the schema and will not be accepted as a valid message
        """
        expected_xml_file_path = str(self.xmlFileDir /
                                     'multipleReplacementOf.xml')
        hash_file_path = str(self.hashFileDir / 'multiReplacementOfhash.json')

        expected_string = FileUtilities.get_file_string(expected_xml_file_path)
        render = self.summaryCareRecord.populate_template_with_file(
            hash_file_path)
        XmlUtilities.assert_xml_equal(expected_string, render)
    def test_normalize_line_endings(self):
        strings_to_test = {
            "CRLF": CR_LF_STRING,
            "CR": CR_STRING,
            "LF": LF_STRING,
            "Mixed": MIXED_STRING
        }

        for line_break_type, test_string in strings_to_test.items():
            message = line_break_type + " line endings should be normalized."

            with self.subTest(message):
                normalized_string = FileUtilities.normalize_line_endings(test_string)

                self.assertEqual(EXPECTED_NORMALIZED_STRING, normalized_string)
    def test_from_string_single(self):
        message = FileUtilities.get_file_string(
            Path(self.message_dir) / 'soapfault_response_single_error.xml')
        fault: SOAPFault = SOAPFault.from_string({}, message)
        self.assertEqual(fault.fault_code, 'SOAP:Server')
        self.assertEqual(fault.fault_string, 'Application Exception')
        self.assertEqual(len(fault.error_list), 1)

        self.assertEqual(fault.error_list[0]['codeContext'],
                         'urn:nhs:names:error:tms')
        self.assertEqual(fault.error_list[0]['errorCode'], '200')
        self.assertEqual(fault.error_list[0]['severity'], 'Error')
        self.assertEqual(fault.error_list[0]['location'], 'Not Supported')
        self.assertEqual(fault.error_list[0]['description'],
                         'System failure to process message - default')
    def test_should_return_success_response_with_valid_json(self):
        """
        Simple assertion of correct values returned from the response parsing method
        """
        input_xml = FileUtilities.get_file_string(
            str(self.xmlFileDir / 'parseSuccessResponse.xml'))
        parsed_data = self.gp_summary_upload_templator.parse_response(
            input_xml)

        self.assertEqual(parsed_data['messageRef'],
                         '9C534C19-C587-4463-9AED-B76F715D3EA3')
        self.assertEqual(parsed_data['messageId'],
                         '2E372546-229A-483F-9B11-EF46ABF3178C')
        self.assertEqual(parsed_data['creationTime'], '20190923112609')
        self.assertEqual(parsed_data['messageDetail'],
                         'GP Summary upload successful')
class DataframeUtilitiesProject:
    """ Returns dataframes either normally indexed or column indexed"""
    FILE_PATH = FileUtilities.get_abs_path(
        "../../Course_Materials_Part2/Video_Lecture_NBs/")  # noqa: E501

    @classmethod
    def get_dataframe(cls, csv_file):
        """ Returns a normally indexed dataframe """
        source_file = cls.FILE_PATH + csv_file
        return pd.read_csv(source_file)

    @classmethod
    def get_indexed_dataframe(cls, csv_file, index_column):
        """ Returns a dataframe indexed on the specified index_column """
        source_file = cls.FILE_PATH + csv_file
        return pd.read_csv(source_file, index_col=index_column)
Example #30
0
class Check(ABC):

    soap_body = "./soap:Body"
    distribution_envelope = soap_body + "/itk:DistributionEnvelope"
    manifest_tag = distribution_envelope + "/itk:header/itk:manifest"
    basic_success_message = FileUtilities.get_file_string(
        str(XML_PATH / 'basic_success_response.xml'))

    namespaces = {
        'soap': 'http://schemas.xmlsoap.org/soap/envelope/',
        'a': 'http://www.etis.fskab.se/v1.0/ETISws',
        'wsa': 'http://www.w3.org/2005/08/addressing',
        'itk': 'urn:nhs-itk:ns:201005'
    }

    def __init__(self, message):
        self.message_tree = message

    @abstractmethod
    def check(self):
        """
        An abstract method called by the validator to run the check
        :return: fail flag, error message
        """
        pass

    def get_manifest_count(self):
        """
        Extracts the count on the manifest tag in the message
        :return: manifest count as a string
        """
        return self.message_tree.find(self.manifest_tag,
                                      self.namespaces).attrib['count']

    def get_payload_count(self):
        """
        Extracts the count on the payloads tag in the message
        :return: payloads count as a string
        """
        return self.message_tree.find(
            self.distribution_envelope + "/itk:payloads",
            self.namespaces).attrib['count']

    def build_error_message(self, error):
        builder = PystacheMessageBuilder(str(TEMPLATE_PATH),
                                         'base_error_template')
        return builder.build_message({"errorMessage": error})