Skip to content

Commit

Permalink
fix: run integration tests and unit tests in docker
Browse files Browse the repository at this point in the history
This way, we can test against PostgreSQL database. In the commit,
we also:

- removed labels_tags__like and origins_tags__like filters. These
  filters triggers an error in PostgreSQL, as we're using a JSONB
  field type, which does not support LIKE queries (this bug was in
  production too, see
  https://openfoodfacts.sentry.io/issues/4911496304/?project=4506270533091328&query=LIKE&referrer=issue-stream&sort=freq&statsPeriod=90d&stream_index=0)
- fixed some integration tests to make it work with PostgreSQL
  • Loading branch information
raphael0202 committed Feb 9, 2024
1 parent 55b1e2e commit 113e787
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 30 deletions.
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export COMPOSE_DOCKER_CLI_BUILD=1
# take it form env, or from env file
COMPOSE_PROJECT_NAME ?= $(shell grep COMPOSE_PROJECT_NAME ${ENV_FILE} | cut -d '=' -f 2)
DOCKER_COMPOSE=docker-compose --env-file=${ENV_FILE}
DOCKER_COMPOSE_TEST=COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME}_test docker-compose --env-file=${ENV_FILE}

# avoid target corresponding to file names, to depends on them
.PHONY: *
Expand Down Expand Up @@ -124,6 +125,18 @@ docs:
checks: toml-check flake8 black-check mypy isort-check docs


unit-tests:
@echo "🥫 Running tests …"
# change project name to run in isolation
${DOCKER_COMPOSE_TEST} run --rm api poetry run pytest tests/unit

integration-tests:
@echo "🥫 Running integration tests …"
# change project name to run in isolation
${DOCKER_COMPOSE_TEST} run --rm api poetry run pytest tests/integration
( ${DOCKER_COMPOSE_TEST} down -v || true )


#------------#
# Production #
#------------#
Expand Down
2 changes: 0 additions & 2 deletions app/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,6 @@ class PriceFilter(Filter):
product_id: Optional[int] | None = None
product_id__isnull: Optional[bool] | None = None
category_tag: Optional[str] | None = None
labels_tags__like: Optional[str] | None = None
origins_tags__like: Optional[str] | None = None
location_osm_id: Optional[int] | None = None
location_osm_type: Optional[LocationOSMEnum] | None = None
location_id: Optional[int] | None = None
Expand Down
4 changes: 4 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,16 @@ services:
<<: *api-common
volumes:
- ./static:/opt/open-prices/static
depends_on:
- postgres

scheduler:
<<: *api-common
command: ["python", "-m", "app", "run-scheduler"]
volumes:
- ./static:/opt/open-prices/static
depends_on:
- postgres

postgres:
restart: $RESTART_POLICY
Expand Down
4 changes: 3 additions & 1 deletion docker/dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ x-api-base: &api-base
- ./README.md:/opt/open-prices/README.md
- ./docs:/opt/open-prices/docs
- ./gh_pages:/opt/open-prices/gh_pages
# Make migrations available so that we can run them easily
# make migrations available so that we can run them easily
- ./alembic:/opt/open-prices/alembic
# mount tests
- ./tests:/opt/open-prices/tests

services:
api:
Expand Down
Empty file added tests/integration/__init__.py
Empty file.
34 changes: 7 additions & 27 deletions tests/test_api.py → tests/integration/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@
import pytest
from fastapi.encoders import jsonable_encoder
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool

from app import crud
from app.api import app, get_db
from app.db import Base
from app.db import Base, engine, session
from app.models import Session as SessionModel
from app.schemas import (
LocationCreate,
Expand All @@ -20,23 +17,12 @@
UserCreate,
)

# database setup
# ------------------------------------------------------------------------------
SQLALCHEMY_DATABASE_URL = "sqlite://"

engine = create_engine(
SQLALCHEMY_DATABASE_URL,
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base.metadata.create_all(bind=engine)


def override_get_db():
try:
db = TestingSessionLocal()
db = session()
yield db
finally:
db.close()
Expand Down Expand Up @@ -166,6 +152,7 @@ def location(db_session):

@pytest.fixture(scope="function")
def clean_users(db_session):
db_session.query(SessionModel).delete()
db_session.query(crud.User).delete()
db_session.commit()

Expand Down Expand Up @@ -550,14 +537,6 @@ def test_get_prices_filters(db_session, user_session: SessionModel, clean_prices
response = client.get("/api/v1/prices?category_tag=en:tomatoes")
assert response.status_code == 200
assert len(response.json()["items"]) == 1
# 1 price with labels_tags
response = client.get("/api/v1/prices?labels_tags__like=en:organic")
assert response.status_code == 200
assert len(response.json()["items"]) == 1
# 1 price with origins_tags
response = client.get("/api/v1/prices?origins_tags__like=en:spain")
assert response.status_code == 200
assert len(response.json()["items"]) == 1
# 1 price with price > 5
response = client.get("/api/v1/prices?price__gt=5")
assert response.status_code == 200
Expand All @@ -573,6 +552,7 @@ def test_get_prices_filters(db_session, user_session: SessionModel, clean_prices


def test_get_prices_orders(db_session, user_session: SessionModel, clean_prices):
# PRICE_1 date is "2023-10-31"
crud.create_price(db_session, PRICE_1, user_session.user)
crud.create_price(
db_session,
Expand All @@ -583,8 +563,8 @@ def test_get_prices_orders(db_session, user_session: SessionModel, clean_prices)
)
response = client.get("/api/v1/prices")
assert response.status_code == 200
assert (response.json()["items"][0]["date"]) == "2023-10-31"
response = client.get("/api/v1/prices?order_by=date") # ASC
assert len(response.json()["items"]) == 2
response = client.get("/api/v1/prices?order_by=%2Bdate") # +date, ASC
assert response.status_code == 200
assert (response.json()["items"][0]["date"]) == "2023-10-01"
response = client.get("/api/v1/prices?order_by=-date") # DESC
Expand Down Expand Up @@ -707,7 +687,7 @@ def test_get_proofs(user_session: SessionModel):
}

for i, item in enumerate(data):
assert item["id"] == i + 1
assert isinstance(item["id"], int)
assert item["file_path"].startswith("0001/")
assert item["file_path"].endswith(".webp")
assert item["type"] == ("PRICE_TAG" if i == 0 else "RECEIPT")
Expand Down

0 comments on commit 113e787

Please sign in to comment.