Skip to content
Merged

Dev #33

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python

name: integration-tests
name: Tests

on:
push:
Expand Down Expand Up @@ -42,11 +39,12 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: "pip"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest pytest-cov alembic
pip install pytest-cov
if [ -f orders_service/requirements-dev.txt ]; then pip install -r orders_service/requirements-dev.txt; fi

- name: Wait for Postgres
Expand All @@ -60,7 +58,7 @@ jobs:
# env:
# DATABASE_URL: postgresql://test:test@localhost:5432/test_db

- name: Integration tests with pytest
- name: Tests with pytest
run: |
mkdir -p logs
LOGFILE="logs/pytest-$(date +'%Y-%m-%d_%H%M%S').log"
Expand Down
36 changes: 34 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ services:
POSTGRES_PASSWORD: ${DATABASE_PSWD}
POSTGRES_DB: ${DATABASE_DB}
ports:
- "15432:5432"
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
Expand All @@ -31,11 +31,43 @@ services:
depends_on:
db:
condition: service_healthy


# test:
test-db:
image: postgres:16-bookworm
profiles: ["test"]
env_file:
- ./.env.test
environment:
POSTGRES_USER: ${DATABASE_USER}
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
POSTGRES_DB: ${DATABASE_DB}
tmpfs:
- /var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U test1"]
interval: 5s
timeout: 5s
retries: 5


orders_service_test:
profiles: ["test"]
build:
context: orders_service/
target: test
dockerfile: ./Dockerfile
environment:
ENV: TEST
env_file: orders_service/.env.test
depends_on:
test-db:
condition: service_healthy

volumes:
postgres_data:


# analytics_service:
# build: ./analytics_service
# ports:
Expand Down
9 changes: 4 additions & 5 deletions orders_service/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,21 @@ FROM base AS dev
COPY requirements-dev.txt .
RUN pip install --no-cache-dir -r requirements-dev.txt

# COPY pytest.ini .
COPY tests ./tests/

COPY alembic.ini .
COPY alembic ./alembic

ENV ENV=DEV

# TEST
FROM dev AS test

# COPY pytest.ini .
COPY tests ./tests/

RUN pip install --no-cache-dir pytest-cov
ENV ENV=TEST

# ---------- production ----------
FROM base AS prod

ENV ENV=PROD


2 changes: 1 addition & 1 deletion orders_service/app/db_logic/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def get_orders(db: Session, name: str | None = None, product: str | None = None)

def delete_by_id(db: Session, order_id: int):
try:
result = get_order_by_id(db, order_id) #catch for none?
result = get_order_by_id(db, order_id)
if not result:
return None
db.delete(result)
Expand Down
2 changes: 1 addition & 1 deletion orders_service/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def create_app():
)
@fastapi_app.get("/")
async def root():
return {"message": "Hello World"}
return {"message": "orders_service"}

fastapi_app.include_router(orders.router)
fastapi_app.include_router(health.router)
Expand Down
6 changes: 5 additions & 1 deletion orders_service/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ if [ "$ENV" = "DEV" ]; then
--reload
elif [ "$ENV" = "TEST" ]; then
echo "Running tests"
exec pytest /app/orders_service/tests --rootdir=/app
exec pytest /app/orders_service --rootdir=/app

# exec pytest -v --cov=orders_service
elif [ "$ENV" = "PROD" ]; then
echo "PROD ENVIRONMENT"
# alembic upgrade head
exec uvicorn orders_service.app.main:app \
--host 0.0.0.0 \
--port 8000
exec uvicorn orders_service.app.main:app \
--host 0.0.0.0 \
--port 8000
Expand Down
60 changes: 60 additions & 0 deletions orders_service/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import os

os.environ.setdefault(
"DATABASE_URL",
"postgresql+psycopg://test1:test1@localhost:5432/orders_TEST"
)

import pytest
from pathlib import Path
from alembic import command
from alembic.config import Config
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
from orders_service.tests.factories.order_factory import OrderFactory
from orders_service.app.core.config import settings
from orders_service.app.models.order import Order


@pytest.fixture(scope="session", autouse=True)
def migrate_db():
base_dir = Path(__file__).resolve().parents[1]
alembic_path = base_dir / "alembic.ini"

alembic_cfg = Config(str(alembic_path))
# alembic_cfg = Config("orders_service/alembic.ini")
command.upgrade(alembic_cfg, "head")
print("[TEST] Database migrated")

yield


engine = create_engine(settings.DATABASE_URL, pool_pre_ping=True)
TestingSession = sessionmaker(
autocommit=False,
autoflush=False,
bind=engine,
)


@pytest.fixture(scope="function", autouse=True)
def db():
connection = engine.connect()
transaction = connection.begin()
session = TestingSession(bind=connection)

yield session

session.close()
transaction.rollback()
connection.close()


@pytest.fixture(autouse=True)
def set_session_for_factories(db: Session):
OrderFactory._meta.sqlalchemy_session = db


@pytest.fixture()
def fixture_order(db: Session):
return OrderFactory()
9 changes: 3 additions & 6 deletions orders_service/tests/factories/order_factory.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import random
from uuid import uuid4
import factory
from orders_service.app.models import order

Expand All @@ -8,9 +6,8 @@ class Meta:
model = order.Order
sqlalchemy_session_persistence = "flush"

id = uuid4
name = factory.Faker("name")
product = "item"
count = random.randint(1, 100)
price = print(round(random.uniform(1.00, 1000.0), 2))
product = factory.Sequence(lambda n: 'item %d' % n)
count = factory.Faker("random_int", min=1, max=100)
price = factory.Faker("pyfloat", left_digits=3, right_digits=2, positive=True)

8 changes: 8 additions & 0 deletions orders_service/tests/integration_tests/app_api_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from fastapi import status

def test_root_endpoint(client):
response = client.get("/")
assert response.status_code == status.HTTP_200_OK
data = response.json()
assert "message" in data
assert data["message"] == "orders_service"
26 changes: 0 additions & 26 deletions orders_service/tests/integration_tests/app_test.py

This file was deleted.

85 changes: 39 additions & 46 deletions orders_service/tests/integration_tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,40 @@
import os

os.environ.setdefault(
"DATABASE_URL",
"postgresql+psycopg://test1:test1@localhost:5432/orders_TEST"
)

import pytest
from pathlib import Path
from alembic import command
from alembic.config import Config
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session
# from pathlib import Path
# from alembic import command
# from alembic.config import Config
# from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
from fastapi.testclient import TestClient
from orders_service.app.main import create_app
from ..factories.order_factory import OrderFactory
from orders_service.app.core.config import settings
# from ..factories.order_factory import OrderFactory
# from orders_service.app.core.config import settings
from orders_service.app.dependencies.db import get_db

print("\n[TEST] SQLAlchemy settings.DATABASE_URL =", settings.DATABASE_URL)
# print("[TEST] Alembic sqlalchemy.url =", alembic_cfg.get_main_option("sqlalchemy.url"))
# print("\n[TEST] SQLAlchemy settings.DATABASE_URL =", settings.DATABASE_URL)


#TODO: path change - alembic.ini
@pytest.fixture(scope="session", autouse=True)
def migrate_db():
base_dir = Path(__file__).resolve().parents[2]
alembic_path = base_dir / "alembic.ini"
# #TODO: path change - alembic.ini
# @pytest.fixture(scope="session", autouse=True)
# def migrate_db():
# base_dir = Path(__file__).resolve().parents[2]
# alembic_path = base_dir / "alembic.ini"

alembic_cfg = Config(str(alembic_path))
# alembic_cfg = Config("orders_service/alembic.ini")
command.upgrade(alembic_cfg, "head")
# alembic_cfg = Config(str(alembic_path))
# # alembic_cfg = Config("orders_service/alembic.ini")
# command.upgrade(alembic_cfg, "head")
# print("[TEST] Database migrated")

yield
# yield

print("\n[TEST] SQLAlchemy settings.DATABASE_URL =", settings.DATABASE_URL)
# print("[TEST] Alembic sqlalchemy.url =", alembic_cfg.get_main_option("sqlalchemy.url"))
# print("\n[TEST] SQLAlchemy settings.DATABASE_URL =", settings.DATABASE_URL)

#TODO: put in function?
engine = create_engine(settings.DATABASE_URL)
TestingSession = sessionmaker(
autocommit=False,
autoflush=False,
bind=engine,
)
# #TODO: put in function?
# engine = create_engine(settings.DATABASE_URL)
# TestingSession = sessionmaker(
# autocommit=False,
# autoflush=False,
# bind=engine,
# )


@pytest.fixture
Expand All @@ -56,19 +49,19 @@ def override_get_db():
app.dependency_overrides.clear()


@pytest.fixture(scope="function", autouse=True)
def db():
connection = engine.connect()
transaction = connection.begin()
session = TestingSession(bind=connection)
# @pytest.fixture(scope="function", autouse=True)
# def db():
# connection = engine.connect()
# transaction = connection.begin()
# session = TestingSession(bind=connection)

yield session
# yield session

session.close()
transaction.rollback()
connection.close()
# session.close()
# transaction.rollback()
# connection.close()


@pytest.fixture(autouse=True)
def set_session_for_factories(db: Session):
OrderFactory._meta.sqlalchemy_session = db
# @pytest.fixture(autouse=True)
# def set_session_for_factories(db: Session):
# OrderFactory._meta.sqlalchemy_session = db
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from fastapi import status

def test_healthcheck(client):
"""Test the healthcheck endpoint."""
response = client.get("/health")
assert response.status_code == status.HTTP_200_OK
data = response.json()
Expand All @@ -10,7 +9,6 @@ def test_healthcheck(client):
# assert "timestamp" in data

def test_healthcheck_db(client):
"""Test the healthcheck database endpoint."""
response = client.get("/health/db")
assert response.status_code == status.HTTP_200_OK
data = response.json()
Expand Down
Loading
Loading