import asyncio
import uuid
from distutils.version import StrictVersion
from os import environ as ENV

import pytest

from aiodocker.docker import Docker
from aiodocker.exceptions import DockerError


_api_versions = {
    "17.06": "v1.30",
    "17.05": "v1.29",
    "17.04": "v1.28",
    "17.03": "v1.27",
}


def _random_name():
    return "aiodocker-" + uuid.uuid4().hex[:7]


@pytest.fixture
def random_name():
    return _random_name


@pytest.fixture(scope='session')
def testing_images():
    # Prepare a small Linux image shared by most test cases.
    event_loop = asyncio.get_event_loop()

    async def _pull():
        docker = Docker()
        required_images = [
            'alpine:latest', 'redis:latest', 'python:3.6.1-alpine',
        ]
        for img in required_images:
            try:
                await docker.images.get(img)
            except DockerError as e:
                assert e.status == 404
                print('Pulling "{img}" for the testing session...'
                      .format(img=img))
                await docker.pull(img)
        await docker.close()
    event_loop.run_until_complete(_pull())


@pytest.fixture
def docker(event_loop, testing_images):
    kwargs = {}
    if "DOCKER_VERSION" in ENV:
        kwargs["api_version"] = _api_versions[ENV["DOCKER_VERSION"]]
    docker = Docker(**kwargs)
    yield docker

    async def _finalize():
        await docker.close()
    event_loop.run_until_complete(_finalize())


@pytest.fixture
def requires_api_version(docker):

    def check(version, reason):
        if StrictVersion(docker.api_version[1:]) < StrictVersion(version[1:]):
            pytest.skip(reason)

    yield check


@pytest.fixture
def swarm(event_loop, docker):
    if StrictVersion(docker.api_version[1:]) < StrictVersion("1.28"):
        pytest.skip("The feature is experimental before API version 1.28")
    assert event_loop.run_until_complete(docker.swarm.init())
    yield docker
    try:
        assert event_loop.run_until_complete(docker.swarm.leave(force=True))
    except DockerError as exc:
        if StrictVersion(docker.api_version[1:]) >= StrictVersion("1.30"):
            raise
        else:
            # NOTE: in Docker version 1.28 and 1.29, it is possible that Docker
            #       refuses to leave the Swarm cleanly. Reducing the number
            #       of service ran seems to solve the issue. More at #53
            assert event_loop.run_until_complete(
                docker.swarm.leave(force=True))


@pytest.fixture
def shell_container(event_loop, docker):
    container = None
    config = {
        "Cmd": ["/bin/ash"],
        "Image": "alpine:latest",
        "AttachStdin": False,
        "AttachStdout": False,
        "AttachStderr": False,
        "Tty": True,
        "OpenStdin": True,
    }

    async def _spawn():
        nonlocal container
        container = await docker.containers.create_or_replace(
            config=config,
            name='aiodocker-testing-shell')
        await container.start()
    event_loop.run_until_complete(_spawn())

    yield container

    async def _delete():
        nonlocal container
        await container.delete(force=True)
    event_loop.run_until_complete(_delete())


@pytest.fixture
def redis_container(event_loop, docker):
    container = None
    config = {
        "Image": "redis:latest",
        "PublishAllPorts": True,
    }

    async def _spawn():
        nonlocal container
        container = await docker.containers.create_or_replace(
            config=config,
            name='aiodocker-testing-redis')
        await container.start()
    event_loop.run_until_complete(_spawn())

    yield container

    async def _delete():
        nonlocal container
        await container.delete(force=True)
    event_loop.run_until_complete(_delete())

@@ -93,16 +93,33 @@
 n as ENV
+%0Aimport traceback
 %0A%0Aimport
@@ -400,24 +400,41 @@
 test.fixture
+(scope='session')
 %0Adef random_
@@ -449,27 +449,837 @@
     
-return _random_name
+yield _random_name%0A%0A    # If some test cases have used randomly-named temporary images,%0A    # we need to clean up them!%0A    if ENV.get('CI', '') == 'true':%0A        # But inside the CI server, we don't need clean up!%0A        return%0A    event_loop = asyncio.get_event_loop()%0A%0A    async def _clean():%0A        docker = Docker()%0A        images = await docker.images.list()%0A        for img in images:%0A            if img%5B'RepoTags'%5D is None:%0A                continue%0A            try:%0A                if img%5B'RepoTags'%5D%5B0%5D.startswith('aiodocker-'):%0A                    print('Deleting image id: %7B0%7D'.format(img%5B'Id'%5D))%0A                    await docker.images.delete(img%5B'Id'%5D, force=True)%0A            except DockerError as e:%0A                traceback.print_exc()%0A        await docker.close()%0A%0A    event_loop.run_until_complete(_clean())
 %0A%0A%0A@
@@ -1932,32 +1932,33 @@
  docker.close()%0A
+%0A
     event_loop.r

Clean up randomly-named temporary images after testing