Esempio n. 1
0
def test_filter_api_methods(server, api_methods_fixture, feature_manager):
    post = UrlMethod(properties=MethodProperties.methods["post_method"][0], slice=None, method_name="post_method", handler=None)
    methods = {
        "POST": post,
        "GET": UrlMethod(
            properties=MethodProperties.methods["get_method"][0], slice=None, method_name="get_method", handler=None
        ),
    }
    openapi = OpenApiConverter(server._transport.get_global_url_map(server.get_slices().values()), feature_manager)
    api_methods = openapi._filter_api_methods(methods)
    assert len(api_methods) == 1
Esempio n. 2
0
    def get_op_mapping(self) -> Dict[str, Dict[str, UrlMethod]]:
        """
        Build a mapping between urls, ops and methods
        """
        url_map: Dict[str, Dict[str, UrlMethod]] = defaultdict(dict)

        # Loop over all methods in this class that have a handler annotation. The handler annotation refers to a method
        # definition. This method definition defines how the handler is invoked.
        for method, handler_list in self._get_endpoint_metadata().items():
            for method_handlers in handler_list:
                # Go over all method annotation on the method associated with the handler
                for properties in common.MethodProperties.methods[method]:
                    url = properties.get_listen_url()

                    # Associate the method with the handler if:
                    # - the handler does not specific a method version
                    # - the handler specifies a method version and the method version matches the method properties
                    if method_handlers[1].__api_version__ is None or (
                            method_handlers[1].__api_version__ is not None
                            and properties.api_version
                            == method_handlers[1].__api_version__):
                        # there can only be one
                        if url in url_map and properties.operation in url_map[
                                url]:
                            raise Exception(
                                f"A handler is already registered for {properties.operation} {url}. "
                            )

                        url_map[url][properties.operation] = UrlMethod(
                            properties, self, method_handlers[1],
                            method_handlers[0])
        return url_map
Esempio n. 3
0
def test_get_operation_no_docstring(api_methods_fixture):
    """
    Test whether an OpenAPI operation is constructed correctly for a
    GET method which doesn't have a docstring.
    """
    get = UrlMethod(
        properties=MethodProperties.methods["dummy_get_with_parameters_no_docstring"][0],
        slice=None,
        method_name="dummy_get_with_parameters_no_docstring",
        handler=None,
    )

    operation_handler = OperationHandler(OpenApiTypeConverter(), ArgOptionHandler(OpenApiTypeConverter()))
    operation = operation_handler.handle_method(get, "/operation/{id}")

    # Asserts on request body
    assert operation.requestBody is None

    # Asserts on parameters
    assert operation.summary is None
    assert operation.description is None
    assert sorted(["header-val", "non_header", "param", "id"]) == sorted([parameter.name for parameter in operation.parameters])
    param_map = {param.name: param.description for param in operation.parameters}
    assert len(param_map) == 4
    assert param_map["header-val"] is None
    assert param_map["non_header"] is None
    assert param_map["param"] is None
    assert param_map["id"] is None

    # Asserts on response
    assert len(operation.responses) == 1
    assert ["header-val"] == list(operation.responses["200"].headers.keys())
    assert operation.responses["200"].description == ""
Esempio n. 4
0
def test_post_operation_no_docstring(api_methods_fixture):
    """
    Test whether an OpenAPI operation is constructed correctly for a
    POST method which doesn't have a docstring.
    """
    post = UrlMethod(
        properties=MethodProperties.methods["dummy_post_with_parameters_no_docstring"][0],
        slice=None,
        method_name="dummy_post_with_parameters_no_docstring",
        handler=None,
    )

    operation_handler = OperationHandler(OpenApiTypeConverter(), ArgOptionHandler(OpenApiTypeConverter()))
    operation = operation_handler.handle_method(post, "/operation/{id}")

    # Asserts on request body
    expected_params = ["param", "non_header"]
    actual_params = list(operation.requestBody.content["application/json"].schema_.properties.keys())
    assert sorted(expected_params) == sorted(actual_params)
    assert operation.requestBody.description == "* **non_header:**\n* **param:**\n"

    # Asserts on parameters
    assert operation.summary is None
    assert operation.description is None
    assert sorted(["header-val", "id"]) == sorted([parameter.name for parameter in operation.parameters])
    param_map = {param.name: param.description for param in operation.parameters}
    assert len(param_map) == 2
    assert param_map["header-val"] is None
    assert param_map["id"] is None

    # Asserts on response
    assert len(operation.responses) == 1
    assert ["header-val"] == list(operation.responses["200"].headers.keys())
    assert operation.responses["200"].description == ""
Esempio n. 5
0
def test_post_operation(api_methods_fixture):
    """
    Test whether an OpenAPI operation is constructed correctly for a
    POST method which is fully annotated and documented.
    """
    short_description = "This is a brief description."
    long_description = "This is a more in depth description of the method."
    header_description = "A header value."
    non_header_description = "Non header value via arg_options."
    param_description = "A parameter."
    id_description = "The id of the resource."
    return_value_description = "A return value."
    raises_os_error_description = "Something went wrong"
    raises_not_found_description = "Resource was not found."
    raises_dummy_exception_description = "A dummy exception"
    method_name = "dummy_post_with_parameters"

    post = UrlMethod(
        properties=MethodProperties.methods["dummy_post_with_parameters"][0],
        slice=None,
        method_name=method_name,
        handler=None,
    )

    operation_handler = OperationHandler(
        OpenApiTypeConverter(), ArgOptionHandler(OpenApiTypeConverter()))
    operation = operation_handler.handle_method(post, "/operation/{id}")

    # Asserts on request body
    expected_params = ["param", "non_header"]
    actual_params = list(operation.requestBody.content["application/json"].
                         schema_.properties.keys())
    assert sorted(expected_params) == sorted(actual_params)
    assert (
        f"* **non_header:** {non_header_description}\n* **param:** {param_description}\n"
        == operation.requestBody.description)

    # Asserts on parameters
    assert operation.summary == short_description
    assert operation.description == long_description
    assert operation.operationId == method_name
    assert sorted(["header-val", "id"]) == sorted(
        [parameter.name for parameter in operation.parameters])
    param_map = {
        param.name: param.description
        for param in operation.parameters
    }
    assert len(param_map) == 2
    assert param_map["header-val"] == header_description
    assert param_map["id"] == id_description

    # Asserts on response
    assert len(operation.responses) == 4
    assert operation.responses["200"].description == return_value_description
    assert operation.responses[
        "404"].description == raises_not_found_description
    assert operation.responses[
        "405"].description == raises_dummy_exception_description
    assert operation.responses[
        "500"].description == raises_os_error_description
Esempio n. 6
0
def test_get_operation_partial_documentation(api_methods_fixture):
    """
    Test whether an OpenAPI operation is constructed correctly for a
    GET method which has missing entries in its docstring.
    """
    short_description = "This is a brief description."
    tid_description = "The inmanta environment id."
    param_description = "A parameter."
    id_description = "The id of the resource."

    get = UrlMethod(
        properties=MethodProperties.
        methods["dummy_get_with_parameters_partial_documentation"][0],
        slice=None,
        method_name="dummy_get_with_parameters_partial_documentation",
        handler=None,
    )

    operation_handler = OperationHandler(
        OpenApiTypeConverter(), ArgOptionHandler(OpenApiTypeConverter()))
    operation = operation_handler.handle_method(
        get, "/operation/{id_doc}/{id_no_doc}")

    # Asserts on request body
    assert operation.requestBody is None

    # Asserts on parameters
    assert operation.summary == short_description
    assert operation.description is None

    expected_parameters = [
        "header-doc", "header-no-doc", "param_doc", "param_no_doc", "id_doc",
        "id_no_doc"
    ]
    actual_parameters = [parameter.name for parameter in operation.parameters]
    assert sorted(expected_parameters) == sorted(actual_parameters)
    param_map = {
        param.name: param.description
        for param in operation.parameters
    }
    assert len(param_map) == 6
    assert param_map["header-doc"] == tid_description
    assert param_map["header-no-doc"] is None
    assert param_map["param_doc"] == param_description
    assert param_map["param_no_doc"] is None
    assert param_map["id_doc"] == id_description
    assert param_map["id_no_doc"] is None

    # Asserts on response
    assert len(operation.responses) == 1
    assert sorted(["header-doc", "header-no-doc"]) == sorted(
        list(operation.responses["200"].headers.keys()))
    assert operation.responses["200"].description == ""
Esempio n. 7
0
def test_get_function_parameters(api_methods_fixture):
    url_method = UrlMethod(
        properties=MethodProperties.methods["dummy_get_with_parameters"][0],
        slice=None,
        method_name="dummy_get_with_parameters",
        handler=None,
    )
    function_parameter_handler = FunctionParameterHandler(
        OpenApiTypeConverter(), ArgOptionHandler(OpenApiTypeConverter()), "/basepath", url_method.properties
    )
    function_parameters = function_parameter_handler.all_params_dct
    assert len(function_parameters) == 4
    assert function_parameters["param"] == inspect.Parameter("param", inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=int)
Esempio n. 8
0
    def handle_method(self, url_method: UrlMethod, path: str) -> Operation:
        function_parameter_handler = FunctionParameterHandler(
            self.type_converter, self.arg_option_handler, path, url_method.properties
        )
        parameters = function_parameter_handler.get_parameters()
        responses = self._build_responses(url_method.properties)

        if url_method.get_operation() in ["POST", "PUT", "PATCH"]:
            extra_params = {"requestBody": function_parameter_handler.convert_request_body()}
        else:
            extra_params = {}

        tags = self._get_tags_of_operation(url_method)

        return Operation(
            responses=responses,
            operationId=url_method.method_name,
            parameters=(parameters if len(parameters) else None),
            summary=url_method.short_method_description,
            description=url_method.long_method_description,
            tags=tags,
            **extra_params,
        )