def setUp(self): self.mock_context = mock.MagicMock('context') self.target_swagger = { "swagger": "2.0", "info": { "version": "1.0.0", "title": "" }, "paths": { } } self.target_swagger_navigator = SwaggerNavigator(self.target_swagger) self.interface_swagger = { "swagger": "2.0", "info": { "version": "1.0.0", "title": "" }, "paths": { } } self.interface_swagger_navigator = SwaggerNavigator(self.interface_swagger) self.test_interface_id = 'test_interface_1_2_3' self.test_path = '/test_path' self.test_definition_name = 'test-definition-name' self.test_definition_value = { 'test-definition-property': 'test-definition-value' } self.test_mappings = {} self.test_lambda_dispatch_for_paths = {} self.test_external_parameters = None
def generate_component_json(self): self.add_def_to_struct_type_conversions() self._component_json["namespace"] = self.get_namespace() self._component_json["componentClass"] = "{}ClientComponent".format(self._resource_group_name) self._component_json["resourceGroup"] = self._resource_group_name self._component_json["redefinitions"] = [] self._component_json["otherClasses"] = [] self._component_json["functions"] = [] base_navigator = SwaggerNavigator(self._swagger) self.__read_functions(base_navigator.get("paths")) return self._component_json
def process_swagger(context, swagger): # make sure we are starting with a valid document validate_swagger(swagger) # process the swagger, order matters swagger_navigator = SwaggerNavigator(swagger) interface.process_interface_implementation_objects(context, swagger_navigator) lambda_dispatch.process_lambda_dispatch_objects(context, swagger_navigator) # make sure we produce a valid document validate_swagger(swagger)
class UnitTest_CloudGemFramework_ResourceManagerCode_swagger_processor_interfaces( unittest.TestCase): def __init__(self, *args, **kwargs): super( UnitTest_CloudGemFramework_ResourceManagerCode_swagger_processor_interfaces, self).__init__(*args, **kwargs) def setUp(self): self.mock_context = mock.MagicMock('context') self.target_swagger = { "swagger": "2.0", "info": { "version": "1.0.0", "title": "" }, "paths": {} } self.target_swagger_navigator = SwaggerNavigator(self.target_swagger) self.interface_swagger = { "swagger": "2.0", "info": { "version": "1.0.0", "title": "" }, "paths": {} } self.interface_swagger_navigator = SwaggerNavigator( self.interface_swagger) self.test_interface_id = 'test_interface_1_2_3' self.test_path = '/test_path' self.test_definition_name = 'test-definition-name' self.test_definition_value = { 'test-definition-property': 'test-definition-value' } self.test_mappings = {} self.test_lambda_dispatch_for_paths = {} self.test_external_parameters = None def add_target_path(self, path, content=None): content = content or {} path_object = self.target_swagger_navigator.get_object( 'paths').add_object(path, content) return path_object def add_interface_path(self, path, content=None): content = content or {} path_object = self.interface_swagger_navigator.get_object( 'paths').add_object(path, content) return path_object def add_target_interface_implementation_object(self, path, interface, path_content=None, lambda_dispatch=None, external_parameters=None): if lambda_dispatch: interface_implementation_object_value = { 'interface': { 'id': interface, 'lambda_dispatch': lambda_dispatch } } else: interface_implementation_object_value = {'interface': interface} path_object = self.add_target_path(path, path_content) interface_implementation_object = path_object.add_object( resource_manager_common.service_interface. INTERFACE_IMPLEMENTATION_OBJECT_NAME, interface_implementation_object_value) if external_parameters: path_object.get_or_add_array('parameters', default=external_parameters) return interface_implementation_object def add_interface_definition(self, definition_name, definition_value): definitions_object = self.interface_swagger_navigator.get_or_add_object( 'definitions') definitions_object.value[definition_name] = definition_value return definitions_object.get(definition_name) def add_target_definition(self, definition_name, definition_value): definitions_object = self.target_swagger_navigator.get_or_add_object( 'definitions') definitions_object.value[definition_name] = definition_value @mock.patch( 'swagger_processor.interface.process_interface_implementation_object') def test_process_interface_implementation_objects_processes_all_objects( self, mock_process_interface_implementation_object): self.add_target_path('/path-without-interface-implemenation') interface_implementation_object_1 = self.add_target_interface_implementation_object( self.test_path + '1', self.test_interface_id) interface_implementation_object_2 = self.add_target_interface_implementation_object( self.test_path + '2', self.test_interface_id) swagger_processor.interface.process_interface_implementation_objects( self.mock_context, self.target_swagger_navigator) mock_process_interface_implementation_object.assert_has_calls( [ mock.call( self.mock_context, SwaggerNavigatorMatcher( interface_implementation_object_1)), mock.call( self.mock_context, SwaggerNavigatorMatcher(interface_implementation_object_2)) ], any_order=True) @mock.patch('swagger_processor.interface.load_interface_swagger') @mock.patch('swagger_processor.interface.insert_interface_definitions') @mock.patch('swagger_processor.interface.insert_interface_paths') def test_process_interface_implementation_object( self, mock_insert_interface_paths, mock_insert_interface_definitions, mock_load_interface_swagger): mock_lambda_dispatch = {'paths': {}} mock_external_parameters = [] interface_implementation_object = self.add_target_interface_implementation_object( self.test_path, self.test_interface_id, lambda_dispatch=mock_lambda_dispatch, external_parameters=mock_external_parameters) mock_mappings = mock_insert_interface_definitions.return_value mock_interface_swagger = mock_load_interface_swagger.return_value swagger_processor.interface.process_interface_implementation_object( self.mock_context, interface_implementation_object) mock_load_interface_swagger.assert_called_once_with( self.mock_context, self.test_interface_id) mock_insert_interface_definitions.assert_called_once_with( SwaggerNavigatorMatcher(interface_implementation_object.root), mock_interface_swagger, self.test_interface_id, mock_external_parameters) mock_insert_interface_paths.assert_called_once_with( SwaggerNavigatorMatcher(interface_implementation_object.parent), mock_interface_swagger, self.test_interface_id, mock_mappings, mock_lambda_dispatch['paths'], mock_external_parameters) self.assertEquals( self.target_swagger[resource_manager_common.service_interface. INTERFACE_METADATA_OBJECT_NAME], {self.test_interface_id: { 'basePath': self.test_path }}) def test_insert_interface_definitions_with_no_source_or_target_definitions_does_not_add_definitions( self): external_parameters = {} swagger_processor.interface.insert_interface_definitions( self.target_swagger_navigator, self.interface_swagger_navigator, self.test_interface_id, external_parameters) self.assertNotIn('definitions', self.target_swagger.keys()) self.assertNotIn( resource_manager_common.service_interface. INTERFACE_METADATA_OBJECT_NAME, self.target_swagger.keys()) def test_insert_interface_definitions_with_only_target_definitions_does_not_modify_definitions( self): self.add_target_definition(self.test_definition_name, self.test_definition_value) target_definitions_copy = copy.deepcopy( self.target_swagger_navigator.get_object('definitions').value) external_parameters = {} swagger_processor.interface.insert_interface_definitions( self.target_swagger_navigator, self.interface_swagger_navigator, self.test_interface_id, external_parameters) self.assertEquals( self.target_swagger_navigator.get_object('definitions').value, target_definitions_copy) self.assertNotIn( resource_manager_common.service_interface. INTERFACE_METADATA_OBJECT_NAME, self.target_swagger.keys()) def test_insert_interface_definitions_with_multiple_source_definitions_inserts_all_definitions( self): self.add_interface_definition(self.test_definition_name + '1', self.test_definition_value) self.add_interface_definition(self.test_definition_name + '2', self.test_definition_value) external_parameters = {} swagger_processor.interface.insert_interface_definitions( self.target_swagger_navigator, self.interface_swagger_navigator, self.test_interface_id, external_parameters) target_definitions_object = self.target_swagger_navigator.get_object( 'definitions') result_definition = target_definitions_object.get_object( self.test_definition_name + '1') self.assertEquals(result_definition.value, self.test_definition_value) result_definition = target_definitions_object.get_object( self.test_definition_name + '2') self.assertEquals(result_definition.value, self.test_definition_value) self.assertEquals( self.target_swagger[resource_manager_common.service_interface. INTERFACE_METADATA_OBJECT_NAME], { self.test_interface_id: { 'definitions': AnyOrderListMatcher([ self.test_definition_name + '1', self.test_definition_name + '2' ]) } }) def test_insert_interface_definitions_preserves_existing_definition(self): interface_definition = {'interface': 'definition'} self.add_interface_definition(self.test_definition_name, interface_definition) target_definition = {'target': 'definition'} self.add_target_definition(self.test_definition_name, target_definition) external_parameters = [] swagger_processor.interface.insert_interface_definitions( self.target_swagger_navigator, self.interface_swagger_navigator, self.test_interface_id, external_parameters) target_definitions_object = self.target_swagger_navigator.get_object( 'definitions') result_definition = target_definitions_object.get_object( self.test_definition_name + '1') self.assertEquals(result_definition, SwaggerNavigatorMatcher(interface_definition)) result_definition = target_definitions_object.get_object( self.test_definition_name) self.assertEquals(result_definition, SwaggerNavigatorMatcher(target_definition)) self.assertEquals( self.target_swagger[resource_manager_common.service_interface. INTERFACE_METADATA_OBJECT_NAME], { self.test_interface_id: { 'definitions': [self.test_definition_name + '1'] } }) def test_insert_interface_definitions_generates_unique_defintion_names( self): interface_definition = {'interface': 'definition'} self.add_interface_definition(self.test_definition_name, interface_definition) target_definition = {'target': 'definition'} self.add_target_definition(self.test_definition_name, target_definition) target_definition_1 = {'target': 'definition1'} self.add_target_definition(self.test_definition_name + '1', target_definition_1) target_definition_2 = {'target': 'definition2'} self.add_target_definition(self.test_definition_name + '2', target_definition_2) external_parameters = [] swagger_processor.interface.insert_interface_definitions( self.target_swagger_navigator, self.interface_swagger_navigator, self.test_interface_id, external_parameters) target_definitions_object = self.target_swagger_navigator.get_object( 'definitions') result_definition = target_definitions_object.get_object( self.test_definition_name + '3') self.assertEquals(result_definition, SwaggerNavigatorMatcher(interface_definition)) result_definition = target_definitions_object.get_object( self.test_definition_name + '1') self.assertEquals(result_definition, SwaggerNavigatorMatcher(target_definition_1)) result_definition = target_definitions_object.get_object( self.test_definition_name + '2') self.assertEquals(result_definition, SwaggerNavigatorMatcher(target_definition_2)) result_definition = target_definitions_object.get_object( self.test_definition_name) self.assertEquals(result_definition, SwaggerNavigatorMatcher(target_definition)) self.assertEquals( self.target_swagger[resource_manager_common.service_interface. INTERFACE_METADATA_OBJECT_NAME], { self.test_interface_id: { 'definitions': [self.test_definition_name + '3'] } }) def test_insert_interface_paths_inserts_paths(self): interface_paths = ['/foo', '/bar'] interface_paths_content = {} lambda_dispatch_for_paths = {} expected_interface_paths_content = {} external_parameters = [] for interface_path in interface_paths: interface_path_content = { 'get': { 'interface_path': interface_path }, 'parameters': [{ 'internal': 'parameter' }] } lambda_dispatch_for_path = { 'get': { 'lambda_dispatch': interface_path } } interface_paths_content[interface_path] = interface_path_content self.add_interface_path(interface_path, interface_path_content) lambda_dispatch_for_paths[ interface_path] = lambda_dispatch_for_path expected_interface_paths_content[interface_path] = copy.deepcopy( interface_path_content) expected_interface_paths_content[interface_path]['get'][ swagger_processor.lambda_dispatch. LAMBDA_DISPATCH_OBJECT_NAME] = lambda_dispatch_for_path['get'] expected_parameters = [] expected_parameters.extend(external_parameters) expected_parameters.extend(interface_path_content['parameters']) expected_interface_paths_content[interface_path][ 'parameters'] = AnyOrderListMatcher(expected_parameters) target_path_content = {'target_path': self.test_path} interface_implementation_object = self.add_target_interface_implementation_object( self.test_path, self.test_interface_id, path_content=target_path_content) swagger_processor.interface.insert_interface_paths( interface_implementation_object.parent, self.interface_swagger_navigator, self.test_interface_id, self.test_mappings, lambda_dispatch_for_paths, external_parameters) target_paths = self.target_swagger_navigator.get_object('paths') self.assertTrue(target_paths.contains(self.test_path)) self.assertEqual( target_paths.get_object(self.test_path).value, target_path_content) for interface_path in interface_paths: self.assertTrue( target_paths.contains(self.test_path + interface_path)) self.assertEquals( target_paths.get_object(self.test_path + interface_path).value, expected_interface_paths_content[interface_path]) self.assertEquals( self.target_swagger[resource_manager_common.service_interface. INTERFACE_METADATA_OBJECT_NAME], { self.test_interface_id: { 'paths': AnyOrderListMatcher([ self.test_path + interface_path for interface_path in interface_paths ]) } }) def test_insert_interface_paths_works_on_root_path(self): interface_paths = ['/foo', '/bar'] interface_paths_content = {} for interface_path in interface_paths: interface_path_content = {'interface_path': interface_path} interface_paths_content[interface_path] = interface_path_content self.add_interface_path(interface_path, interface_path_content) target_path_content = {'target_path': self.test_path} interface_implementation_object = self.add_target_interface_implementation_object( '/', self.test_interface_id, path_content=target_path_content) swagger_processor.interface.insert_interface_paths( interface_implementation_object.parent, self.interface_swagger_navigator, self.test_interface_id, self.test_mappings, self.test_lambda_dispatch_for_paths, self.test_external_parameters) target_paths = self.target_swagger_navigator.get_object('paths') self.assertTrue(target_paths.contains('/')) self.assertEqual( target_paths.get_object('/').value, target_path_content) for interface_path in interface_paths: self.assertTrue(target_paths.contains(interface_path)) self.assertEquals( target_paths.get_object(interface_path).value, interface_paths_content[interface_path]) self.assertEquals( self.target_swagger[resource_manager_common.service_interface. INTERFACE_METADATA_OBJECT_NAME], { self.test_interface_id: { 'paths': AnyOrderListMatcher(interface_paths) } }) def test_insert_interface_paths_fails_with_duplicate_paths(self): interface_path = '/foo' self.add_interface_path(interface_path) interface_implementation_object = self.add_target_interface_implementation_object( self.test_path, self.test_interface_id) self.add_target_path(self.test_path + interface_path) with self.assertRaisesRegexp(RuntimeError, self.test_path + interface_path): swagger_processor.interface.insert_interface_paths( interface_implementation_object.parent, self.interface_swagger_navigator, self.test_interface_id, self.test_mappings, self.test_lambda_dispatch_for_paths, self.test_external_parameters) def test_copy_with_updated_refs_with_ref(self): test_target = '#/definition/test-target' definition_object = self.add_interface_definition( self.test_definition_name, {'$ref': test_target}) mappings = {'test-target': 'mapped-target'} result = swagger_processor.interface.copy_with_updated_refs( definition_object, mappings) self.assertEquals(result, {'$ref': '#/definition/mapped-target'}) def test_copy_with_updated_refs_with_nested_ref_in_object(self): test_target = '#/definition/test-target' definition_object = self.add_interface_definition( self.test_definition_name, {'container': { 'the-ref': { '$ref': test_target } }}) mappings = {'test-target': 'mapped-target'} result = swagger_processor.interface.copy_with_updated_refs( definition_object, mappings) self.assertEquals( result, {'container': { 'the-ref': { '$ref': '#/definition/mapped-target' } }}) def test_copy_with_updated_refs_with_nested_ref_in_array(self): test_target = '#/definition/test-target' definition_object = self.add_interface_definition( self.test_definition_name, {'container': [{ '$ref': test_target }]}) mappings = {'test-target': 'mapped-target'} result = swagger_processor.interface.copy_with_updated_refs( definition_object, mappings) self.assertEquals( result, {'container': [{ '$ref': '#/definition/mapped-target' }]}) def test_copy_with_updated_refs_with_nested_ref_in_object_in_array(self): test_target = '#/definition/test-target' definition_object = self.add_interface_definition( self.test_definition_name, {'container': [{ 'the-ref': { '$ref': test_target } }]}) mappings = {'test-target': 'mapped-target'} result = swagger_processor.interface.copy_with_updated_refs( definition_object, mappings) self.assertEquals(result, { 'container': [{ 'the-ref': { '$ref': '#/definition/mapped-target' } }] }) def test_copy_with_updated_refs_with_string(self): mappings = {'string': 'should-not-be-used'} string_value = 'string' string_navigator = self.add_interface_definition( self.test_definition_name, 'string') result = swagger_processor.interface.copy_with_updated_refs( string_navigator, mappings) self.assertEquals(result, string_value) def test_parse_interface_id_with_valid_id(self): expected_gem_name = 'TestGemName' expected_interface_name = 'TestInterfaceName' expected_interface_version = Version('1.2.3') interface_id = expected_gem_name + '_' + expected_interface_name + '_' + str( expected_interface_version).replace('.', '_') actual_gem_name, actual_interface_name, actual_interface_version = swagger_processor.interface.parse_interface_id( interface_id) self.assertEquals(actual_gem_name, expected_gem_name) self.assertEquals(actual_interface_name, expected_interface_name) self.assertEquals(actual_interface_version, expected_interface_version)
def process_lambda_dispatch_objects(swagger): swagger_navigator = SwaggerNavigator(swagger) # The x-amazon-cloud-canvas-lambda-dispatch objects can appear in the swagger object (root) # a path object or an operation object. We use these to generate x-amazon-apigateway-integration # objects for each operation that doesn't have one already. # # For the lambda, module, and function properties, the value specified by the "lowest" object # override any values provided by the "higher" object (so you can set a defaults at the top # and override then for individual paths or operations). # # For additional_properties, addnitional_request_template_cntent, and additional_response_template_content # properties, the aggregate values are injected into the x-amazon-apigateway-integration. # # We keep track of the lambda dispatch objects that are "in scope" in the displatch_object_stack. # This starts with the one in the swagger object, then the one for a "current" path, then # one for the "current" operation (the stack will never have more than three entries). # # As part of this processing, we need to know an operation's current parameters. Swagger # allows parameters to be defined in the path or operation object, with parameters in the # operation object overriding those in the path object. Swagger lets you put paramter # definitions in the swagger object, but these are not used for any path/operation unless # the path/operation parameters use $ref to identify one of these definitions. We use the # parameter_object_stack to keep track of the "current" path and operation parameters. dispatch_object_stack = [] parameters_object_stack = [] dispatch_object_stack.append( swagger_navigator.remove_object(LAMBDA_DISPATCH_OBJECT_NAME, {})) missing_security_warnings = [] global_security_object = swagger_navigator.get_object('security', default=None) for path, path_object in swagger_navigator.get_object('paths').items(): dispatch_object_stack.append( path_object.remove_object(LAMBDA_DISPATCH_OBJECT_NAME, {})) parameters_object_stack.append(path_object.get_array('parameters', [])) options_operation_needed_for_cors = False options_operation_found = False for operation, operation_object in path_object.items(): # Swagger allows a path object to have properties that don't represent an # operation. Only the following properties define operations. if operation not in [ 'get', 'put', 'post', 'delete', 'options', 'head', 'patch' ]: continue if operation == 'options': options_operation_found = True dispatch_object_stack.append( operation_object.remove_object(LAMBDA_DISPATCH_OBJECT_NAME, {})) parameters_object_stack.append( operation_object.get_array('parameters', [])) # Create an x-amazon-apigateway-intergration object only if the operation object # doesn't have one already. if not operation_object.contains( API_GATEWAY_INTEGRATION_OBJECT_NAME): # We assume executing a lambda can result in both internal server errors and # client errors, in addition to success. We add definitions for these # responses to the operation object if they aren't already present. if _add_error_response(operation_object): _ensure_error_definition(swagger_navigator) # By default we want all APIs to be callable only when using valid AWS IAM # credentails. If no security object is present, add add one. if _determine_if_iam_security_enabled(dispatch_object_stack): if _add_iam_security_to_operation(operation_object): _ensure_iam_security_definition(swagger_navigator) # Construct the x-amazon-apigateway-intergration object using the information # we have in the x-amazon-cloud-canvas-lambda-dispatch objects that are currently # in scope. integration_object = _make_integration_object( dispatch_object_stack, parameters_object_stack, path, operation) operation_object.value[ API_GATEWAY_INTEGRATION_OBJECT_NAME] = integration_object if _determine_if_cors_enabled(dispatch_object_stack): options_operation_needed_for_cors = True __add_cores_response_headers_to_operation(operation_object) # If no security has been declared or inserted above, API Gateway will make the operation public. if global_security_object.is_none: security_array = operation_object.get_array('security', default=None) if security_array.is_none: missing_security_warnings.append(' {:<7} {}'.format( operation, path)) dispatch_object_stack.pop() # operation scope parameters_object_stack.pop() if options_operation_needed_for_cors and not options_operation_found: __add_options_operation_for_cors(path, path_object) dispatch_object_stack.pop() # path scope parameters_object_stack.pop() dispatch_object_stack.pop() # swagger scope if missing_security_warnings: print '' print 'WARNING: the following operations do not specify a swagger "security" object.' print 'The Service APIs for these operations will be publically accessible.' print '' for warning in missing_security_warnings: print warning print ''