def test_non_existent_file(caplog) -> None:
    """
    Asserts that a non-existent file will raise an error.
    """
    with pytest.raises(ImproperlyConfigured,
                       match='The path `test` does not point to a valid file. '
                       'Make sure to point to the specification file.'):
        fetch_from_dir('test')
        assert 'Path `test` does not resolve as a valid file.' in caplog.records
def test_bad_filetype() -> None:
    """
    Asserts that an appropriate exception is raised when a function tries to pass a non yml/json schema.
    """
    with pytest.raises(
            ImproperlyConfigured,
            match=
            'The specified file path does not seem to point to a JSON or YAML file.'
    ):
        fetch_from_dir(settings.BASE_DIR + '/demo_project/settings.py')
def test_successful_yml_fetch() -> None:
    """
    Tests that a file is fetched successfully.
    """
    content = fetch_from_dir(settings.BASE_DIR +
                             '/demo_project/openapi-schema.yml')
    assert 'openapi' in content
def test_successful_parse_undocumented_endpoints() -> None:
    """
    Asserts that a schema section is returned successfully.
    """
    schema = fetch_from_dir(settings.BASE_DIR +
                            '/demo_project/openapi-schema.yml')

    for url in ['/api/v1/cars/incorrect/', '/api/v1/trucks/incorrect/']:
        schema_section = parse_endpoint(schema, 'GET', url, status_code=200)
        assert schema_section == {'type': 'array', 'items': {}}
def test_no_matching_method() -> None:
    """
    Asserts that the right exception is raised when an endpoint is documented, but the particular method is not.
    """
    schema = fetch_from_dir(settings.BASE_DIR +
                            '/demo_project/openapi-schema.yml')
    del schema['paths']['/api/v1/trucks/correct/']['get']
    with pytest.raises(KeyError,
                       match='The OpenAPI schema has no method called `GET`'):
        schema_section = parse_endpoint(schema,
                                        'GET',
                                        '/api/v1/trucks/correct/',
                                        status_code=200)
def test_unreadable_file(monkeypatch, caplog) -> None:
    """
    Asserts that the appropriate error is raised when we fail to read a file.
    """
    class MockedLogger:
        def debug(self, *args):
            raise Exception('test')

        def exception(self, *args):
            import logging

            logger = logging.getLogger('django_swagger_tester')
            logger.exception('test')

    monkeypatch.setattr('django_swagger_tester.static.get_schema.logger',
                        MockedLogger)

    with pytest.raises(
            ImproperlyConfigured,
            match=
            'Could not read the openapi specification. Please make sure the path setting is correct.\n\nError: test'
    ):
        fetch_from_dir(settings.BASE_DIR + '/demo_project/openapi-schema.yml')
def test_no_matching_routes() -> None:
    """
    Asserts that the right exception is raised when an endpoint is not documented in the schema.
    """
    schema = fetch_from_dir(settings.BASE_DIR +
                            '/demo_project/openapi-schema.yml')
    del schema['paths']['/api/v1/trucks/correct/']
    with pytest.raises(
            ValueError,
            match=
            'Could not match the resolved url to a documented endpoint in the OpenAPI specification'
    ):
        schema_section = parse_endpoint(schema,
                                        'GET',
                                        '/api/v1/trucks/correct/',
                                        status_code=200)
def test_successful_parse_documented_endpoints() -> None:
    """
    Asserts that a schema section is returned successfully.
    """
    schema = fetch_from_dir(settings.BASE_DIR +
                            '/demo_project/openapi-schema.yml')
    documented_endpoints = [
        {
            'url': '/api/v1/cars/correct/',
            'expected': {
                'title': 'Success',
                'type': 'array',
                'items': {
                    'title': 'Success',
                    'type': 'object',
                    'properties': {
                        'name': {
                            'description': 'A swedish car?',
                            'type': 'string',
                            'example': 'Saab'
                        },
                        'color': {
                            'description': 'The color of the car.',
                            'type': 'string',
                            'example': 'Yellow'
                        },
                        'height': {
                            'description': 'How tall the car is.',
                            'type': 'string',
                            'example': 'Medium height'
                        },
                        'width': {
                            'description': 'How wide the car is.',
                            'type': 'string',
                            'example': 'Very wide'
                        },
                        'length': {
                            'description': 'How long the car is.',
                            'type': 'string',
                            'example': '2 meters'
                        },
                    },
                },
            },
        },
        {
            'url': '/api/v1/trucks/correct/',
            'expected': {
                'title': 'Success',
                'type': 'array',
                'items': {
                    'title': 'Success',
                    'type': 'object',
                    'properties': {
                        'name': {
                            'description': 'A swedish truck?',
                            'type': 'string',
                            'example': 'Saab'
                        },
                        'color': {
                            'description': 'The color of the truck.',
                            'type': 'string',
                            'example': 'Yellow'
                        },
                        'height': {
                            'description': 'How tall the truck is.',
                            'type': 'string',
                            'example': 'Medium height'
                        },
                        'width': {
                            'description': 'How wide the truck is.',
                            'type': 'string',
                            'example': 'Very wide'
                        },
                        'length': {
                            'description': 'How long the truck is.',
                            'type': 'string',
                            'example': '2 meters'
                        },
                    },
                },
            },
        },
    ]
    for item in documented_endpoints:
        print('s')
        schema_section = parse_endpoint(schema,
                                        'GET',
                                        item['url'],
                                        status_code=200)
        assert schema_section == item['expected']
Esempio n. 9
0
def _validate_settings(
        config: dict) -> Tuple[str, Union[str, None], Union[str, None]]:
    """
    Validates settings.

    :param config: package settings, dict
    :return: Tuple of 3 strings/optional strings
            - schema setting ("dynamic" or "static"),
            - case setting (e.g., "camel case"),
            - and path (file path if schema setting is static, else None)
    """
    logger.debug('Validating settings.')

    # Make sure schema is correctly specified
    # The default schema value is "dynamic", so a `None` would only be set if it was overwritten by the project settings
    schema_is_none = not config['SCHEMA'] or not isinstance(
        config['SCHEMA'], str)
    if schema_is_none or config['SCHEMA'].lower() not in ['dynamic', 'static']:
        logger.error(
            'SCHEMA setting is mis-specified. Needs to be "dynamic" or "static", not %s',
            config['SCHEMA'])
        raise ImproperlyConfigured(
            f'`SCHEMA` needs to be set to `dynamic` or `static` in the openapi-tester module, '
            f'not {config["SCHEMA"]}. Please update your SWAGGER_TESTER settings.'
        )

    # Make sure the case setting is correctly specified
    # The default case value "camel case"
    accepted_cases = ['camel case', 'snake case', 'kebab case', 'pascal case']
    if config['CASE'] is None:
        pass
    elif not isinstance(config['CASE'],
                        str) or config['CASE'] not in accepted_cases:
        logger.error('CASE setting is mis-specified.')
        raise ImproperlyConfigured(
            f'The openapi-tester package currently doesn\'t support a case called {config["CASE"]}.'
            f' Set case to `snake case` for snake_case, '
            f'`camel case` for camelCase, '
            f'`pascal case` for PascalCase,'
            f'`kebab case` for kebab-case, '
            f'or to `None` to skip case validation completely.')

    # Make sure the path to an openapi schema is specified if the SCHEMA is set to `static`
    if config['SCHEMA'] == 'static':
        if config['PATH'] is None:
            logger.error('PATH setting is not specified.')
            raise ImproperlyConfigured(
                f'`PATH` is a required setting for the django-swagger-tester module. Please update your SWAGGER_TESTER settings.'
            )
        elif not isinstance(config['PATH'], str):
            logger.error('PATH setting is not a string.')
            raise ImproperlyConfigured(
                '`PATH` needs to be a string. Please update your SWAGGER_TESTER settings.'
            )
        else:
            from django_swagger_tester.static.get_schema import fetch_from_dir

            fetch_from_dir(config['PATH'])

    # Make sure drf-yasg is installed for dynamic schemas
    elif config['SCHEMA'] == 'dynamic':
        if 'drf_yasg' not in apps.app_configs.keys():
            raise ImproperlyConfigured(
                '`drf_yasg` is missing from INSTALLED_APPS. '
                'The package is required for testing dynamic schemas.')
    return (
        config['SCHEMA'].lower(),
        config['CASE'].lower() if config['CASE'] else None,
        config['PATH'].lower() if config['PATH'] else None,
    )