I am trying to setup integration tests in my GitLab CI pipeline. For that, I use docker compose
to spin up a container exposing fastapi http endpoints and use a series of pytest unittests to query these endpoints. When I run the container on my local machine and execute pytest tests
, everything works. When ran in the GitLab pipeline, the container spins up just fine, but all tests fail with
FAILED tests/test_endpoints.py::test_video_upload - requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8000): Max retries exceeded with url: /video_upload (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fd392a9a5a0>: Failed to establish a new connection: [Errno 111] Connection refused'))
docker-compose.yml
:
services:
fitai-pro-service:
container_name: fitai-pro
build: .
image: tabeqc/fitai-pro
volumes:
- .:/app
ports:
- "8000:8000"
command: >
uvicorn api:app --host 0.0.0.0 --port 8000
.gitlab-ci.yml
:
stages:
- test
test:
stage: test
image:
name: docker:latest
services:
- name: docker:dind
variables:
DOCKER_COMPOSE_FILE: "app/docker-compose.yml"
DOCKER_HOST: "tcp://docker:2375"
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
before_script:
- apk add --no-cache python3 py3-pip
- python3 -m venv /venv
- source /venv/bin/activate
- pip install --upgrade pip
- pip install -r tests/requirements.txt
- docker-compose -f $DOCKER_COMPOSE_FILE up -d
- docker exec fitai-pro curl -v http://localhost:8000/health || exit 1
script:
- pytest tests
after_script:
- docker-compose -f $DOCKER_COMPOSE_FILE down
Dockerfile
:
FROM python:3.11-slim
WORKDIR /app
RUN apt-get update && \
apt-get install -y \
curl \
libgl1 \
libgl1-mesa-glx \
libglib2.0-0 && \
rm -rf /var/lib/apt/lists/*
COPY . .
RUN pip install --upgrade -r requirements.txt
part of tests.py
:
URL = "http://localhost:8000"
def test_video_upload(sample_video):
url = f"{URL}/video_upload"
with open(sample_video, "rb") as video_file:
response = requests.post(url, files={"video_file": video_file})
assert response.status_code == 200
assert "video_path" in response.json()
os.unlink(sample_video)
No matter what I set the host part of URL
to (localhost
, docker
, fitai-pro
etc.), the result is the same. Also, docker exec fitai-pro curl -v http://localhost:8000/health
works fine locally, but also returns a Connection refused
error in the pipeline.
Any leads are very much appreciated.
Turns out it was just a matter of waiting for the containers to finish starting up before attempting the tests. Using docker
as hostname and adding a repeated health check to make sure the tests only begin when the container is ready solved the issue.
Example command in before_script
that accomplishes this:
- >
i=1; while [ $i -le 15 ]; do
curl -v http://docker:8000/health && break || sleep 1;
if [ $i -eq 15 ]; then exit 1; fi;
i=$((i + 1));
done