Ejemplo n.º 1
0
        def scoped_containers_fixture(docker_project: Project, request):
            now = datetime.utcnow()
            if request.config.getoption("--use-running-containers"):
                containers = docker_project.containers(
                )  # type: List[Container]
            else:
                if any(docker_project.containers()):
                    raise ContainersAlreadyExist(
                        'pytest-docker-compose tried to start containers but there are'
                        ' already running containers: %s, you probably scoped your'
                        ' tests wrong' % docker_project.containers())
                containers = docker_project.up()
                if not containers:
                    raise ValueError(
                        "`docker-compose` didn't launch any containers!")

            container_getter = ContainerGetter(docker_project)
            yield container_getter

            if request.config.getoption("--verbose"):
                for container in sorted(containers, key=lambda c: c.name):
                    header = "Logs from {name}:".format(name=container.name)
                    print(header, '\n', "=" * len(header))
                    print(
                        container.logs(since=now).decode("utf-8",
                                                         errors="replace")
                        or "(no logs)", '\n')

            if not request.config.getoption("--use-running-containers"):
                docker_project.down(
                    ImageType.none,
                    request.config.getoption(
                        "--docker-compose-remove-volumes"))
Ejemplo n.º 2
0
def docker_containers(
        docker_project: Project) -> Iterator[Dict[str, Container]]:
    """
    Spins up a the containers for the Docker project and returns
    them.

    Note that this fixture's scope is a single test; the containers
    will be stopped after the test is finished.

    This is intentional; stopping the containers destroys local
    storage, so that the next test can start with fresh containers.
    """
    containers: List[Container] = docker_project.up(DOCKER_SERVICES)
    if not containers:
        raise ValueError("`docker-compose` didn't launch any containers!")
    containers_by_name = dict([(c.name, c) for c in containers])

    yield containers_by_name

    # Send container logs to stdout, so that they get included in
    # the test report.
    # https://docs.pytest.org/en/latest/capture.html
    for container in sorted(containers, key=lambda c: c.name):
        header = "Logs from {0}:".format(container.name)
        logger.info(header)
        logger.info("=" * len(header))
        logger.info(container.logs().decode("utf-8", errors="replace")
                    or "(no logs)")
        logger.info('')

    docker_project.down(ImageType.none, False)
Ejemplo n.º 3
0
    def _containers_down(
        cls,
        docker_project: Project,
        docker_containers: typing.Iterable[Container],
    ) -> None:
        """
        Brings down containers that were launched using
        :py:meth:`_containers_up`.
        """
        # Send container logs to stdout, so that they get included in
        # the test report.
        # https://docs.pytest.org/en/latest/capture.html
        for container in sorted(docker_containers, key=lambda c: c.name):
            header = "Logs from {name}:".format(name=container.name)
            print(header)
            print("=" * len(header))
            print(container.logs().decode("utf-8", errors="replace")
                  or "(no logs)")
            print()

        docker_project.down(ImageType.none, False)
Ejemplo n.º 4
0
async def docker_compose(loop, request, docker_project: Project,
                         postgres_override_addr):
    async def check_postgres(url):
        conn = await asyncpg.connect(url, loop=loop)
        await conn.close()

    checks = {
        ('postgres', 'POSTGRES_DSN', postgres_override_addr,
         'postgresql://[email protected]:%d/postgres'
         '' % COMPOSE_POSTGRES_PORT, check_postgres),
    }

    result = {}

    fns = []
    to_start = []
    for svc, name, override, url, fn in checks:
        if override:
            result[name] = override
        else:
            to_start.append(svc)
            fns.append((fn, url))
            result[name] = url

    if not to_start:
        yield result
    else:
        containers = docker_project.up(to_start, remove_orphans=True)

        if not containers:
            raise ValueError("`docker-compose` didn't launch any containers!")

        try:
            timeout = 60
            start_time = time.time()
            print()
            print('Waiting for docker services...')
            last_err = None
            while start_time + timeout > time.time():
                try:
                    await asyncio.gather(*[fn(url) for fn, url in fns],
                                         loop=loop)
                    break

                except Exception as err:
                    last_err = err
                    await asyncio.sleep(1, loop=loop)
            else:
                last_err_type = type(last_err)
                raise TimeoutError(f'Unable to start all container services'
                                   f' within {timeout} seconds. Last error:'
                                   f' {last_err} ({last_err_type})')
            print('Docker services are ready')
            yield result
        finally:

            # Send container logs to stdout, so that they get included in
            # the test report.
            # https://docs.pytest.org/en/latest/capture.html
            for container in sorted(containers, key=lambda c: c.name):
                if request.config.getoption('show_docker_logs'):
                    header = f"Logs from {container.name}:"
                    print(header)
                    print("=" * len(header))
                    print(container.logs().decode("utf-8", errors="replace")
                          or "(no logs)")
                    print()

            docker_project.down(ImageType.none, False)
Ejemplo n.º 5
0
async def compose(loop,
                  request,
                  docker_project: Project,
                  postgres_override_addr,
                  rabbit_override_addr):
    async def check_postgres(url):
        conn = await asyncpg.connect(url, loop=loop)
        await conn.close()

    async def check_rabbit(url):
        transport, protocol = await aioamqp.from_url(url, loop=loop)
        await protocol.close()

    # async def check_redis(url):
    #     conn = await aioredis.create_connection(url)
    #     conn.close()

    # async def check_http(url):
    #     async with aiohttp.ClientSession(loop=loop) as ses:
    #         resp = await ses.get(url)
    #         assert resp.status == 200

    checks = {
        (
            'postgres',
            'DB_URL',
            postgres_override_addr,
            COMPOSE_POSTGRES_URL,
            check_postgres
        ),
        (
            'rabbit',
            'RABBIT_URL',
            rabbit_override_addr,
            COMPOSE_RABBIT_URL,
            check_rabbit
        ),
    }

    result = {}

    fns = []
    to_start = []
    urls = []
    for svc, name, override, url, fn in checks:
        if override:
            result[name] = override
        else:
            to_start.append(svc)
            urls.append(url)
            fns.append((fn, url))
            result[name] = url

    if not to_start:
        yield result
    else:
        containers = docker_project.up(to_start)

        if not containers:
            raise ValueError("`docker-compose` didn't launch any containers!")

        try:
            timeout = 60
            start_time = time.time()
            print()
            print('Waiting for docker services...')
            print('\n'.join(urls))
            last_err = None
            while start_time + timeout > time.time():
                try:
                    await asyncio.gather(*[fn(url) for fn, url in fns],
                                         loop=loop)
                    break

                except Exception as err:
                    last_err = err
                    await asyncio.sleep(1, loop=loop)
            else:
                last_err_type = type(last_err)
                raise TimeoutError(f'Unable to start all container services'
                                   f' within {timeout} seconds. Last error:'
                                   f' {last_err} ({last_err_type})')
            print('Docker services are ready')
            yield result
        finally:

            # Send container logs to stdout, so that they get included in
            # the test report.
            # https://docs.pytest.org/en/latest/capture.html
            for container in sorted(containers, key=lambda c: c.name):
                if request.config.getoption('show_docker_logs'):
                    header = f"Logs from {container.name}:"
                    print(header)
                    print("=" * len(header))
                    print(
                        container.logs().decode("utf-8", errors="replace") or
                        "(no logs)"
                    )
                    print()

            docker_project.down(ImageType.none, False)