Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: github pipeline for running integration test #256

Merged
merged 19 commits into from
Nov 26, 2024
Merged
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
105 changes: 105 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
name: Integration Tests

on:
push:
branches:
- main
pull_request:
branches:
- main

env:
DB_PORT: 5432
DB_NAME: spotnet
DB_USER: postgres
DB_PASSWORD: password
DB_HOST: db
STARKNET_NODE_URL: http://178.32.172.148:6060
REDIS_HOST: redis
REDIS_PORT: 6379
ENV_VERSION: DEV

jobs:
integration-tests:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.x"

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Create .env file
run: |
cat << EOF > .env.dev
ENV_VERSION=DEV
STARKNET_NODE_URL=${{ env.STARKNET_NODE_URL }}
DB_USER=${{ env.DB_USER }}
DB_PASSWORD=${{ env.DB_PASSWORD }}
DB_NAME=${{ env.DB_NAME }}
DB_HOST=${{ env.DB_HOST }}
DB_PORT=${{ env.DB_PORT }}
REDIS_HOST=${{ env.REDIS_HOST }}
REDIS_PORT=${{ env.REDIS_PORT }}
EOF

- name: Build and Start Containers
run: |
docker compose -f docker-compose.dev.yaml up -d --build
echo "Waiting for containers to be ready..."
sleep 30

- name: Install Test Dependencies in Container
run: |
docker exec backend_dev pip install pytest pytest-cov
docker exec backend_dev pip freeze # Debug: show installed packages

- name: Wait for Backend Service
timeout-minutes: 5
run: |
while ! curl -s http://localhost:8000/health > /dev/null; do
echo "Waiting for backend service..."
sleep 10

# Check if the container is still running before logging
if ! docker ps | grep -q backend_dev; then
echo "Backend container is not running!"
docker compose -f docker-compose.dev.yaml logs backend_dev || true
exit 1
fi

# Log the backend service status for debugging purposes.
docker compose -f docker-compose.dev.yaml logs backend_dev || true
done

- name: Apply Migrations
run: |
docker exec backend_dev alembic -c web_app/alembic.ini upgrade head || {
echo "Migration failed. Showing backend logs:"
docker compose -f docker-compose.dev.yaml logs backend_dev || true
exit 1
}

- name: Run Integration Tests with Coverage
run: |
docker exec backend_dev bash -c "cd /app && python -m pytest web_app/test_integration/ -v"


- name: Clean Up
if: always()
run: |
docker compose -f docker-compose.dev.yaml logs > docker-logs.txt || true
docker compose -f docker-compose.dev.yaml down -v

- name: Upload Docker Logs on Failure
if: failure()
uses: actions/upload-artifact@v3
with:
name: docker-logs
path: docker-logs.txt
16 changes: 11 additions & 5 deletions docker-compose.dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ services:
- app_network
depends_on:
- db
environment:
- DB_HOST=db
- DB_PORT=5432
- DB_NAME=spotnet
- DB_USER=postgres
- DB_PASSWORD=password

db:
image: postgres:14
Expand All @@ -31,11 +37,11 @@ services:
POSTGRES_PASSWORD: password
volumes:
- postgres_data_dev:/var/lib/postgresql/data
- ./init-db:/docker-entrypoint-initdb.d # Automatically run initialization scripts
- ./init-db:/docker-entrypoint-initdb.d
networks:
- app_network
ports:
- "5432:5432"
- "${DB_PORT:-5432}:5432" # Use environment variable for port mapping
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
interval: 10s
Expand All @@ -48,13 +54,13 @@ services:
dockerfile: Dockerfile.dev
container_name: frontend_dev
volumes:
- ./frontend:/app # For live code updates during development
- ./frontend:/app
ports:
- "3000:80" # Serve the frontend on localhost:3000
- "3000:80"
networks:
- app_network
depends_on:
- backend

volumes:
postgres_data_dev:
postgres_data_dev:
Empty file added integration_tests/__init__.py
Empty file.
110 changes: 110 additions & 0 deletions integration_tests/test_position_creation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""
Module: Position Creation Tests
This module contains integration tests for the creation and management
of user positions within the webapp
Key Components:
- **PositionDBConnector**: Manages database operations for positions.
- **DepositMixin**: Processes transaction data.
- **DashboardMixin**: Retrieves current token prices.
Test Class:
- **PositionCreationTest**: Validates position workflows:
1. Fetching transaction data.
2. Creating and verifying positions.
3. Updating position statuses.
"""
import asyncio
import pytest
from typing import Dict, Any
from datetime import datetime
from web_app.db.crud import PositionDBConnector, AirDropDBConnector
from web_app.contract_tools.mixins.dashboard import DashboardMixin
from web_app.db.models import Status

position_db = PositionDBConnector()
airdrop = AirDropDBConnector()


class TestPositionCreation:
"""
Integration test for creating and managing positions.
Steps:
1. Fetch transaction data using `DepositMixin.get_transaction_data`.
2. Create a position using `PositionDBConnector`.
3. Verify the created position's attributes.
4. Fetch current token prices using `DashboardMixin`.
5. Update position status and validate changes.
"""

form_data_1: Dict[str, Any] = {
"wallet_id": "0x011F0c180b9EbB2B3F9601c41d65AcA110E48aec0292c778f41Ae286C78Cc374",
"token_symbol": "STRK",
"amount": "2",
"multiplier": 1,
"borrowing_token": "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
}

form_data_2: Dict[str, Any] = {
"wallet_id": "0x011F0c180b9EbB2B3F9601c41d65AcA110E48aec0292c778f41Ae286C78Cc374",
"token_symbol": "ETH",
"amount": "5",
"multiplier": 1,
"borrowing_token": "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
}

form_data_3: Dict[str, Any] = {
"wallet_id": "0x011F0c180b9EbB2B3F9601c41d65AcA110E48aec0292c778f41Ae286C78Cc374",
"token_symbol": "USDC",
"amount": "1",
"multiplier": 1,
"borrowing_token": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
}

@pytest.mark.parametrize("form_data", [form_data_1, form_data_2, form_data_3])
def test_create_position(self, form_data: Dict[str, Any]) -> None:
"""
Args:
form_data (Dict[str, Any]): Position data.
Returns:
None
"""
wallet_id = form_data["wallet_id"]
token_symbol = form_data["token_symbol"]
amount = form_data["amount"]
multiplier = form_data["multiplier"]
borrowing_token = form_data["borrowing_token"]

existing_user = position_db.get_user_by_wallet_id(wallet_id)
if not existing_user:
position_db.create_user(wallet_id)

position = position_db.create_position(
wallet_id=wallet_id,
token_symbol=token_symbol,
amount=amount,
multiplier=multiplier,
)
assert (
position.status == Status.PENDING
), "Position status should be 'pending' upon creation"

current_prices = asyncio.run(DashboardMixin.get_current_prices())
assert (
position.token_symbol in current_prices
), "Token price missing in current prices"
position.start_price = current_prices[position.token_symbol]
position.created_at = datetime.utcnow()

print(
f"Position {position.id} created successfully with status '{position.status}'."
)

position_status = position_db.open_position(position.id, current_prices)
assert (
position_status == Status.OPENED
), "Position status should be 'opened' after updating"
print(f"Position {position.id} successfully opened.")

user = position_db.get_user_by_wallet_id(wallet_id)
airdrop.delete_all_users_airdrop(user.id)
position_db.delete_all_user_positions(user.id)
position_db.delete_user_by_wallet_id(wallet_id)
6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,8 @@ isort = "5.13.2"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
build-backend = "poetry.core.masonry.api"

[tool.pytest.ini_options]
asyncio_mode = "strict"
asyncio_default_fixture_loop_scope = "function"