-
Notifications
You must be signed in to change notification settings - Fork 21
/
conftest.py
135 lines (108 loc) · 4.12 KB
/
conftest.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# Modified from https://github.com/jupyter/docker-stacks/
import os
import logging
import docker
import pytest
import requests
from requests.packages.urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter
LOGGER = logging.getLogger(__name__)
IMAGE_NAME_ENV_VAR = "IMAGE_NAME"
NB_PREFIX_ENV_VAR = "NB_PREFIX"
@pytest.fixture(scope='session')
def http_client():
"""Requests session with retries and backoff."""
s = requests.Session()
retries = Retry(total=9, backoff_factor=1)
s.mount('http://', HTTPAdapter(max_retries=retries))
s.mount('https://', HTTPAdapter(max_retries=retries))
return s
@pytest.fixture(scope='session')
def docker_client():
"""Docker client configured based on the host environment"""
return docker.from_env()
@pytest.fixture(scope='session')
def image_name():
"""Image name to test"""
image_name = os.getenv(IMAGE_NAME_ENV_VAR)
LOGGER.debug(f"Found image_name {image_name} in env variable {IMAGE_NAME_ENV_VAR}")
if image_name is None or len(image_name) == 0:
raise ValueError(f"Image name not found in environment variable {IMAGE_NAME_ENV_VAR}. Did you forget to set it?")
return image_name
@pytest.fixture(scope='session')
def nb_prefix():
"""
NB_PREFIX environment variable for test
Used in the notebook redirect path (eg: localhost:8888/$NB_PREFIX)
"""
nb_prefix = os.getenv(NB_PREFIX_ENV_VAR)
LOGGER.debug(f"Found nb_prefix {nb_prefix} in env variable {NB_PREFIX_ENV_VAR}")
if nb_prefix is None or len(nb_prefix) == 0:
LOGGER.debug(f"nb_prefix not found in environment variable {NB_PREFIX_ENV_VAR}. Did you forget to set it?"
f" Setting to empty string")
nb_prefix = ""
return nb_prefix
class TrackedContainer(object):
"""Wrapper that collects docker container configuration and delays
container creation/execution.
Parameters
----------
docker_client: docker.DockerClient
Docker client instance
image_name: str
Name of the docker image to launch
nb_prefix: str, optional
The NB_PREFIX arg, the base url for the server
**kwargs: dict, optional
Default keyword arguments to pass to docker.DockerClient.containers.run
"""
def __init__(self, docker_client, image_name, **kwargs):
self.container = None
self.docker_client = docker_client
self.image_name = image_name
self.kwargs = kwargs
def run(self, **kwargs):
"""Runs a docker container using the preconfigured image name
and a mix of the preconfigured container options and those passed
to this method.
Keeps track of the docker.Container instance spawned to kill it
later.
Parameters
----------
**kwargs: dict, optional
Keyword arguments to pass to docker.DockerClient.containers.run
extending and/or overriding key/value pairs passed to the constructor
Returns
-------
docker.Container
"""
all_kwargs = {}
all_kwargs.update(self.kwargs)
all_kwargs.update(kwargs)
LOGGER.info(f"Running {self.image_name} with args {all_kwargs} ...")
self.container = self.docker_client.containers.run(self.image_name, **all_kwargs)
return self.container
def remove(self):
"""Kills and removes the tracked docker container."""
if self.container:
self.container.remove(force=True)
def get_cmd(self):
image = self.docker_client.images.get(self.image_name)
return image.attrs['Config']['Cmd']
@pytest.fixture(scope='function')
def container(docker_client, image_name, nb_prefix):
"""Notebook container with initial configuration appropriate for testing
(e.g., HTTP port exposed to the host for HTTP calls).
Yields the container instance and kills it when the caller is done with it.
"""
container = TrackedContainer(
docker_client,
image_name,
detach=True,
ports={
'8888/tcp': 8888
},
environment={'NB_PREFIX': nb_prefix},
)
yield container
container.remove()