def perform_request(self): """ Perform the validation. Uses https://github.com/p1c2u/openapi-spec-validator on the specfile (dict) returned from the OpenAPI endpoint. """ # Step 1 basic sanity check result = Result(True, 'OpenAPI Validation Test') result.start() api_doc = None try: wfs3 = WebFeatureService(self._resource.url, version='3.0') # TODO: OWSLib 0.17.1 has no call to '/api yet. # Build endpoint URL (may have f=json etc) api_url = wfs3._build_url('api') # Get OpenAPI spec from endpoint as dict once api_doc = requests.get(api_url).json() # Basic sanity check for attr in ['components', 'paths', 'openapi']: val = api_doc.get(attr, None) if val is None: msg = '/api: missing attr: %s' % attr result.set(False, msg) break except Exception as err: result.set(False, str(err)) result.stop() self.result.add_result(result) # No use to proceed if OpenAPI basics not complied if api_doc is None or result.success is False: return # ASSERTION: /api exists, next OpenAPI Validation # Step 2 detailed OpenAPI Compliance test result = Result(True, 'Validate OpenAPI Compliance') result.start() try: # Call the openapi-spec-validator and iterate through errors errors_iterator = openapi_v3_spec_validator.iter_errors(api_doc) for error in errors_iterator: # Add each validation error as separate Result object result = push_result(self, result, False, str(error), 'OpenAPI Compliance Result') except Exception as err: result.set(False, 'OpenAPI Validation err: e=%s' % str(err)) result.stop() # Add to overall Probe result self.result.add_result(result)
def perform_request(self): """ Perform the validation. Uses https://github.com/p1c2u/openapi-spec-validator on the specfile (dict) returned from the OpenAPI endpoint. """ # Step 1 basic sanity check result = Result(True, 'OpenAPI Sanity Check') result.start() api_doc = None try: oa_feat = Features(self._resource.url, headers=self.get_request_headers()) set_accept_header(oa_feat, type_for_link( oa_feat.links, 'service-desc')) api_doc = oa_feat.api() # Basic sanity check for attr in ['components', 'paths', 'openapi']: val = api_doc.get(attr, None) if val is None: msg = 'OpenAPI doc: missing attr: %s' % attr result.set(False, msg) break except Exception as err: result.set(False, '%s:%s' % (result.message, str(err))) result.stop() self.result.add_result(result) # No use to proceed if OpenAPI basics not complied if api_doc is None or result.success is False: return # ASSERTION: OpenAPI doc exists, next OpenAPI Validation # Step 2 detailed OpenAPI Compliance test result = Result(True, 'Validate OpenAPI Compliance') result.start() try: # Call the openapi-spec-validator and iterate through errors errors_iterator = openapi_v3_spec_validator.iter_errors(api_doc) for error in errors_iterator: # Add each validation error as separate Result object result = push_result( self, result, False, str(error), 'OpenAPI Compliance Result') except Exception as err: result.set(False, '%s:%s' % (result.message, str(err))) result.stop() # Add to overall Probe result self.result.add_result(result)
def perform_request(self): """ Perform the request. See https://github.com/geopython/OWSLib/blob/ master/tests/doctests/wms_GeoServerCapabilities.txt """ # Test capabilities doc result = Result(True, 'Test Capabilities') result.start() try: wms = WebMapService(self._resource.url) title = wms.identification.title self.log('response: title=%s' % title) except Exception as err: result.set(False, str(err)) # Do more rigorous stuff here below result.stop() self.result.add_result(result)
def perform_request(self): """ Perform the drilldown. """ # Be sure to use bare root URL http://.../FeatureServer fs_url = self._resource.url.split('?')[0] # Assemble request templates with root FS URL req_tpl = { 'fs_caps': fs_url + '?f=json', 'layer_caps': fs_url + '/%d?f=json', 'get_features': fs_url + '/%d/query?where=1=1' '&outFields=*&resultOffset=0&' 'resultRecordCount=1&f=json', 'get_feature_by_id': fs_url + '/%d/query?where=%s=%s&outFields=*&f=json' } # 1. Test top Service endpoint existence result = Result(True, 'Test Service Endpoint') result.start() layers = [] try: fs_caps = self.perform_esrifs_get_request(req_tpl['fs_caps']) for attr in ['currentVersion', 'layers']: val = fs_caps.get(attr, None) if val is None: msg = 'Service: missing attr: %s' % attr result = push_result(self, result, False, msg, 'Test Layer:') continue layers = fs_caps.get('layers', []) except Exception as err: result.set(False, str(err)) result.stop() self.result.add_result(result) if len(layers) == 0: return # 2. Test each Layer Capabilities result = Result(True, 'Test Layer Capabilities') result.start() layer_ids = [] layer_caps = [] try: for layer in layers: layer_ids.append(layer['id']) for layer_id in layer_ids: layer_caps.append( self.perform_esrifs_get_request(req_tpl['layer_caps'] % layer_id)) except Exception as err: result.set(False, str(err)) result.stop() self.result.add_result(result) if self._parameters['drilldown_level'] == 'basic': return # ASSERTION: will do full drilldown from here # 3. Test getting Features from Layers result = Result(True, 'Test Layers') result.start() layer_id = 0 try: for layer_id in layer_ids: try: features = self.perform_esrifs_get_request( req_tpl['get_features'] % layer_id) obj_id_field_name = features['objectIdFieldName'] features = features['features'] if len(features) == 0: continue # At least one Feature: use first and try to get by id object_id = features[0]['attributes'][obj_id_field_name] feature = self.perform_get_request( req_tpl['get_feature_by_id'] % (layer_id, obj_id_field_name, str(object_id))).json() feature = feature['features'] if len(feature) == 0: msg = 'layer: %d: missing Feature - id: %s' \ % (layer_id, str(object_id)) result = push_result(self, result, False, msg, 'Test Layer: %d' % layer_id) except Exception as e: msg = 'GetLayer: id=%d: err=%s ' \ % (layer_id, str(e)) result = push_result(self, result, False, msg, 'Test Get Features:') continue except Exception as err: result.set(False, 'Layer: id=%d : err=%s' % (layer_id, str(err))) result.stop() # Add to overall Probe result self.result.add_result(result)
def perform_request(self): """ Perform the drilldown. See https://github.com/geopython/OWSLib/blob/ master/tests/doctests/wfs3_GeoServerCapabilities.txt """ wfs3 = None collections = None # 1.1 Test Landing Page result = Result(True, 'Test Landing Page') result.start() try: wfs3 = WebFeatureService(self._resource.url, version='3.0') except Exception as err: result.set(False, '%s:%s' % (result.message, str(err))) result.stop() self.result.add_result(result) # 1.2 Test top endpoints existence: /conformance result = Result(True, 'conformance endpoint exists') result.start() try: wfs3.conformance() except Exception as err: result.set(False, str(err)) result.stop() self.result.add_result(result) # 1.3 Test top endpoints existence: /collections result = Result(True, 'Get collections') result.start() try: collections = wfs3.collections() except Exception as err: result.set(False, '%s:%s' % (result.message, str(err))) result.stop() self.result.add_result(result) # 1.4 Test top endpoints existence: OpenAPI doc result = Result(True, 'Test OpenAPI Doc') result.start() try: # TODO: OWSLib 0.17.1 has no call to '/api yet, upgrade when GHC # supports Py3 to 0.19+. api = wfs3_api_doc(wfs3) for attr in ['components', 'paths', 'openapi']: val = api.get(attr, None) if val is None: msg = 'missing attr: %s' % attr result = push_result(self, result, False, msg, 'Test OpenAPI doc') continue except Exception as err: result.set(False, '%s:%s' % (result.message, str(err))) result.stop() self.result.add_result(result) if self._parameters['drilldown_level'] == 'basic': return # ASSERTION: will do full drilldown, level 2, from here # 2. Test layers # TODO: use parameters to work on less/more drilling # "full" could be all layers. result = Result(True, 'Test Collections') result.start() coll_id = '' try: for collection in collections: coll_id = collection['id'] coll_id = coll_id try: coll = wfs3.collection(coll_id) # TODO: Maybe also add crs for attr in ['id', 'links']: val = coll.get(attr, None) if val is None: msg = '%s: missing attr: %s' \ % (coll_id, attr) result = push_result(self, result, False, msg, 'Test Collection') continue except Exception as e: msg = 'GetCollection %s: OWSLib err: %s ' \ % (str(e), coll_id) result = push_result(self, result, False, msg, 'Test GetCollection') continue try: items = wfs3.collection_items(coll_id, limit=1) except Exception as e: msg = 'GetItems %s: OWSLib err: %s ' % (str(e), coll_id) result = push_result(self, result, False, msg, 'Test GetItems') continue features = items.get('features', None) if features is None: msg = 'GetItems %s: No features attr' % coll_id result = push_result(self, result, False, msg, 'Test GetItems') continue type = items.get('type', '') if type != 'FeatureCollection': msg = '%s:%s type not FeatureCollection: %s' \ % (coll_id, type, val) result = push_result(self, result, False, msg, 'Test GetItems') continue if len(items['features']) > 0: fid = items['features'][0]['id'] try: item = wfs3.collection_item(coll_id, fid) except Exception as e: msg = 'GetItem %s: OWSLib err: %s' \ % (str(e), coll_id) result = push_result(self, result, False, msg, 'Test GetItem') continue for attr in \ ['id', 'links', 'properties', 'geometry', 'type']: val = item.get(attr, None) if val is None: msg = '%s:%s missing attr: %s' \ % (coll_id, str(fid), attr) result = push_result(self, result, False, msg, 'Test GetItem') continue if attr == 'type' and val != 'Feature': msg = '%s:%s type not Feature: %s' \ % (coll_id, str(fid), val) result = push_result(self, result, False, msg, 'Test GetItem') continue except Exception as err: result.set(False, 'Collection err: %s : e=%s' % (coll_id, str(err))) result.stop() # Add to overall Probe result self.result.add_result(result)
def perform_request(self): """ Perform the drilldown. See https://github.com/geopython/OWSLib/blob/ master/tests/doctests/wms_GeoServerCapabilities.txt """ wms = None # 1. Test capabilities doc, parses result = Result(True, 'Test Capabilities') result.start() try: wms = WebMapService(self._resource.url) title = wms.identification.title self.log('response: title=%s' % title) except Exception as err: result.set(False, str(err)) result.stop() self.result.add_result(result) # 2. Test layers # TODO: use parameters to work on less/more drilling # "full" could be all layers. result = Result(True, 'Test Layers') result.start() try: # Pick a random layer layer_name = random.sample(wms.contents.keys(), 1)[0] layer = wms[layer_name] # TODO Only use EPSG:4326, later random CRS if 'EPSG:4326' in layer.crsOptions \ and layer.boundingBoxWGS84: # Search GetMap operation get_map_oper = None for oper in wms.operations: if oper.name == 'GetMap': get_map_oper = oper break format = None for format in get_map_oper.formatOptions: if format.startswith('image/'): break # format = random.sample(get_map_oper.formatOptions, 1)[0] self.log('testing layer: %s' % layer_name) layer_bbox = layer.boundingBoxWGS84 wms.getmap(layers=[layer_name], styles=[''], srs='EPSG:4326', bbox=(layer_bbox[0], layer_bbox[1], layer_bbox[2], layer_bbox[3]), size=(256, 256), format=format, transparent=False) self.log('WMS GetMap: format=%s' % format) # Etc, to be finalized except Exception as err: result.set(False, str(err)) result.stop() # Add to overall Probe result self.result.add_result(result)
def perform_request(self): """ Perform the reporting. """ # Be sure to use bare root URL http://.../FeatureServer ghc_url = self._resource.url.split('?')[0] # Assemble request templates with root FS URL summary_url = ghc_url + '/api/v1.0/summary/' # 1. Get the summary (JSON) report from GHC endpoint result = Result(True, 'Get GHC Report') result.start() try: response = self.perform_get_request(summary_url) status = response.status_code overall_status = status / 100 if overall_status in [4, 5]: raise Exception('HTTP Error status=%d reason=%s' % (status, response.reason)) summary_report = response.json() except Exception as err: msg = 'Cannot get summary from %s err=%s' % \ (summary_url, str(err)) result.set(False, msg) result.stop() self.result.add_result(result) return # ASSERTION - summary report fetch ok # 2. Do email reporting with summary report result = Result(True, 'Send Email') result.start() try: config = App.get_config() # Create message body with report template_vars = {'summary': summary_report, 'config': config} msg_body = render_template2('status_report_email.txt', template_vars) resource = self._resource to_addrs = self._parameters.get('email', None) if to_addrs is None: raise Exception( 'No emails set for GHCEmailReporter in resource=%s' % resource.identifier) to_addrs = to_addrs.replace(' ', '') if len(to_addrs) == 0: raise Exception( 'No emails set for GHCEmailReporter in resource=%s' % resource.identifier) to_addrs = to_addrs.split(',') msg = MIMEText(msg_body, 'plain', 'utf-8') msg['From'] = formataddr( (config['GHC_SITE_TITLE'], config['GHC_ADMIN_EMAIL'])) msg['To'] = ', '.join(to_addrs) msg['Subject'] = '[%s] %s' % (config['GHC_SITE_TITLE'], gettext('Status summary')) from_addr = '%s <%s>' % (config['GHC_SITE_TITLE'], config['GHC_ADMIN_EMAIL']) msg_text = msg.as_string() send_email(config['GHC_SMTP'], from_addr, to_addrs, msg_text) except Exception as err: msg = 'Cannot send email. Contact admin: ' LOGGER.warning(msg + ' err=' + str(err)) result.set(False, 'Cannot send email: %s' % str(err)) result.stop() # Add to overall Probe result self.result.add_result(result)
def perform_request(self): """ Perform the drilldown. See https://github.com/geopython/OWSLib/blob/ master/tests/doctests/wfs3_GeoServerCapabilities.txt """ wfs3 = None collections = None # 1. Test top endpoints existence result = Result(True, 'Test Top Endpoints') result.start() try: wfs3 = WebFeatureService(self._resource.url, version='3.0') wfs3.conformance() # TODO: OWSLib 0.17.1 has no call to '/api yet. url = wfs3._build_url('api') api = requests.get(url).json() for attr in ['components', 'paths', 'openapi']: val = api.get(attr, None) if val is None: msg = '/api: missing attr: %s' % attr result = push_result(self, result, False, msg, 'Test Collection') continue collections = wfs3.collections() except Exception as err: result.set(False, str(err)) result.stop() self.result.add_result(result) if self._parameters['drilldown_level'] == 'basic': return # ASSERTION: will do full drilldown from here # 2. Test layers # TODO: use parameters to work on less/more drilling # "full" could be all layers. result = Result(True, 'Test Collections') result.start() coll_name = '' try: for collection in collections: coll_name = collection['name'] coll_name = coll_name.encode('utf-8') try: coll = wfs3.collection(coll_name) # TODO: Maybe also add crs for attr in ['name', 'links']: val = coll.get(attr, None) if val is None: msg = '%s: missing attr: %s' \ % (coll_name, attr) result = push_result(self, result, False, msg, 'Test Collection') continue except Exception as e: msg = 'GetCollection %s: OWSLib err: %s ' \ % (str(e), coll_name) result = push_result(self, result, False, msg, 'Test GetCollection') continue try: items = wfs3.collection_items(coll_name, limit=1) except Exception as e: msg = 'GetItems %s: OWSLib err: %s ' % (str(e), coll_name) result = push_result(self, result, False, msg, 'Test GetItems') continue features = items.get('features', None) if features is None: msg = 'GetItems %s: No features attr' % coll_name result = push_result(self, result, False, msg, 'Test GetItems') continue type = items.get('type', '') if type != 'FeatureCollection': msg = '%s:%s type not FeatureCollection: %s' \ % (coll_name, type, val) result = push_result(self, result, False, msg, 'Test GetItems') continue if len(items['features']) > 0: fid = items['features'][0]['id'] try: item = wfs3.collection_item(coll_name, fid) except Exception as e: msg = 'GetItem %s: OWSLib err: %s' \ % (str(e), coll_name) result = push_result(self, result, False, msg, 'Test GetItem') continue for attr in \ ['id', 'links', 'properties', 'geometry', 'type']: val = item.get(attr, None) if val is None: msg = '%s:%s missing attr: %s' \ % (coll_name, str(fid), attr) result = push_result(self, result, False, msg, 'Test GetItem') continue if attr == 'type' and val != 'Feature': msg = '%s:%s type not Feature: %s' \ % (coll_name, str(fid), val) result = push_result(self, result, False, msg, 'Test GetItem') continue except Exception as err: result.set(False, 'Collection err: %s : e=%s' % (coll_name, str(err))) result.stop() # Add to overall Probe result self.result.add_result(result)