コード例 #1
0
def config_with_migrations(
    tmp_path: Path,
    mocker: ptm.MockFixture,
    request: t.Any,
) -> t.Tuple[Path, model.Config, int]:
    migrations_count = 10
    script_location = tmp_path
    if request.param == 'relative':
        script_location = Path(
            '/'.join([
                '..'
                for _ in range(len(script_location.absolute().parents, ) + 1)
            ]) + str(tmp_path), )

    files = [(script_location / f'migration_{i}.py')
             for i in range(migrations_count)]
    for i, f in enumerate(files):
        f.touch(exist_ok=False)
        f.write_text(
            '\n'.join([
                '',
                f'revision = {i+1}',
                '',
                'async def upgrade():',
                '    ...',
                '',
                'async def downgrade():',
                '    ...',
            ]), )

    return script_location, model.Config(
        script_location=script_location,
        database_name=mocker.stub(),
        database_dsn=mocker.stub(),
    ), migrations_count
コード例 #2
0
def config_with_migrations(
        tmp_path: t.Any,
        mocker: ptm.MockFixture,
) -> t.Tuple[model.Config, int]:
    migrations_count = 10
    files = [(tmp_path / f'migration_{i}.py') for i in range(migrations_count)]
    for i, f in enumerate(files):
        f.touch(exist_ok=False)
        f.write_text(
            '\n'.join([
                '',
                f'revision = {i+1}',
                '',
                'async def upgrade():',
                '    ...',
                '',
                'async def downgrade():',
                '    ...',
            ]),
        )

    return model.Config(
        script_location=tmp_path,
        database_name=mocker.stub(),
        database_dsn=mocker.stub(),
    ), migrations_count
コード例 #3
0
async def test_get_revision_migration_table_exists_with_entries(
    db_connection: asyncpg.Connection,
    table_schema: str,
    table_name: str,
    mocker: ptm.MockFixture,
) -> None:
    max_revisions = 10
    await migration.create_table(
        connection=db_connection,
        table_schema=table_schema,
        table_name=table_name,
    )
    for i in range(1, max_revisions + 1):
        await migration.save(
            connection=db_connection,
            migration=model.Migration(
                revision=model.Revision(i),
                label=__name__,
                path=mocker.stub(),
                upgrade=mocker.stub(),
                downgrade=mocker.stub(),
            ),
            direction=secrets.choice([
                model.MigrationDir.DOWN,
                model.MigrationDir.UP,
            ]),
            table_schema=table_schema,
            table_name=table_name,
        )

    assert (await migration.latest_revision(
        connection=db_connection,
        table_schema=table_schema,
        table_name=table_name,
    )) == max_revisions
コード例 #4
0
def test_app_add_api_different_base_path(
    mocker: ptm.MockFixture,
    tmp_path: Path,
) -> None:
    spec_one = mocker.stub()
    spec_one.servers = [model.OASServer(url='/v1', variables={})]

    spec_two = mocker.stub()
    spec_two.servers = [model.OASServer(url='/v2', variables={})]

    spec_admin = mocker.stub()
    spec_admin.servers = [model.OASServer(url='/admin', variables={})]

    apply_spec = mocker.patch('axion.plugins._aiohttp._apply_specification')

    the_app = app.AioHttpPlugin(configuration=mocker.ANY)

    the_app.add_api(spec_one)
    the_app.add_api(spec_two)
    the_app.add_api(spec_admin)

    router_resources = list(the_app.root_app.router.resources())
    assert len(router_resources) == 3
    assert len(the_app.api_base_paths) == 3

    for prefix, the_spec in (
        ('/v1', spec_one),
        ('/v2', spec_two),
        ('/admin', spec_admin),
    ):
        sub_app_a = the_app.api_base_paths.get(prefix, None)
        sub_app_b = next(
            (r for r in router_resources if r.canonical == prefix), None)

        assert sub_app_a is not None
        assert isinstance(
            sub_app_a,
            web.Application,
        )

        assert sub_app_b is not None
        assert isinstance(
            sub_app_b,
            web_urldispatcher.PrefixedSubAppResource,
        )

        assert sub_app_a == sub_app_b._app
        apply_spec.assert_any_call(
            for_app=sub_app_b._app,
            spec=the_spec,
        )
        apply_spec.assert_any_call(
            for_app=sub_app_a,
            spec=the_spec,
        )
コード例 #5
0
def test_app_add_api_duplicated_base_path(
    server_url: str,
    mocker: ptm.MockFixture,
) -> None:
    spec_one = mocker.stub()
    spec_one.servers = [model.OASServer(url=server_url, variables={})]

    spec_two = mocker.stub()
    spec_two.servers = [model.OASServer(url=server_url, variables={})]

    apply_spec = mocker.patch('axion.plugins._aiohttp._apply_specification')

    the_app = app.AioHttpPlugin(configuration=mocker.ANY)
    the_app.add_api(spec_one)
    with pytest.raises(
            app.DuplicateBasePath,
            match=(f'You tried to add API with base_path={server_url}, '
                   f'but it is already added. '
                   f'If you want to add more than one API, you will need to '
                   f'specify unique base paths for each API. '
                   f'You can do this either via OAS\'s "servers" property or '
                   f'base_path argument of this function.'),
    ):
        the_app.add_api(spec_two)

    assert len(the_app.api_base_paths) == 1

    assert mock.call(
        for_app=the_app.api_base_paths[server_url],
        spec=spec_one,
    ) in apply_spec.call_args_list
    assert mock.call(
        for_app=the_app.api_base_paths[server_url],
        spec=spec_two,
    ) not in apply_spec.call_args_list

    if server_url == '/':
        apply_spec.assert_called_once_with(
            for_app=the_app.root_app,
            spec=spec_one,
        )
        assert not the_app.root_app._subapps
    else:
        assert the_app.root_app._subapps
        assert 1 == len(the_app.root_app._subapps)
        apply_spec.assert_called_once_with(
            for_app=the_app.root_app._subapps[-1],
            spec=spec_one,
        )
コード例 #6
0
def test_add_api_multiple_servers(
    mocker: ptm.MockFixture,
    caplog: _logging.LogCaptureFixture,
) -> None:
    loaded_spec = mocker.stub()
    loaded_spec.servers = [
        model.OASServer(url='/v1', variables={}),
        model.OASServer(url='/v2', variables={}),
        model.OASServer(url='/v3', variables={}),
    ]

    mocker.patch('axion.plugins._aiohttp._apply_specification')

    the_app = app.AioHttpPlugin(configuration=mocker.ANY)
    the_app.add_api(spec=loaded_spec)

    assert len(the_app.api_base_paths) == 1

    assert '/v1' in the_app.api_base_paths
    assert '/v2' not in the_app.api_base_paths
    assert '/v3' not in the_app.api_base_paths

    msg = ('There are 3 servers, axion will assume first one. '
           'This behavior might change in the future, once axion knows '
           'how to deal with multiple servers')
    assert next(
        filter(
            lambda r: r.levelname.lower() == 'warning' and r.msg == msg,
            caplog.records,
        ),
        None,
    ) is not None
コード例 #7
0
def test_tictactoe_draw(mocker: pytest_mock.MockFixture) -> None:
    send_message = mocker.stub(name='send_message_stub')
    bot = TicTacToeUserHandler(send_message)
    bot.handle_message('start')
    bot.handle_message('X 1 1')
    bot.handle_message('O 2 2')
    bot.handle_message('X 0 0')
    bot.handle_message('O 1 0')
    bot.handle_message('X 1 2')
    bot.handle_message('O 2 1')
    bot.handle_message('X 2 0')
    bot.handle_message('O 0 2')
    bot.handle_message('X 0 1')
    assert send_message.call_args_list == [
        mocker.call('...\n...\n...'),
        mocker.call('...\n.X.\n...'),
        mocker.call('...\n.X.\n..O'),
        mocker.call('X..\n.X.\n..O'),
        mocker.call('XO.\n.X.\n..O'),
        mocker.call('XO.\n.X.\n.XO'),
        mocker.call('XO.\n.XO\n.XO'),
        mocker.call('XOX\n.XO\n.XO'),
        mocker.call('XOX\n.XO\nOXO'),
        mocker.call('XOX\nXXO\nOXO'),
        mocker.call('Game is finished, draw'),
    ]
コード例 #8
0
def test_app_add_api_overlapping_base_paths(
    server_url: str,
    overlapping_server_url: str,
    mocker: ptm.MockFixture,
) -> None:
    spec_one = mocker.stub()
    spec_one.servers = [model.OASServer(url=server_url, variables={})]

    spec_two = mocker.stub()
    spec_two.servers = [
        model.OASServer(url=overlapping_server_url, variables={})
    ]

    apply_spec = mocker.patch('axion.plugins._aiohttp._apply_specification')

    the_app = app.AioHttpPlugin(configuration=mocker.ANY)

    the_app.add_api(spec_one)
    with pytest.raises(
            app.OverlappingBasePath,
            match=
        (f'You tried to add API with base_path={overlapping_server_url}, '
         f'but it is overlapping one of the APIs that has been already added. '
         f'You need to make sure that base paths for all APIs do '
         f'not overlap each other.'),
    ):
        the_app.add_api(spec_two)

    assert len(the_app.api_base_paths) == 1
    apply_spec.assert_called_once_with(
        for_app=the_app.api_base_paths[server_url],
        spec=spec_one,
    )

    if server_url == '/':
        apply_spec.assert_called_once_with(
            for_app=the_app.root_app,
            spec=spec_one,
        )
        assert not the_app.root_app._subapps
    else:
        assert the_app.root_app._subapps
        assert 1 == len(the_app.root_app._subapps)
        apply_spec.assert_called_once_with(
            for_app=the_app.root_app._subapps[-1],
            spec=spec_one,
        )
コード例 #9
0
def test_game_not_started(mocker: pytest_mock.MockFixture) -> None:
    send_message = mocker.stub(name='send_message_stub')
    bot = TicTacToeUserHandler(send_message)
    bot.handle_message('O 2 1')
    bot.handle_message('Hello')
    assert send_message.call_args_list == [
        mocker.call('Game is not started'),
        mocker.call('Game is not started')
    ]
コード例 #10
0
def test_chat_broadcast(mocker: pytest_mock.MockFixture) -> None:
    send_message = mocker.stub(name='send_message_stub')
    bot = ChatBot(send_message)
    bot.handle_message(10, 'hello')
    bot.handle_message(11, 'world')
    assert send_message.call_args_list == [
        mocker.call(10, '#10: hello'),
        mocker.call(10, '#11: world'),
        mocker.call(11, '#11: world'),
    ]
コード例 #11
0
def test_multiple_operations(mocker: pytest_mock.MockFixture) -> None:
    send_message = mocker.stub(name='send_message_stub')
    bot = CalculatorUserHandler(send_message)
    bot.handle_message('2 * 3')
    bot.handle_message('3 / 2')
    bot.handle_message('3 - 4')
    assert send_message.call_args_list == [
        mocker.call('6'),
        mocker.call('1'),
        mocker.call('-1')
    ]
コード例 #12
0
def test_wrong_symbols(mocker: pytest_mock.MockFixture) -> None:
    send_message = mocker.stub(name='send_message_stub')
    bot = TicTacToeUserHandler(send_message)
    bot.handle_message('start')
    bot.handle_message('X 0 0')
    bot.handle_message('A 1 1')
    bot.handle_message('B 2 2')
    assert send_message.call_args_list == [
        mocker.call('...\n...\n...'),
        mocker.call('X..\n...\n...'),
        mocker.call('Invalid turn'),
        mocker.call('Invalid turn')
    ]
コード例 #13
0
def test_game_many_starts(mocker: pytest_mock.MockFixture) -> None:
    send_message = mocker.stub(name='send_message_stub')
    bot = TicTacToeUserHandler(send_message)
    bot.handle_message('start')
    bot.handle_message('start')
    bot.handle_message('start')
    bot.handle_message('start')
    assert send_message.call_args_list == [
        mocker.call('...\n...\n...'),
        mocker.call('...\n...\n...'),
        mocker.call('...\n...\n...'),
        mocker.call('...\n...\n...')
    ]
コード例 #14
0
def test_tictactoe_wrong_arguments(mocker: pytest_mock.MockFixture) -> None:
    send_message = mocker.stub(name='send_message_stub')
    bot = TicTacToeUserHandler(send_message)
    bot.handle_message('start')
    bot.handle_message('X 0 0')
    bot.handle_message('X 1 0')
    bot.handle_message('O 0 0')
    assert send_message.call_args_list == [
        mocker.call('...\n...\n...'),
        mocker.call('X..\n...\n...'),
        mocker.call('Invalid turn'),
        mocker.call('Invalid turn'),
    ]
コード例 #15
0
    async def test_async_iterator_updates(
            self, progress: DurationProgress,
            mocker: pytest_mock.MockFixture) -> None:
        stub = mocker.stub()
        progress.duration = servo.Duration("0.7ms")
        async for update in progress.every("0.1ms"):
            stub(update.progress)

        try:
            stub.assert_called()
        except AssertionError as e:
            # TODO yagni code is yagni, fix test if it ever gets used
            pytest.xfail(f"Failure in unused code: {e}")
        assert progress.progress == 100.0
コード例 #16
0
    def test_true_if_code_matches(
        self,
        mocker: ptm.MockFixture,
    ) -> None:
        oas_op = mocker.stub()
        oas_op.id = mocker.ANY
        oas_op.responses = responses = {
            http_code: mocker.ANY
            for http_code in range(200, 500)
        }

        v = validator.HttpCodeValidator(oas_op)

        for http_code in responses.keys():
            assert v({'http_code': http_code}) == http_code
コード例 #17
0
    def test_always_true_default_repr(
        self,
        mocker: ptm.MockFixture,
    ) -> None:

        oas_op = mocker.stub()
        oas_op.id = mocker.ANY
        oas_op.responses = {
            'default': mocker.ANY,
        }

        v = validator.HttpCodeValidator(oas_op)

        for http_code in range(200, 500):
            assert v({'http_code': http_code}) == http_code
コード例 #18
0
def test_db_history(
    cli_runner: testing.CliRunner,
    mocker: ptm.MockFixture,
    entries_count: int,
) -> None:
    @dataclass
    class MockedConfig:
        database_dsn: str
        database_name: str

    entries = model.MigrationHistory([
        model.MigrationHistoryEntry(
            revision=model.Revision(rev),
            timestamp=model.Timestamp(dt.datetime.today()),
            label=mocker.stub(),
            direction=model.MigrationDir.UP if rev %
            2 else model.MigrationDir.DOWN,
        ) for rev in range(entries_count)
    ])

    mocker.patch(
        'asyncpg_migrate.loader.load_configuration',
        return_value=MockedConfig(
            'postgres://*****:*****@test:5432/test',
            'test',
        ),
    )
    mocker.patch(
        'asyncpg.connect',
        side_effect=asyncio.coroutine(lambda dsn: object()),
    )
    mocker.patch(
        'asyncpg_migrate.engine.migration.list',
        side_effect=asyncio.coroutine(lambda *args, **kwargs: entries),
    )

    from asyncpg_migrate import main

    result = cli_runner.invoke(main.db, 'history')
    if not entries_count:
        assert result.exception is not None
        assert result.exit_code == 1
        assert 'No revisions found, you might want to run some migrations first :)' in \
            result.output
    else:
        assert result.exception is None
        assert result.exit_code == 0
        assert len(result.output.split('\n')[3:]) - 1 == entries_count
コード例 #19
0
def test_many_invalid_turns(mocker: pytest_mock.MockFixture) -> None:
    send_message = mocker.stub(name='send_message_stub')
    bot = TicTacToeUserHandler(send_message)
    bot.handle_message('start')
    bot.handle_message('O 1 1')
    bot.handle_message('X 1 1')
    bot.handle_message('X 2 2')
    bot.handle_message('O 0 0')
    bot.handle_message('O 2 2')
    assert send_message.call_args_list == [
        mocker.call('...\n...\n...'),
        mocker.call('Invalid turn'),
        mocker.call('...\n.X.\n...'),
        mocker.call('Invalid turn'),
        mocker.call('O..\n.X.\n...'),
        mocker.call('Invalid turn')
    ]
コード例 #20
0
def test_add_api_single_server(
    server_base_path: str,
    add_api_base_path: t.Optional[str],
    mocker: ptm.MockFixture,
    tmp_path: Path,
) -> None:
    loaded_spec = mocker.stub()
    loaded_spec.servers = [
        model.OASServer(
            url=server_base_path,
            variables={},
        )
    ]

    apply_spec = mocker.patch('axion.plugins._aiohttp._apply_specification')
    get_base_path = mocker.patch(
        'axion.plugins._aiohttp._get_base_path',
        return_value=server_base_path,
    )

    the_app = app.AioHttpPlugin(configuration=mocker.ANY)
    the_app.add_api(loaded_spec, add_api_base_path)

    assert len(the_app.api_base_paths) == 1

    if add_api_base_path is not None:

        assert add_api_base_path in the_app.api_base_paths
        assert server_base_path not in the_app.api_base_paths

        get_base_path.assert_not_called()
        apply_spec.assert_called_once_with(
            for_app=the_app.api_base_paths[add_api_base_path],
            spec=loaded_spec,
        )
    else:

        assert server_base_path in the_app.api_base_paths
        assert add_api_base_path not in the_app.api_base_paths

        get_base_path.assert_called_once_with(loaded_spec.servers)
        apply_spec.assert_called_once_with(
            for_app=the_app.api_base_paths[server_base_path],
            spec=loaded_spec,
        )
コード例 #21
0
def test_tictactoe_winner_x(mocker: pytest_mock.MockFixture) -> None:
    send_message = mocker.stub(name='send_message_stub')
    bot = TicTacToeUserHandler(send_message)
    bot.handle_message('start')
    bot.handle_message('X 0 0')
    bot.handle_message('O 1 0')
    bot.handle_message('X 1 1')
    bot.handle_message('O 2 0')
    bot.handle_message('X 2 2')
    assert send_message.call_args_list == [
        mocker.call('...\n...\n...'),
        mocker.call('X..\n...\n...'),
        mocker.call('XO.\n...\n...'),
        mocker.call('XO.\n.X.\n...'),
        mocker.call('XOO\n.X.\n...'),
        mocker.call('XOO\n.X.\n..X'),
        mocker.call('Game is finished, X wins'),
    ]
コード例 #22
0
def test_x_wins(mocker: pytest_mock.MockFixture) -> None:
    send_message = mocker.stub(name='send_message_stub')
    bot = TicTacToeUserHandler(send_message)
    bot.handle_message('start')
    bot.handle_message('X 1 1')
    bot.handle_message('O 1 2')
    bot.handle_message('X 0 0')
    bot.handle_message('O 2 2')
    bot.handle_message('X 0 2')
    bot.handle_message('O 2 0')
    bot.handle_message('X 0 1')
    assert send_message.call_args_list == [
        mocker.call('...\n...\n...'),
        mocker.call('...\n.X.\n...'),
        mocker.call('...\n.X.\n.O.'),
        mocker.call('X..\n.X.\n.O.'),
        mocker.call('X..\n.X.\n.OO'),
        mocker.call('X..\n.X.\nXOO'),
        mocker.call('X.O\n.X.\nXOO'),
        mocker.call('X.O\nXX.\nXOO'),
        mocker.call('Game is finished, X wins')
    ]
コード例 #23
0
    def test_fail_if_no_match(
        self,
        mocker: ptm.MockFixture,
    ) -> None:
        oas_op = mocker.stub()
        oas_op.id = op_id = mocker.ANY
        oas_op.responses = responses = {
            http_code: mocker.ANY
            for http_code in range(200, 204)
        }

        v = validator.HttpCodeValidator(oas_op)
        wrong_code = 304

        with pytest.raises(validator.ValidationError) as err:
            v({'http_code': wrong_code})

        assert err.value.oas_operation_id == mocker.ANY
        assert err.value.occurred_at == 'return.http_code'
        assert err.value.message == (
            f'HTTP code {wrong_code} does not match {op_id} '
            f'response codes {{{", ".join(map(str, responses.keys()))}}}.'
        )
コード例 #24
0
def test_app_add_with_custom_base_path(mocker: ptm.MockFixture) -> None:
    server_url = '/api/v1/'
    arg_base_path = '/'

    spec_one = mocker.stub()
    spec_one.servers = [
        model.OASServer(url=server_url, variables={}),
    ]

    apply_spec = mocker.patch('axion.plugins._aiohttp._apply_specification')
    get_base_path = mocker.patch('axion.plugins._aiohttp._get_base_path')

    the_app = app.AioHttpPlugin(configuration=mocker.ANY)
    the_app.add_api(spec_one, base_path=arg_base_path)

    assert 1 == len(the_app.api_base_paths)
    assert arg_base_path in the_app.api_base_paths
    assert server_url not in the_app.api_base_paths

    apply_spec.assert_any_call(
        for_app=the_app.root_app,
        spec=spec_one,
    )
    get_base_path.assert_not_called()
コード例 #25
0
def test_tictactoe_not_started(mocker: pytest_mock.MockFixture) -> None:
    send_message = mocker.stub(name='send_message_stub')
    bot = TicTacToeUserHandler(send_message)
    bot.handle_message('START THE GAME, STUPID BOT')
    assert send_message.call_args_list == [mocker.call('Game is not started')]
コード例 #26
0
def test_addition(mocker: pytest_mock.MockFixture) -> None:
    send_message = mocker.stub(name='send_message_stub')
    CalculatorUserHandler(send_message).handle_message('2 + 3')
    assert send_message.call_args_list == [mocker.call('5')]