def run(self): if self.metadata_container is None: return test_name = "Storage Services CRUD test" print "MESSAGE::%s starting" % test_name print "TEST_CASE::API crawling" api_explorer = ApiExplorer(self.metadata_container, self.configuration) self.discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) print "STATUS::{status}".format(status=status) requirements = [ Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1), Requirement(MetadataConstants.STORAGE_SERVICE, min=1), Requirement(MetadataConstants.LOGICAL_DRIVE_COLLECTION, min=1), Requirement(MetadataConstants.REMOTE_TARGET_COLLECTION, min=1), Requirement(MetadataConstants.LOGICAL_DRIVE, min=2) ] preconditions = Preconditions(self.metadata_container, requirements) status = preconditions.validate(self.discovery_container) if status == ValidationStatus.FAILED: self.set_status_blocked() return self.api_caller = ApiCaller(self.configuration) status = ValidationStatus.join_statuses(status, self.crud_logical_drive()) status = ValidationStatus.join_statuses(status, self.crud_remote_target()) print "MESSAGE::%s overall status: %s" % (test_name, ColorPrinter.format_status(status))
def run(self): api_explorer = ApiExplorer(self.metadata_container, self.configuration) discovery_container, status = api_explorer.discover( MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) status = ValidationStatus.PASSED catalog = expanduser( "~" ) + "/.cts/tests/Rack_Scale_2_5_Storage_Services/required/tests_archeo_ss/" for test in listdir(catalog): with open(catalog + test) as f: data = json.load(f) test_name = data["name"] print "TEST_CASE::Validating section " + ColorPrinter.format_text(test_name, color=ColorPrinter.YELLOW_FORE) + \ " of architecture specification" status_of_test = ArchSpecTests().parse_json( discovery_container, data) if _skip_pnc_tests_if_resource_is_not_available(test) and \ (status_of_test == ValidationStatus.FAILED): status = ValidationStatus.join_statuses( status, ValidationStatus.PASSED_WITH_WARNINGS) print "MESSAGE:: CTS can not detect a PNC. Skipping this tests" else: status = ValidationStatus.join_statuses( status, status_of_test) print "STATUS::{status}".format(status=status_of_test) print "MESSAGE::All tests finished" print "STATUS::{status}".format(status=status)
def run(self): print "TEST_CASE::API crawling" api_explorer = ApiExplorer(self.metadata_container, self.configuration) discovery_container, status = api_explorer.discover( MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) print "STATUS::{status}".format(status=status) print "TEST_CASE::Checking for mandatory entities" requirements = [ Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1) ] preconditions = Preconditions(self.metadata_container, requirements) self.set_validation_status(preconditions.validate(discovery_container)) validation_functions = [ self.at_least_one_compute_module_in_pod, self.at_least_one_ethernet_switch_in_the_pod, self.ethernet_based_fabric_for_network_connectivity, self.secure_communication_channel, self.node_reset_support, self.manual_tests, self.validate_all_or_none_chassis_have_location, self.validate_path_using_contains_property, self.power_monitoring_support ] for validation_function in validation_functions: try: validation_function(discovery_container) except Exception as err: print "ERROR::Exception %s" % err self.set_validation_status(ValidationStatus.FAILED) print "SCREEN::Overall status: %s" % self.validation_status
def run(self): if self.metadata_container is None: return self.chosen_endpoint, self.chosen_zone, self.chosen_volume, self.chosen_volume_collection = (None,)*4 self.initiator_endpoint, self.target_endpoint, self.zone_endpoint, self.created_volume = (None,)*4 test_name = "Storage Services CRUD test" print "MESSAGE::%s starting" % test_name print "TEST_CASE::API crawling" api_explorer = ApiExplorer(self.metadata_container, self.configuration) self.discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) print "STATUS::{status}".format(status=status) requirements = [ Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1), Requirement(MetadataConstants.STORAGE_SERVICE, min=1), Requirement(MetadataConstants.VOLUME, min=1), Requirement(MetadataConstants.VOLUME_COLLECTION, min=1) ] preconditions = Preconditions(self.metadata_container, requirements) status = preconditions.validate(self.discovery_container) if status == ValidationStatus.FAILED: self.set_status_failed() return self.api_caller = ApiCaller(self.configuration) status = ValidationStatus.join_statuses(status, self.crud_fabrics_target()) print "MESSAGE::%s overall status: %s" % (test_name, ColorPrinter.format_status(status))
def run(self): try: json_loader = JsonLoader() except OSError: print('ERROR:: No proper action found. Please reinstall a CTS') return if self.metadata_container is None: return if not self.configuration.UseCase: json_loader.print_available_actions() return try: actions_to_take = json_loader.get_use_case( self.configuration.UseCase) specific_action = json_loader.get_use_case_action( actions_to_take['filepath']) except (IndexError, TypeError): json_loader.print_available_actions() print('ERROR:: The selected action was not found. Exiting..') return print('TEST_CASE::API crawling') api_explorer = ApiExplorer(self.metadata_container, self.configuration) self.discovery_container, status = api_explorer.discover( MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) configuration = self.configuration self.api_caller = ApiCaller(configuration) print('TEST_CASE::Action Runner') status = self.action_runner(specific_action) print('STATUS::{status}'.format(status=status))
def test_discovery_from_nested_additional_properties(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> <Property Name="Oem" Type="N.Oem"> </Property> </EntityType> <ComplexType Name="Oem" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> </ComplexType> <ComplexType Name="Inner" Abstract="false"> <NavigationProperty Name="Link" Type="N.Referenced" ContainsTarget="true"> </NavigationProperty> </ComplexType> <EntityType Name="Referenced" Abstract="false"> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "#N.Outer", "Oem": { "additional_property": { "@odata.type": "#N.Inner", "Link": { "@odata.id": "/this/is/the/link/to/be/discovered" }, } } } referenced = \ { "@odata.id": "referenced.id", "@odata.type": "#N.Referenced", } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, referenced, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(2, get_resource.call_count) self.assertNotIn("ERROR::", '\n'.join(output))
def test_validate_elements_of_collection_with_elements_referenced_by_out_of_range_json_pointer(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <NavigationProperty Name="MyCollection" Type="Collection(ReferencedEntity)" ContainsTarget="true"> <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> </NavigationProperty> </EntityType> <EntityType Name="ReferencedEntity" Abstract="false"> <Property Name="name" Type="Edm.String"/> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "N.Outer", "MyCollection": [ { "@odata.id": "/outer#MyCollection/0" }, { "@odata.id": "/outer#MyCollection/2" # pointer out of range } ] } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration(**dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch('cts_core.commons.api_caller.ApiCaller.get_resource') as get_resource: get_resource.side_effect = [(Link('url1', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, Link('url1', 'netloc')), (Link('url2', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, Link('url2', 'netloc')), (Link('url3', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, Link('url3', 'netloc'))] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(3, get_resource.call_count) self.assertIn( 'ERROR::JSON pointer exception while dereferencing /MyCollection/2', ';'.join(output)) requirements = [ ] validator = MetadataGetValidator(metadata_container, requirements) with StdoutCapture() as output: self.assertEqual(ValidationStatus.PASSED, validator.validate(discovery_container)) self.assertEqual(0, len(re.findall('ERROR::', ';'.join(output))))
def test_handle_collection_with_typeless_elements_referenced_by_json_pointer( self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <NavigationProperty Name="MyCollection" Type="Collection(ReferencedEntity)" ContainsTarget="true"> <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> </NavigationProperty> </EntityType> <EntityType Name="ReferencedEntity" Abstract="false"> <Property Name="name" Type="Edm.String"/> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "N.Outer", "MyCollection": [ { # implicit odata.type = ReferencedEntity "@odata.id": "/outer#MyCollection/0", "name": "MyName 0" }, { # implicit odata_type = ReferencedEntity "@odata.id": "/outer#MyCollection/1", "name": "MyName 1" } ] } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings( metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch('cts_core.commons.api_caller.ApiCaller.get_resource' ) as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(3, get_resource.call_count) self.assertEqual(0, len(re.findall('ERROR::', ';'.join(output))))
def run(self): print "TEST_CASE::API crawling" api_explorer = ApiExplorer(self.metadata_container, self.configuration) discovery_container, status = api_explorer.discover( MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) print "STATUS::{status}".format(status=status) detected_profile = ValidateProfiles(discovery_container) detected_profile.validate()
def run(self): print "TEST_CASE::API crawling" api_explorer = ApiExplorer(self.metadata_container, self.configuration) discovery_container, status = api_explorer.discover( MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) print "STATUS::{status}".format(status=status) MetadataGetValidator( self.metadata_container, RequiredTypes_PSME_2_1).validate(discovery_container)
def run(self): metadata_manager = MetadataManager(self.configuration) metadata_manager.load_files() metadata_container = metadata_manager.load_metadata_properties() api_explorer = ApiExplorer("/redfish/v1/", "ServiceRoot.ServiceRoot", metadata_container, self.configuration) discovery_container = api_explorer.process_with_resource(DiscoveryContainer()) discovery_container.keys() status = MetadataPatchValidator(metadata_container, self.configuration).validate(discovery_container) self.set_status(status)
def run(self): print "TEST_CASE::API crawling" api_explorer = ApiExplorer(self.metadata_container, self.configuration) discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) print "STATUS::{status}".format(status=status) requirements = [ Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1) ] MetadataGetValidator(self.metadata_container, requirements).validate(discovery_container)
def test_handle_collection_with_typeless_elements_referenced_by_json_pointer(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <NavigationProperty Name="MyCollection" Type="Collection(ReferencedEntity)" ContainsTarget="true"> <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> </NavigationProperty> </EntityType> <EntityType Name="ReferencedEntity" Abstract="false"> <Property Name="name" Type="Edm.String"/> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "N.Outer", "MyCollection": [ { # implicit odata.type = ReferencedEntity "@odata.id": "/outer#MyCollection/0", "name": "MyName 0" }, { # implicit odata_type = ReferencedEntity "@odata.id": "/outer#MyCollection/1", "name": "MyName 1" } ] } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch('cts_core.commons.api_caller.ApiCaller.get_resource') as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(3, get_resource.call_count) self.assertEqual(0, len(re.findall('ERROR::', ';'.join(output))))
def run(self): if self.metadata_container is None: return print "TEST_CASE::API crawling" api_explorer = ApiExplorer(self.metadata_container, self.configuration) discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) print "STATUS::{status}".format(status=status) MetadataGetValidator(self.metadata_container, RequiredTypes_Storage_2_4).validate(discovery_container) performance_status = self._measuring_request_responses(api_explorer) print("STATUS::{status}".format(status=performance_status))
def run(self): print "TEST_CASE::API crawling" api_explorer = ApiExplorer(self.metadata_container, self.configuration) discovery_container, status = api_explorer.discover( MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) print "STATUS::{status}".format(status=status) validator = MetadataPatchValidator(self.metadata_container, self.configuration, PatchingStrategy2_1(), RequiredTypes_Storage_2_1) validator.validate(discovery_container)
def run(self): print self.configuration.__dict__ metadata_manager = MetadataManager(self.configuration) metadata_manager.load_files() metadata_container = metadata_manager.load_metadata_properties() api_explorer = ApiExplorer("/redfish/v1/", "ServiceRoot.ServiceRoot", metadata_container, self.configuration) discovery_container = api_explorer.process_with_resource(DiscoveryContainer()) discovery_container.keys() status = MetadataPatchValidator(metadata_container, self.configuration).validate(discovery_container) if status: self.set_status_passed() else: self.set_status_failed()
def run(self): if self.metadata_container is None: return print "TEST_CASE::API crawling" api_explorer = ApiExplorer(self.metadata_container, self.configuration) discovery_container, status = api_explorer.discover( MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) print "STATUS::{status}".format(status=status) MetadataGetValidator( self.metadata_container, RequiredTypes_PSME_2_3, skip_check_predicate=SkipCheckPredicate_PSME_2_3).validate( discovery_container)
def run(self): if self.metadata_container is None: return print "TEST_CASE::API crawling" api_explorer = ApiExplorer(self.metadata_container, self.configuration) discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) print "STATUS::{status}".format(status=status) validator = MetadataPatchValidator(self.metadata_container, self.configuration, PatchingStrategy2_4(), RequiredTypes_PODM_2_4, skip_list=self.configuration.IgnoredElements) validator.validate(discovery_container) performance_status = self._measuring_request_responses(api_explorer) print("STATUS::{status}".format(status=performance_status))
def test_discovery_error_if_unexpected_additional_properties(self): """ Entity type used in this test does not accept additional properties. As a result, ApiExplorer is expected to raise an error about unexpected 'additional_property' property. ApiExplorer validate """ metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Property Name="@odata.id" Type="Edm.String"/> <Property Name="@odata.type" Type="Edm.String"/> <Property Name="expected" Type="Edm.Int64"/> <Annotation Term="OData.AdditionalProperties" Bool="false"/> </EntityType> </Schema> """ resource = \ { "@odata.id": "id", "@odata.type": "N.Outer", "expected": 10, "additional_property": 1 } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings( "Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource' ) as get_resource: get_resource.side_effect = [ (Link('link', 'netloc'), RequestStatus.SUCCESS, resource, None) ] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertIn("unexpected properties: [additional_property]", '\n'.join(output))
def run(self): metadata_manager = MetadataManager(self.configuration) metadata_manager.load_files() metadata_container = metadata_manager.load_metadata_properties() api_explorer = ApiExplorer("/redfish/v1/", "ServiceRoot.ServiceRoot", metadata_container, self.configuration) discovery_container = api_explorer.process_with_resource( DiscoveryContainer()) status = MetadataGetValidator(metadata_container).validate( discovery_container) if status: self.set_status_passed() else: self.set_status_failed()
def run(self): if self.metadata_container is None: return print "TEST_CASE::API crawling" api_explorer = ApiExplorer(self.metadata_container, self.configuration) discovery_container, status = api_explorer.discover( MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) print "STATUS::{status}".format(status=status) requirements = [ Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1) ] validator = MetadataPatchValidator(self.metadata_container, self.configuration, PatchingStrategy2_1(), requirements) validator.validate(discovery_container)
def post_resource(self, url, discovery_container, payload=None, acceptable_return_codes=None, wait_if_async=True, expect_location=None, api_endpoint_override=None): """ Sends http POST request to remote endpoint. Throws AsyncOperation if service created task in response to this request. :type url: str :type discovery_container: DiscoveryContainer :type payload: dict :type acceptable_return_codes: list(int) :type wait_if_async: bool """ from cts_core.discovery.api_explorer import ApiExplorer if expect_location is None: expect_location = True _, status, status_code, response_body, headers = \ self._perform_call(url, http_method=HttpMethods.POST, payload=payload, acceptable_return_codes=acceptable_return_codes, api_endpoint_override=api_endpoint_override) # determine if the operation was completed synchronously or asynchronously if status_code == ReturnCodes.ACCEPTED: if not wait_if_async: raise AsyncOperation() status, status_code, response_body, headers = self._wait_for_task(headers, discovery_container, acceptable_ret_codes=acceptable_return_codes) if expect_location and status and not self._skip_refresh_after_request(url): try: # add the created element and discover all its children new_url = self.links_factory.get_resource_link(headers["Location"], api_endpoint_override=api_endpoint_override).link print "MESSAGE::Refreshing {} info".format(new_url) # refresh the collection info _, get_status, get_status_code, _, _ = self.get_resource(url, discovery_container, api_endpoint_override=api_endpoint_override, check_resource_against_metadata=True) _, rediscovery_status = ApiExplorer(discovery_container.metadata_container, self._config_property_reader).discover(new_url, discovery_container.get_expected_odata_type_for_url(new_url), discovery_container) if get_status and rediscovery_status: print "MESSAGE::Refreshed %s and its children info" % new_url else: cts_warning("Refreshing {odata_id:id} after POST generated errors. Get status code: {code}", odata_id=new_url, code=get_status_code) except (KeyError, TypeError) as err: cts_warning( "POST {odata_id:id} Response has no 'Location' header; Error: {err:exception}", odata_id=url, err=err) return status, status_code, response_body, headers
def run(self): api_explorer = ApiExplorer(self.metadata_container, self.configuration) discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) status = ValidationStatus.PASSED catalog = expanduser("~") + "/.cts/tests/Rack_Scale_2_5_PSME/required/tests_archeo_psme/" for test in listdir(catalog): with open(catalog + test) as f: data = json.load(f) test_name = data["name"] print "TEST_CASE::Validating section " + ColorPrinter.format_text(test_name, color=ColorPrinter.YELLOW_FORE) + \ " of architecture specification" status_of_test = ArchSpecTests().parse_json(discovery_container, data) print "STATUS::{status}".format(status=status_of_test) status = ValidationStatus.join_statuses(status, status_of_test) print "MESSAGE::All tests finished" print "STATUS::{status}".format(status=status)
def run(self): if self.metadata_container is None: return print "TEST_CASE::API crawling" api_explorer = ApiExplorer(self.metadata_container, self.configuration) self.discovery_container, status = api_explorer.discover( MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) print "STATUS::{status}".format(status=status) requirements = [ Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1), ] preconditions = Preconditions(self.metadata_container, requirements) status = preconditions.validate(self.discovery_container) self.api_caller = ApiCaller(self.configuration) self.crud_vlan()
def run(self): if self.metadata_container is None: return self.chosen_endpoint, self.chosen_zone, self.chosen_volume, self.chosen_volume_collection = ( None, ) * 4 self.initiator_endpoint, self.target_endpoint, self.zone_endpoint, self.created_volume = ( None, ) * 4 self.initiator_unique_name = self.generate_unique_names() if self.configuration.UniqueInitiatorName \ != "generate" else self.configuration.UniqueInitiatorName self.target_unique_name = self.generate_unique_names() if self.configuration.UniqueTargetName \ != "generate" else self.configuration.UniqueTargetName test_name = "Storage Services CRUD test with NVM Express (NVMe) Support" print "MESSAGE::%s starting" % test_name print "TEST_CASE::API crawling" api_explorer = ApiExplorer(self.metadata_container, self.configuration) self.discovery_container, status = api_explorer.discover( MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) print "STATUS::{status}".format(status=status) requirements = [ Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1), Requirement(MetadataConstants.STORAGE_SERVICE, min=1), Requirement(MetadataConstants.VOLUME, min=1), Requirement(MetadataConstants.VOLUME_COLLECTION, min=1) ] preconditions = Preconditions(self.metadata_container, requirements) status = preconditions.validate(self.discovery_container) if status == ValidationStatus.FAILED: self.set_status_failed() return self.api_caller = ApiCaller(self.configuration) status = ValidationStatus.join_statuses(status, self.crud_nvme()) print "MESSAGE::%s overall status: %s" % ( test_name, ColorPrinter.format_status(status))
def run(self): if self.metadata_container is None: return print "TEST_CASE::API crawling" api_explorer = ApiExplorer(self.metadata_container, self.configuration) self.discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) print "STATUS::{status}".format(status=status) requirements = [ Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1), ] preconditions = Preconditions(self.metadata_container, requirements) status = preconditions.validate(self.discovery_container) self.api_caller = ApiCaller(self.configuration) self.crud_vlan()
def test_discovery_can_handle_null_navigation_property(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <NavigationProperty Name="Link" Type="N.Referenced" ContainsTarget="true"> </NavigationProperty> </EntityType> <EntityType Name="Referenced" Abstract="false"> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "#N.Outer", "Link": { "@odata.id": None }, } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings( "Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource' ) as get_resource: get_resource.side_effect = [ (Link('link', 'netloc'), RequestStatus.SUCCESS, resource, None) ] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertNotIn("ERROR::", '\n'.join(output))
def test_discovery_error_if_unexpected_additional_properties(self): """ Entity type used in this test does not accept additional properties. As a result, ApiExplorer is expected to raise an error about unexpected 'additional_property' property. ApiExplorer validate """ metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Property Name="@odata.id" Type="Edm.String"/> <Property Name="@odata.type" Type="Edm.String"/> <Property Name="expected" Type="Edm.Int64"/> <Annotation Term="OData.AdditionalProperties" Bool="false"/> </EntityType> </Schema> """ resource = \ { "@odata.id": "id", "@odata.type": "N.Outer", "expected": 10, "additional_property": 1 } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertIn("unexpected properties: [additional_property]", '\n'.join(output))
def run(self): json_loader = JsonLoader() if self.metadata_container is None: return if not self.configuration.UseCase: json_loader.print_available_actions() return actions_to_take = json_loader.get_use_case(self.configuration.UseCase) specific_action = json_loader.get_use_case_action(actions_to_take['filepath']) print('TEST_CASE::API crawling') api_explorer = ApiExplorer(self.metadata_container, self.configuration) self.discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) configuration = self.configuration self.api_caller = ApiCaller(configuration) print('TEST_CASE::Action Runner') status = self.action_runner(specific_action) print('STATUS::{status}'.format(status=status))
def run(self): json_loader = JsonLoader() if self.metadata_container is None: return if not self.configuration.UseCase: json_loader.print_available_actions() return actions_to_take = json_loader.get_use_case(self.configuration.UseCase) specific_action = json_loader.get_use_case_action( actions_to_take['filepath']) print('TEST_CASE::API crawling') api_explorer = ApiExplorer(self.metadata_container, self.configuration) self.discovery_container, status = api_explorer.discover( MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) configuration = self.configuration self.api_caller = ApiCaller(configuration) print('TEST_CASE::Action Runner') status = self.action_runner(specific_action) print('STATUS::{status}'.format(status=status))
def test_discovery_can_handle_null_navigation_property(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <NavigationProperty Name="Link" Type="N.Referenced" ContainsTarget="true"> </NavigationProperty> </EntityType> <EntityType Name="Referenced" Abstract="false"> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "#N.Outer", "Link": { "@odata.id": None }, } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertNotIn("ERROR::", '\n'.join(output))
def run(self): if self.metadata_container is None: return print "TEST_CASE::API crawling" api_explorer = ApiExplorer(self.metadata_container, self.configuration) discovery_container, status = api_explorer.discover(MetadataConstants.SERVICE_ROOT_URI, MetadataConstants.SERVICE_ROOT) print "STATUS::{status}".format(status=status) print "TEST_CASE::Checking for mandatory entities" requirements = [ Requirement(MetadataConstants.SERVICE_ROOT, min=1, max=1) ] preconditions = Preconditions(self.metadata_container, requirements) self.set_validation_status(preconditions.validate(discovery_container)) validation_functions = [self.at_least_one_compute_module_in_pod, self.at_least_one_ethernet_switch_in_the_pod, self.ethernet_based_fabric_for_network_connectivity, self.secure_communication_channel, self.node_reset_support, self.manual_tests, self.validate_all_or_none_chassis_have_location, self.validate_path_using_contains_property, self.power_monitoring_support] for validation_function in validation_functions: try: validation_function(discovery_container) except Exception as err: cts_error("Exception {err:exception}", err=err) self.set_validation_status(ValidationStatus.FAILED) print "SCREEN::Overall status: %s" % self.validation_status
class ApiExplorerUnitTest(unittest.TestCase): def setUp(self): config_property_parser = Mock() config_property_parser.ApiEndpoint = "" config_property_parser.UseSSL = "Yes" self.api_explorer = ApiExplorer(None, config_property_parser) def test_visited_endpoint(self): discovery_container = DiscoveryContainer() discovery_container.add_resource(ApiResource("http://*****:*****@odata.type': 'type.of.b', 'inner': [ {'@odata.type': 'type.of.first.inner'}, {'@odata.type': 'type.of.second.inner'} ] }, None)) link, status, body, _ = self.api_explorer._get_resource("/a/b#inner/0") self.assertEqual(RequestStatus.SUCCESS, status) self.assertEqual({'@odata.type': 'type.of.first.inner'}, body) def test_discovery_from_additional_properties(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> </EntityType> <ComplexType Name="Inner" Abstract="false"> <NavigationProperty Name="Link" Type="N.Referenced" ContainsTarget="true"> </NavigationProperty> </ComplexType> <EntityType Name="Referenced" Abstract="false"> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "#N.Outer", "additional_property": { "@odata.type": "#N.Inner", "Link": { "@odata.id": "/this/is/the/link/to/be/discovered" }, } } referenced = \ { "@odata.id": "referenced.id", "@odata.type": "#N.Referenced", } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, referenced, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(2, get_resource.call_count) self.assertNotIn("ERROR::", '\n'.join(output)) def test_discovery_error_if_unexpected_additional_properties(self): """ Entity type used in this test does not accept additional properties. As a result, ApiExplorer is expected to raise an error about unexpected 'additional_property' property. ApiExplorer validate """ metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Property Name="@odata.id" Type="Edm.String"/> <Property Name="@odata.type" Type="Edm.String"/> <Property Name="expected" Type="Edm.Int64"/> <Annotation Term="OData.AdditionalProperties" Bool="false"/> </EntityType> </Schema> """ resource = \ { "@odata.id": "id", "@odata.type": "N.Outer", "expected": 10, "additional_property": 1 } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertIn("unexpected properties: [additional_property]", '\n'.join(output)) def test_discovery_from_nested_additional_properties(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> <Property Name="Oem" Type="N.Oem"> </Property> </EntityType> <ComplexType Name="Oem" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> </ComplexType> <ComplexType Name="Inner" Abstract="false"> <NavigationProperty Name="Link" Type="N.Referenced" ContainsTarget="true"> </NavigationProperty> </ComplexType> <EntityType Name="Referenced" Abstract="false"> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "#N.Outer", "Oem": { "additional_property": { "@odata.type": "#N.Inner", "Link": { "@odata.id": "/this/is/the/link/to/be/discovered" }, } } } referenced = \ { "@odata.id": "referenced.id", "@odata.type": "#N.Referenced", } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, referenced, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(2, get_resource.call_count) self.assertNotIn("ERROR::", '\n'.join(output)) def test_discovery_can_handle_null_navigation_property(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <NavigationProperty Name="Link" Type="N.Referenced" ContainsTarget="true"> </NavigationProperty> </EntityType> <EntityType Name="Referenced" Abstract="false"> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "#N.Outer", "Link": { "@odata.id": None }, } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertNotIn("ERROR::", '\n'.join(output)) def test_handle_entities_with_dynamic_property_patterns(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> <Annotation Term="Redfish.DynamicPropertyPatterns"> <Collection> <Record> <PropertyValue Property="Pattern" String="[a-z0-9]+"/> <PropertyValue Property="Type" String="N.Referenced"/> </Record> <Record> <PropertyValue Property="Pattern" String="[A-Z0-9]+"/> <PropertyValue Property="Type" String="N.Referenced"/> </Record> </Collection> </Annotation> </EntityType> <ComplexType Name="Referenced" Abstract="false"> <Property Name="name" Type="Edm.String"/> </ComplexType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "N.Outer", "additional1": { "name": "additional#1" }, "additional2": { "name": "additional#2" }, "ADDITIONAL3": "ADDITIONAL3", "ADDITIONAL4": "ADDITIONAL4", "SiMpLeTyPeIsOk": 22, "CoMpLeXInVaLiD": {"x": 1} } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [ (Link('https://{API_ENDPOINT}/outer'.format( API_ENDPOINT=API_ENDPOINT), 'netloc'), RequestStatus.SUCCESS, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertEqual(1, len(re.findall('ERROR::', ';'.join(output)))) self.assertIn( 'ERROR::url=https://1.2.3.4:567/outer#CoMpLeXInVaLiD: @odata.type not found in ' 'complex additional property;', output.raw) def test_handle_complex_types_with_dynamic_property_patterns(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Property Name="inner" Type="N.TypeWithDynamics"/> </EntityType> <ComplexType Name="TypeWithDynamics" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> <Annotation Term="Redfish.DynamicPropertyPatterns"> <Collection> <Record> <PropertyValue Property="Pattern" String="[a-z0-9]+"/> <PropertyValue Property="Type" String="N.Referenced"/> </Record> <Record> <PropertyValue Property="Pattern" String="[A-Z0-9]+"/> <PropertyValue Property="Type" String="Edm.String"/> </Record> </Collection> </Annotation> </ComplexType> <ComplexType Name="Referenced" Abstract="false"> <Property Name="name" Type="Edm.String"/> </ComplexType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "N.Outer", "inner": { "additional1": { "name": "additional#1" }, "additional2": { "name": "additional#2" }, "ADDITIONAL3": "ADDITIONAL3", "ADDITIONAL4": "ADDITIONAL4", "SiMpLeTyPeIsOk": 22, "CoMpLeXInVaLiD": {"x": 1} } } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [(Link('https://{API_ENDPOINT}/outer'.format( API_ENDPOINT=API_ENDPOINT), 'netloc'), RequestStatus.SUCCESS, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertEqual(1, len(re.findall('ERROR::', ';'.join(output)))) self.assertIn( 'ERROR::url=https://1.2.3.4:567/outer#inner.CoMpLeXInVaLiD: @odata.type not found in complex additional property;', ';'.join(output)) def test_handle_collection_with_typeless_elements_referenced_by_json_pointer(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <NavigationProperty Name="MyCollection" Type="Collection(ReferencedEntity)" ContainsTarget="true"> <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> </NavigationProperty> </EntityType> <EntityType Name="ReferencedEntity" Abstract="false"> <Property Name="name" Type="Edm.String"/> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "N.Outer", "MyCollection": [ { # implicit odata.type = ReferencedEntity "@odata.id": "/outer#MyCollection/0", "name": "MyName 0" }, { # implicit odata_type = ReferencedEntity "@odata.id": "/outer#MyCollection/1", "name": "MyName 1" } ] } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch('cts_core.commons.api_caller.ApiCaller.get_resource') as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(3, get_resource.call_count) self.assertEqual(0, len(re.findall('ERROR::', ';'.join(output))))
def setUp(self): config_property_parser = Mock() config_property_parser.ApiEndpoint = "" config_property_parser.UseSSL = "Yes" self.api_explorer = ApiExplorer(None, config_property_parser)
def test_validate_elements_of_collection_with_elements_referenced_by_out_of_range_json_pointer( self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <NavigationProperty Name="MyCollection" Type="Collection(ReferencedEntity)" ContainsTarget="true"> <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> </NavigationProperty> </EntityType> <EntityType Name="ReferencedEntity" Abstract="false"> <Property Name="name" Type="Edm.String"/> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "N.Outer", "MyCollection": [ { "@odata.id": "/outer#MyCollection/0" }, { "@odata.id": "/outer#MyCollection/2" # pointer out of range } ] } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings( "Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch('cts_core.commons.api_caller.ApiCaller.get_resource' ) as get_resource: get_resource.side_effect = [ (Link('url1', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, Link('url1', 'netloc')), (Link('url2', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, Link('url2', 'netloc')), (Link('url3', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, Link('url3', 'netloc')) ] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(3, get_resource.call_count) self.assertIn( 'ERROR::JSON pointer exception while dereferencing /MyCollection/2', ';'.join(output)) requirements = [] validator = MetadataGetValidator(metadata_container, requirements) with StdoutCapture() as output: self.assertEqual(ValidationStatus.PASSED, validator.validate(discovery_container)) self.assertEqual(0, len(re.findall('ERROR::', ';'.join(output))))
def test_handle_complex_types_with_dynamic_property_patterns(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Property Name="inner" Type="N.TypeWithDynamics"/> </EntityType> <ComplexType Name="TypeWithDynamics" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> <Annotation Term="Redfish.DynamicPropertyPatterns"> <Collection> <Record> <PropertyValue Property="Pattern" String="[a-z0-9]+"/> <PropertyValue Property="Type" String="N.Referenced"/> </Record> <Record> <PropertyValue Property="Pattern" String="[A-Z0-9]+"/> <PropertyValue Property="Type" String="Edm.String"/> </Record> </Collection> </Annotation> </ComplexType> <ComplexType Name="Referenced" Abstract="false"> <Property Name="name" Type="Edm.String"/> </ComplexType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "N.Outer", "inner": { "additional1": { "name": "additional#1" }, "additional2": { "name": "additional#2" }, "ADDITIONAL3": "ADDITIONAL3", "ADDITIONAL4": "ADDITIONAL4", "SiMpLeTyPeIsOk": 22, "CoMpLeXInVaLiD": {"x": 1} } } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [(Link('https://{API_ENDPOINT}/outer'.format( API_ENDPOINT=API_ENDPOINT), 'netloc'), RequestStatus.SUCCESS, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertEqual(1, len(re.findall('ERROR::', ';'.join(output)))) self.assertIn( 'ERROR::url=https://1.2.3.4:567/outer#inner.CoMpLeXInVaLiD: @odata.type not found in complex additional property;', ';'.join(output))
class ApiExplorerUnitTest(unittest.TestCase): def setUp(self): config_property_parser = Mock() config_property_parser.ApiEndpoint = "" config_property_parser.UseSSL = "Yes" self.api_explorer = ApiExplorer(None, config_property_parser) def test_visited_endpoint(self): discovery_container = DiscoveryContainer() discovery_container.add_resource(ApiResource("http://*****:*****@odata.type': 'type.of.b', 'inner': [ {'@odata.type': 'type.of.first.inner'}, {'@odata.type': 'type.of.second.inner'} ] }, None)) link, status, body, _ = self.api_explorer._get_resource("/a/b#inner/0") self.assertEqual(RequestStatus.SUCCESS, status) self.assertEqual({'@odata.type': 'type.of.first.inner'}, body) def test_get_resource_with_odata(self): self.api_explorer._api_caller.get_resource = MagicMock( return_value=( Link('link', 'netloc'), RequestStatus.SUCCESS, None, { '@odata.type': 'type.of.b', 'inner': [ {'@odata.id': '/redfish/a/b#inner/3'}, {'@odata.id': '/redfish/a/b#inner/4'} ] }, None)) link, status, body, _ = self.api_explorer._get_resource("/redfish/a/b#inner/3") self.assertEqual(RequestStatus.SUCCESS, status) self.assertEqual({'@odata.id': '/redfish/a/b#inner/3'}, body) def test_get_resource_with_odata_failed(self): self.api_explorer._api_caller.get_resource = MagicMock( return_value=( Link('link', 'netloc'), RequestStatus.SUCCESS, None, { '@odata.type': 'type.of.b', 'inner': [ {'@odata.id': '/redfish/a/b#inner/3'}, {'@odata.id': '/redfish/a/b#inner/4'} ] }, None)) with StdoutCapture() as output: link, status, body, _ = self.api_explorer._get_resource("/redfish/a/b#inner/543534634") self.assertIsNot(RequestStatus.SUCCESS, status) self.assertIn( "ERROR::Could not find /inner/543534634 from url=/redfish/a/b#inner/543534634 with search by @odata.id;", output.raw) def test_discovery_from_additional_properties(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> </EntityType> <ComplexType Name="Inner" Abstract="false"> <NavigationProperty Name="Link" Type="N.Referenced" ContainsTarget="true"> </NavigationProperty> </ComplexType> <EntityType Name="Referenced" Abstract="false"> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "#N.Outer", "additional_property": { "@odata.type": "#N.Inner", "Link": { "@odata.id": "/this/is/the/link/to/be/discovered" }, } } referenced = \ { "@odata.id": "referenced.id", "@odata.type": "#N.Referenced", } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, referenced, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(2, get_resource.call_count) self.assertNotIn("ERROR::", '\n'.join(output)) def test_discovery_error_if_unexpected_additional_properties(self): """ Entity type used in this test does not accept additional properties. As a result, ApiExplorer is expected to raise an error about unexpected 'additional_property' property. ApiExplorer validate """ metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Property Name="@odata.id" Type="Edm.String"/> <Property Name="@odata.type" Type="Edm.String"/> <Property Name="expected" Type="Edm.Int64"/> <Annotation Term="OData.AdditionalProperties" Bool="false"/> </EntityType> </Schema> """ resource = \ { "@odata.id": "id", "@odata.type": "N.Outer", "expected": 10, "additional_property": 1 } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertIn("unexpected properties: [additional_property]", '\n'.join(output)) def test_discovery_from_nested_additional_properties(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> <Property Name="Oem" Type="N.Oem"> </Property> </EntityType> <ComplexType Name="Oem" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> </ComplexType> <ComplexType Name="Inner" Abstract="false"> <NavigationProperty Name="Link" Type="N.Referenced" ContainsTarget="true"> </NavigationProperty> </ComplexType> <EntityType Name="Referenced" Abstract="false"> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "#N.Outer", "Oem": { "additional_property": { "@odata.type": "#N.Inner", "Link": { "@odata.id": "/this/is/the/link/to/be/discovered" }, } } } referenced = \ { "@odata.id": "referenced.id", "@odata.type": "#N.Referenced", } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, referenced, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(2, get_resource.call_count) self.assertNotIn("ERROR::", '\n'.join(output)) @unittest.skip("Temporary change related to bug in Discovery mechanism") def test_discovery_can_handle_null_navigation_property(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <NavigationProperty Name="Link" Type="N.Referenced" ContainsTarget="true"> </NavigationProperty> </EntityType> <EntityType Name="Referenced" Abstract="false"> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "#N.Outer", "Link": { "@odata.id": None }, } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertNotIn("ERROR::", '\n'.join(output)) def test_handle_entities_with_dynamic_property_patterns(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> <Annotation Term="Redfish.DynamicPropertyPatterns"> <Collection> <Record> <PropertyValue Property="Pattern" String="[a-z0-9]+"/> <PropertyValue Property="Type" String="N.Referenced"/> </Record> <Record> <PropertyValue Property="Pattern" String="[A-Z0-9]+"/> <PropertyValue Property="Type" String="N.Referenced"/> </Record> </Collection> </Annotation> </EntityType> <ComplexType Name="Referenced" Abstract="false"> <Property Name="name" Type="Edm.String"/> </ComplexType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "N.Outer", "additional1": { "name": "additional#1" }, "additional2": { "name": "additional#2" }, "ADDITIONAL3": "ADDITIONAL3", "ADDITIONAL4": "ADDITIONAL4", "SiMpLeTyPeIsOk": 22, "CoMpLeXInVaLiD": {"x": 1} } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [ (Link('https://{API_ENDPOINT}/outer'.format( API_ENDPOINT=API_ENDPOINT), 'netloc'), RequestStatus.SUCCESS, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertEqual(1, len(re.findall('ERROR::', ';'.join(output)))) self.assertIn( 'ERROR::url=https://1.2.3.4:567/outer#CoMpLeXInVaLiD: @odata.type not found in ' 'complex additional property;', output.raw) def test_handle_complex_types_with_dynamic_property_patterns(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <Property Name="inner" Type="N.TypeWithDynamics"/> </EntityType> <ComplexType Name="TypeWithDynamics" Abstract="false"> <Annotation Term="OData.AdditionalProperties" Bool="true"/> <Annotation Term="Redfish.DynamicPropertyPatterns"> <Collection> <Record> <PropertyValue Property="Pattern" String="[a-z0-9]+"/> <PropertyValue Property="Type" String="N.Referenced"/> </Record> <Record> <PropertyValue Property="Pattern" String="[A-Z0-9]+"/> <PropertyValue Property="Type" String="Edm.String"/> </Record> </Collection> </Annotation> </ComplexType> <ComplexType Name="Referenced" Abstract="false"> <Property Name="name" Type="Edm.String"/> </ComplexType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "N.Outer", "inner": { "additional1": { "name": "additional#1" }, "additional2": { "name": "additional#2" }, "ADDITIONAL3": "ADDITIONAL3", "ADDITIONAL4": "ADDITIONAL4", "SiMpLeTyPeIsOk": 22, "CoMpLeXInVaLiD": {"x": 1} } } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch( 'cts_core.discovery.api_explorer.ApiExplorer._get_resource') as get_resource: get_resource.side_effect = [(Link('https://{API_ENDPOINT}/outer'.format( API_ENDPOINT=API_ENDPOINT), 'netloc'), RequestStatus.SUCCESS, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(1, get_resource.call_count) self.assertEqual(1, len(re.findall('ERROR::', ';'.join(output)))) self.assertIn( 'ERROR::url=https://1.2.3.4:567/outer#inner.CoMpLeXInVaLiD: @odata.type not found in complex additional property;', ';'.join(output)) def test_handle_collection_with_typeless_elements_referenced_by_json_pointer(self): metadata = """ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="N"> <EntityType Name="Outer" Abstract="false"> <NavigationProperty Name="MyCollection" Type="Collection(ReferencedEntity)" ContainsTarget="true"> <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> </NavigationProperty> </EntityType> <EntityType Name="ReferencedEntity" Abstract="false"> <Property Name="name" Type="Edm.String"/> </EntityType> </Schema> """ resource = \ { "@odata.id": "resource.id", "@odata.type": "N.Outer", "MyCollection": [ { # implicit odata.type = ReferencedEntity "@odata.id": "/outer#MyCollection/0", "name": "MyName 0" }, { # implicit odata_type = ReferencedEntity "@odata.id": "/outer#MyCollection/1", "name": "MyName 1" } ] } metadata_manager = MetadataManager(["qualifier"]) metadata_container = metadata_manager.read_metadata_from_strings("Unknown", metadata) discovery_container = DiscoveryContainer() configuration = Configuration( **dict(UseSSL='True', ApiEndpoint=API_ENDPOINT)) api_explorer = ApiExplorer(metadata_container, configuration) with mock.patch('cts_core.commons.api_caller.ApiCaller.get_resource') as get_resource: get_resource.side_effect = [(Link('link', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, None), (Link('link', 'netloc'), RequestStatus.SUCCESS, ReturnCodes.OK, resource, None)] with StdoutCapture() as output: api_explorer.discover("/outer", "N.Outer", discovery_container) self.assertEqual(3, get_resource.call_count) self.assertEqual(0, len(re.findall('ERROR::', ';'.join(output))))