def test_handle_ellipse(self, mock_outer, mock_cov, mock_def_route): # Mock for apply_policy_settings. mock_outer.find_service_for_ellipse = MagicMock() expected = lostservice.model.responses.FindServiceResponse() mock_outer.find_service_for_ellipse.return_value = { 'response': expected } mock_cov.check_coverage = MagicMock() mock_cov.check_coverage.return_value = 'some.server.name' mock_def_route.check_default_route = MagicMock() mock_def_route.check_default_route.side_effect = \ NotFoundException('The server could not find an answer to the query.') target = lostservice.handling.core.FindServiceHandler( mock_outer, mock_cov, mock_def_route) model = lostservice.model.requests.FindServiceRequest() model.location = lostservice.model.location.Location() model.location.location = lostservice.model.geodetic.Ellipse() with self.assertRaises(NotFoundException) as context: actual = target.handle_request(model, {}) mock_outer.find_service_for_ellipse.assert_called_once() mock_outer.find_service_for_ellipse.assert_called_with(model) self.assertTrue('The server could not find an answer to the query.' in str(context.exception)) self.assertTrue(actual is expected, 'Response did not match expected value.')
def handle_request(self, request, context): """ Entry point for request handling. :param request: The request :type request: A subclass of :py:class:`ListServicesByLocationRequest` :param context: The request context. :type context: ``dict`` :return: The response. :rtype: :py:class:`ListServicesByLocationResponse` """ try: self.check_coverage(request.location.location) except Exception: raise response = None if type(request.location.location) is Point: response = self._outer.list_services_by_location_for_point(request) elif type(request.location.location) is Circle: response = self._outer.list_services_by_location_for_circle( request) elif type(request.location.location) is Ellipse: response = self._outer.list_services_by_location_for_ellipse( request) elif type(request.location.location) is Arcband: response = self._outer.list_service_by_location_for_arcband( request) elif type(request.location.location) is Polygon: response = self._outer.list_services_by_location_for_polygon( request) elif type(request.location.location) is CivicAddress: response = self._outer.list_services_by_location_for_civicaddress( request) else: logger.error('Invalid location type.') raise BadRequestException('Invalid location type.') if response is not None: logger.debug('Response found!') return_value = { 'response': response['response'], 'latitude': response['latitude'], 'longitude': response['longitude'] } return return_value else: logger.error( f'Unable to find an answer to the query for {request.location.location}.' ) raise NotFoundException( 'The server could not find an answer to the query.')
def check_default_route(self, request): """ Check if there is a default route for the passed in request :param request: a Find Service Request :type request FindServiceRequest :return: The mapping if there is a default found """ # Check for default routes # if there are none then throw a NotFoundException (return a notFound LoST error) default_route_uri = None if type(request.location.location) is CivicAddress: default_route_uri = self._get_default_civic_route(request) else: default_route_uri = self._get_default_route(request) if default_route_uri is None: logger.warning( f'No default route URI found for URN: {request.service}') raise NotFoundException( 'The server could not find an answer to the query.') else: logger.debug(f'Using default route URI: {default_route_uri}') # Create a default mapping given just a uri new_dict = { 'serviceurn': request.service, 'routeuri': default_route_uri, 'displayname': '', 'srcunqid': str(uuid.uuid4()), 'servicenum': '', 'updatedate': str(datetime.datetime.utcnow()), 'default_route_used': True } default_mapping = [new_dict] return default_mapping
def handle_request(self, request, context): """ Entry point for request handling. :param request: The request :type request: A subclass of :py:class:`FindServiceRequest` :param context: The request context. :type context: ``dict`` :return: The response. :rtype: :py:class:`FindServiceResponse` """ try: self.check_coverage(request.location.location) except Exception: raise try: response = None if type(request.location.location) is Point: response = self._outer.find_service_for_point(request) elif type(request.location.location) is Circle: response = self._outer.find_service_for_circle(request) elif type(request.location.location) is Ellipse: response = self._outer.find_service_for_ellipse(request) elif type(request.location.location) is Arcband: response = self._outer.find_service_for_arcband(request) elif type(request.location.location) is Polygon: response = self._outer.find_service_for_polygon(request) elif type(request.location.location) is CivicAddress: response = self._outer.find_service_for_civicaddress(request) else: logger.error('Invalid location type.') raise BadRequestException('Invalid location type.') except NotFoundException: if type(request.location.location) is CivicAddress: # check if default route exists, if not raise the same exception mapping = self._default_route_handler.check_default_route( request) # build the response with this mapping outer_response = self._outer._build_response( [], request.location.id, mapping, request.nonlostdata) response = { 'response': outer_response, 'latitude': 0.0, 'longitude': 0.0 } else: raise NotFoundException( 'The server could not find an answer to the query.') return_value = {} # If it's not a CivicAddress and there are no mappings, then check for a default route. # Unlike FindCivic which throws an exception if it can't find a resolution, geodetic # requests return nothing for the mapping an empty list if type(request.location.location) is not CivicAddress and \ (response['response'].mappings is None or len(response['response'].mappings) == 0): # the following function can throw a NotFoundException, In that case since we've exhausted all # tries we let it get caught by execute_query in app.py (which returns a not found message) mapping = self._default_route_handler.check_default_route(request) # build the response with this mapping response['response'] = self._outer._build_response( [], request.location.id, mapping, request.nonlostdata) return_value['latitude'] = response['latitude'] return_value['longitude'] = response['longitude'] return_value['response'] = response['response'] return return_value
def run_civic_location_search(self, locator, offset_distance, civic_request): """ Creates a dictionary of values to pass into the civvy library to run civic address match queries. :param locator: :param offset_distance: the distance to offset the resultant point of an RCL match. :param civic_request: int :return: a collection of results from the civic location queries. """ # Make sure we have a locator to use first. if locator is not None: civvy_obj = civic_request.location.location # Create dictionary of values from request into a civic location dictionary for civvy to use. civic_dict = {} civic_dict['country'] = civvy_obj.country if civvy_obj.a1: civic_dict['a1'] = civvy_obj.a1 if civvy_obj.a2: civic_dict['a2'] = civvy_obj.a2 if civvy_obj.a3: civic_dict['a3'] = civvy_obj.a3 if civvy_obj.a4: civic_dict['a4'] = civvy_obj.a4 if civvy_obj.a5: civic_dict['a5'] = civvy_obj.a5 if civvy_obj.a6: civic_dict['a6'] = civvy_obj.a6 if civvy_obj.rd: civic_dict['rd'] = civvy_obj.rd if civvy_obj.pod: civic_dict['pod'] = civvy_obj.pod if civvy_obj.sts: civic_dict['sts'] = civvy_obj.sts if civvy_obj.hno: civic_dict['hno'] = civvy_obj.hno if civvy_obj.hns: civic_dict['hns'] = civvy_obj.hns if civvy_obj.lmk: civic_dict['lmk'] = civvy_obj.lmk if civvy_obj.loc: civic_dict['loc'] = civvy_obj.loc if civvy_obj.flr: civic_dict['flr'] = civvy_obj.flr if civvy_obj.nam: civic_dict['nam'] = civvy_obj.nam if civvy_obj.pc: civic_dict['pc'] = civvy_obj.pc if civvy_obj.pom: civic_dict['pom'] = civvy_obj.pom if civvy_obj.hnp: civic_dict['hnp'] = civvy_obj.hnp if civvy_obj.lmkp: civic_dict['lmkp'] = civvy_obj.lmkp if civvy_obj.mp: civic_dict['mp'] = civvy_obj.mp # We can create several civic addresses and pass them to the locator. civic_address = CivicAddress(**civic_dict) logger.info('Executing civic address query') # Let's get the results for this civic address. logger.debug( 'Running civic address query for list services through civvy.') locator_results = locator.locate_civic_address( civic_address=civic_address, offset_distance=offset_distance) return locator_results else: # Who did this, and why are you doing it?! logger.error('Locator object not passed.') raise NotFoundException( 'Locator not defined, cannot complete civic address request.', None) return None
def format(self, data): """ Formats a findService LoST response. :param data: The response to be formatted. :type data: :py:class:`FindServiceResponse` :return: The formatted output. :rtype: :py:class:`_ElementTree` """ if data.mappings is None or len(data.mappings) == 0: logger.warning('Could not find an answer to the request.', None) raise NotFoundException('Could not find an answer to the request.', None) # create the root element of the xml response. xml_response = lxml.etree.Element('findServiceResponse', nsmap={ None: LOST_URN, GML_PREFIX: GML_URN }) for item in data.mappings: # Add mapping sub element mapping = lxml.etree.SubElement(xml_response, 'mapping', attrib={ 'expires': item.expires, 'lastUpdated': str(item.last_updated), 'source': item.source, 'sourceId': item.source_id }) # add the displayname, serviceurn, routeuri, servicenum to mapping services_element = lxml.etree.SubElement(mapping, 'service') services_element.text = item.service_urn if type(item) is ResponseMapping: services_element = lxml.etree.SubElement( mapping, 'displayName') services_element.text = item.display_name attr = services_element.attrib attr['{http://www.w3.org/XML/1998/namespace}lang'] = 'en' services_element = lxml.etree.SubElement(mapping, 'uri') services_element.text = item.route_uri services_element = lxml.etree.SubElement( mapping, 'serviceNumber') services_element.text = item.service_number # if boundary_value = None do not add serviceBoundary tag to the response (override setting) # if boundary_value = "" then include serviceBoundaryReference tag # if boundary_value contains value then include serviceBoundary tag if item.boundary_value is not None: if item.boundary_value == "": attr_element = collections.OrderedDict() attr_element['source'] = item.source attr_element['key'] = item.source_id lxml.etree.SubElement(mapping, 'serviceBoundaryReference', attrib=attr_element) else: # TODO - fix the profile. services_element = lxml.etree.SubElement( mapping, 'serviceBoundary', profile='geodetic-2d') final_gml_as_xml = io.StringIO( '''<root xmlns:gml="{0}">{1}</root>'''.format( GML_URN, item.boundary_value)) final_gml = etree.parse(final_gml_as_xml).getroot() services_element.extend(final_gml) elif type(item) is AdditionalDataResponseMapping: services_element = lxml.etree.SubElement(mapping, 'uri') services_element.text = item.adddatauri if hasattr(item, "locationValidation"): # add the validation element validation_element = lxml.etree.SubElement( xml_response, 'locationValidation') if item.locationValidation.get("valid"): valid_element = lxml.etree.SubElement( validation_element, 'valid') valid_element.text = item.locationValidation.get("valid") if item.locationValidation.get("invalid"): invalid_element = lxml.etree.SubElement( validation_element, 'invalid') invalid_element.text = item.locationValidation.get( "invalid") if item.locationValidation.get("unchecked"): unchecked_element = lxml.etree.SubElement( validation_element, 'unchecked') unchecked_element.text = item.locationValidation.get( "unchecked") # add the path element path_element = lxml.etree.SubElement(xml_response, 'path') # not generate a 'via' element for each source. if data.path is not None: for a_path in data.path: via_element = lxml.etree.SubElement(path_element, 'via', attrib={'source': a_path}) lxml.etree.SubElement(xml_response, 'locationUsed', attrib={'id': data.location_used}) # Add NonLoSTdata items into response (pass though items) for nonlost_item in data.nonlostdata: xml_response.append(nonlost_item) return xml_response