Search code examples
pythonunit-testingdockerpython-requestsdockerpy

Connection aborted when unit test to request to docker container built in python


My goal is to write a unit test that builds a docker container and tries to execute a request to the newly built container.

The test first builds an docker image, then runs the image and finally tries to execute a request to the newly created container. Currently running the test using py.test gives me

requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response',))

whereas running the same code in ipython works just fine.

Expected behavior: py.test gives a successful result.

Test

import pytest
import docker
import requests

@pytest.fixture(scope='module')
def docker_env():
    return docker.from_env()

@pytest.fixture(scope='module')
def docker_image(docker_env):
    client = docker_env
    image = client.images.build(path = ".", tag = "python-test:latest")
    yield image, client
    client.images.remove("python-test:latest")

def test_port(docker_image):
    image, client = docker_image
    client.containers.run("python-test:latest", 
                          entrypoint="/opt/conda/envs/python-docker-test/bin/gunicorn --config /usr/src/app/gunicorn.conf.py app:api",
                          detach=True,
                          ports={'8000/tcp': ('127.0.0.1', 8000)})

    resp = requests.get("http://127.0.0.1:8000/hello")
    assert resp.status == 200
    # Expect success, currently getting an error

Dockerfile

My docker file looks as follows,

FROM phusion/baseimage:0.9.22
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8

RUN apt-get update --fix-missing && apt-get install -y wget bzip2 ca-certificates \
    libglib2.0-0 libxext6 libsm6 libxrender1 \
    git mercurial subversion

RUN echo 'export PATH=/opt/conda/bin:$PATH' > /etc/profile.d/conda.sh && \
    wget --quiet https://repo.continuum.io/miniconda/Miniconda3-4.3.30-Linux-x86_64.sh -O ~/miniconda.sh && \
    /bin/bash ~/miniconda.sh -b -p /opt/conda && \
    rm ~/miniconda.sh

ENV PATH /opt/conda/bin:$PATH

WORKDIR /usr/src/app
COPY . .

RUN conda env create -f environment.yml

EXPOSE 8000

SHELL ["/bin/bash", "-c"]

ENTRYPOINT  source activate python-docker-test && /opt/conda/envs/python-docker-test/bin/gunicorn \
  --config /usr/src/app/gunicorn.conf.py  app:api

app.py

import falcon

class TestServer:
    def on_get(self, req, resp):
        resp.content_type = "text/text"

        resp.body = "hello world"
        resp.status = falcon.HTTP_OK

api = falcon.API()
api.add_route("/hello", TestServer())

environment.yml

name: python-docker-test
channels:
 - anaconda
 - conda-forge
dependencies:
 - python==3.6
 - gunicorn==19.7.1
 - pytest==3.2.5
 - gunicorn==19.7.1
 - ipython
 - falcon==1.3.0
 - pip==9.0.1
 - pip:
   - docker==2.7.0

Gunicorn.conf.py

bind = '0.0.0.0:8000'

System specs

  • Server Version: 17.12.0-ce
  • uname: 17.3.0 Darwin Kernel Version 17.3.0

Solution

  • The right test looks like,

    def test_port(docker_image):
        image, client = docker_image
        import time
        container = client.containers.run("python-test:latest",
                                          detach=True,
                                          ports={'8000/tcp': ('127.0.0.1', 8000)})
    
        time.sleep(1)
        resp = requests.get("http://127.0.0.1:8000/hello")
    
        container.kill()
        assert resp.status_code == 200