forked from jupyter/docker-stacks
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor to share fixtures with option tests
- Loading branch information
Showing
3 changed files
with
136 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# Copyright (c) Jupyter Development Team. | ||
# Distributed under the terms of the Modified BSD License. | ||
import os | ||
|
||
import docker | ||
import pytest | ||
import requests | ||
|
||
from requests.packages.urllib3.util.retry import Retry | ||
from requests.adapters import HTTPAdapter | ||
|
||
|
||
@pytest.fixture(scope='session') | ||
def http_client(): | ||
"""Requests session with retries and backoff.""" | ||
s = requests.Session() | ||
retries = Retry(total=5, 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""" | ||
return os.getenv('TEST_IMAGE', 'jupyter/base-notebook') | ||
|
||
|
||
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 | ||
**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) | ||
self.container = self.docker_client.containers.run(self.image_name, **all_kwargs) | ||
return self.container | ||
|
||
def kill(self): | ||
"""Kills the tracked docker container.""" | ||
if self.container: | ||
self.container.kill() | ||
|
||
|
||
@pytest.fixture(scope='function') | ||
def container(docker_client, image_name): | ||
"""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, | ||
auto_remove=False, | ||
ports={ | ||
'8888/tcp': 8888 | ||
} | ||
) | ||
yield container | ||
container.kill() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,9 @@ | ||
# Copyright (c) Jupyter Development Team. | ||
# Distributed under the terms of the Modified BSD License. | ||
import os | ||
import time | ||
|
||
import docker | ||
import pytest | ||
import requests | ||
|
||
|
||
@pytest.fixture(scope='session') | ||
def docker_client(): | ||
"""Docker client to use""" | ||
return docker.from_env() | ||
|
||
|
||
@pytest.fixture(scope='session') | ||
def image_name(): | ||
"""Image name to test""" | ||
return os.getenv('TEST_IMAGE', 'jupyter/base-notebook') | ||
|
||
|
||
@pytest.fixture(scope='function') | ||
def nb_container(docker_client, image_name): | ||
"""Notebook container to test""" | ||
container = docker_client.containers.run( | ||
image_name, | ||
detach=True, | ||
auto_remove=True, | ||
ports={ | ||
'8888/tcp': 8888 | ||
} | ||
) | ||
yield container | ||
container.kill() | ||
|
||
|
||
def test_server_liveliness(nb_container): | ||
"""Notebook server should eventually respond with HTTP 200 OK.""" | ||
for i in range(10): | ||
try: | ||
resp = requests.get('http://localhost:8888') | ||
except requests.exceptions.ConnectionError: | ||
# Wait a bit and try again. Just because the docker container | ||
# is running doesn't mean the notebook server is ready to accept | ||
# connections inside it. | ||
time.sleep(i) | ||
else: | ||
assert resp.status_code == 200 | ||
break | ||
else: | ||
assert False, 'could not connect to server' | ||
def test_secured_server(container, http_client): | ||
"""Notebook server should eventually request user login.""" | ||
container.run() | ||
resp = http_client.get('http://localhost:8888') | ||
resp.raise_for_status() | ||
assert 'login_submit' in resp.text |