5

I want to test from one container via pytest (test below), whether another (webbelow) interacts nicely with our Postgresql DB.

I am having the following docker-compose.yaml file

version: '3.8'

services:
  web:
    build: 
      context: ./src/
      dockerfile: Dockerfile
    command: |
      bash -c 'while !</dev/tcp/db/5432; do sleep 1; done; uvicorn app.main:app --reload --workers 1 --host 0.0.0.0 --port 8000'
    volumes:
      - ./src/:/usr/src/app/
    ports:
      - 8002:8000
    environment:
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/postgres_dev
    depends_on:
      - db
  test:
    build: 
      context: ./src/
      dockerfile: Dockerfile-test
    volumes:
      - ./src/:/usr/src/app/
    stdin_open: true
    environment:
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/postgres_dev
      - TEST_PORT=8002
    depends_on:
      - web
  db:
    image: postgres:13-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    ports:
      - 5432:5432
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=postgres_dev
volumes:
  postgres_data:

Furthermore, Dockerfile-testlooks like

# pull official base image
FROM python:3.9.4-alpine

# set work directory
WORKDIR /usr/src/

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# copy requirements file
COPY ./tests/requirements.txt /usr/src/app/requirements.txt

# install dependencies
RUN set -eux \
    && apk add --no-cache --virtual .build-deps build-base \
        libressl-dev libffi-dev gcc musl-dev python3-dev \
        postgresql-dev bash \
    && pip install --upgrade pip setuptools wheel \
    && pip install -r /usr/src/app/requirements.txt \
    && rm -rf /root/.cache/pip

# copy project
COPY ./tests/ /usr/src/app/tests

and requirements.txtlooks like

pytest==6.2.5
requests==2.26.0
pytest-httpserver==1.0.3
psycopg2==2.9.2

and conftest.py looks like

import pytest
import psycopg2

@pytest.fixture(scope='function')
def session():
    conn = psycopg2.connect(host="localhost", database="hello_fastapi_dev", user="hello_fastapi", password="hello_fastapi")
    # Create a cursor object
    session = conn.cursor()
    yield session
    # Close the cursor and connection to so the server can allocate
    # bandwidth to other requests
    session.close()
    conn.close()

However, when I run

docker-compose up -d --build
docker-compose run test pytest

I get

../local/lib/python3.9/site-packages/requests/adapters.py:516: ConnectionError
=========================================================================================================================== short test summary info ============================================================================================================================
FAILED app/tests/test_projects.py::test_ping - requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8002): Max retries exceeded with url: /ping (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7faf175a86a0>: Failed...
FAILED app/tests/test_projects.py::test_auth - requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8002): Max retries exceeded with url: /auth/register (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7faf174d0070...
ERROR app/tests/test_projects.py::test_project_create - psycopg2.OperationalError: could not connect to server: Connection refused
========================================================================================================================== 2 failed, 1 error in 0.49s ==========================================================================================================================
ERROR: 1

Hence, it seems like I cannot get a connection. Could you help me here?

tobias
  • 501
  • 1
  • 6
  • 15
  • As usual, docker container don't find each other via localhost. You need to use the container name or compose service name. In your database URL env var you don't use localhost. Why would you use it in the tests? Whz don't you use that variable, if you set it like that? – The Fool Dec 22 '21 at 14:44
  • @TheFool Many thanks for your input, could you explain to me how I could reach some API in web from test like "http://localhost:8002/ping" just without the localhost? – tobias Dec 22 '21 at 14:46
  • I doubt you could do that. – The Fool Dec 22 '21 at 14:48
  • You can do that, by assigning a host name for every service you are building. Use of an orchestrator like k8s or swarm also has these capabilities. This is a starting point https://stackoverflow.com/questions/29924843/how-do-i-set-hostname-in-docker-compose – Kris Dec 22 '21 at 14:52
  • Ah sorry I think I misunderstood your question. I thought you were claiming to be able to do that. You can reach the web service by using it's name has hostname. Use http://web:8002 and do the same thing for the database like you have it in your env var and also the tcp check in the web command. – The Fool Dec 22 '21 at 14:53
  • In Docker, each container is its own `localhost`. You need to use the name of the database container `db` as a host name to connect to it from another container. The linked questions and [Networking in Compose](https://docs.docker.com/compose/networking/) in the Docker documentation have some more examples. – David Maze Dec 22 '21 at 14:56
  • db is technically not the container name though.Its the name of the compose service. If you had replicas you would get loadbalancing across them, using that name for example. The container name would be something like myproject_db_1. – The Fool Dec 22 '21 at 15:00
  • @TheFool When I run `r =requests.get('http://web:8002/ping')` from within test via pytest I get `FAILED app/tests/test_projects.py::test_ping - requests.exceptions.InvalidSchema: No connection adapters were found for 'web:8002/ping'`. Do you know what causes the issue? – tobias Dec 22 '21 at 15:25
  • Yes sorry, 8002 is for outside. That's your port mapping. Inside the network you need to use 8000. – The Fool Dec 22 '21 at 16:04
  • I got some great tips by looking at @tobias Dockerfile-test. Thanks. – bitofagoob Jul 22 '23 at 10:12

0 Answers0