Skip to content
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
2 changes: 1 addition & 1 deletion .env.docker.example
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ OZ_ACCOUNT_PRIVATE_KEY=sk-test-123

# --- Frontend/App Config ---
NEXT_PUBLIC_APP_URL=http://localhost:3000
TELEGRAM_APP_URL=sk-test-123
TELEGRAM_APP_URL=sk-test-123
15 changes: 15 additions & 0 deletions Dockerfile.py-be-test
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM python:3.12-slim

WORKDIR /app/py-be

COPY py-be/pyproject.toml py-be/poetry.lock ./

RUN pip install poetry

RUN poetry install --no-root

COPY py-be/ ./

RUN chmod +x run_tests.sh

ENTRYPOINT ["./run_tests.sh"]
8 changes: 7 additions & 1 deletion anon/backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
FROM rust:1.86-slim AS builder
WORKDIR /app

# Install curl in the builder stage
RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/*

# Disable SQLx compile-time checks
ENV SQLX_OFFLINE=true

# Cache dependencies
COPY Cargo.toml ./
# Create a dummy main to cache deps
Expand All @@ -18,7 +24,7 @@ WORKDIR /app

# Minimal runtime deps
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates wget \
&& apt-get install -y --no-install-recommends ca-certificates wget curl \
&& rm -rf /var/lib/apt/lists/*

COPY --from=builder /app/target/release/backend /usr/local/bin/app
Expand Down
2 changes: 1 addition & 1 deletion anon/backend/src/routes/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub async fn generate_contract(
// For now, we'll create a placeholder implementation

// Validate user exists
let user = sqlx::query!("SELECT id FROM users WHERE id = $1", req.user_id)
let user = sqlx::query!("SELECT id FROM users WHERE id = $1", req.user_id as i64)
.fetch_optional(&pool)
.await
.map_err(|e| crate::libs::error::map_sqlx_error(&e))?;
Expand Down
2 changes: 1 addition & 1 deletion anon/backend/src/routes/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub async fn me(
});

Ok(Json(UserMeRes {
id: rec.id,
id: rec.id as i64,
wallet: rec.wallet,
created_at: rec.created_at,
profile,
Expand Down
6 changes: 2 additions & 4 deletions anon/backend/tests/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# Integration Tests

This directory contains integration tests for the backend API endpoints.
This directory contains integration tests for the backend API endpoints

## Test Structure

- `generate_contract_test.rs` - Tests for the POST /generate endpoint
- `test_config.rs` - Test configuration and database setup utilities
- `mod.rs` - Test module organization
- `common/mod.rs` - Shared test utilities and configuration

## Setup

Expand Down Expand Up @@ -104,7 +103,6 @@ The integration tests cover:

- `create_test_server()` - Creates a test server with database connection
- `create_test_user()` - Creates a test user for testing
- `cleanup_test_data()` - Cleans up test data after each test

## Notes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,3 @@ impl TestConfig {
Ok(pool)
}
}

pub async fn setup_test_database() -> Result<PgPool, Box<dyn std::error::Error>> {
let config = TestConfig::from_env();
let pool = config.create_pool().await?;
Ok(pool)
}

pub async fn cleanup_test_database(pool: &PgPool) -> Result<(), sqlx::Error> {
// Clean up test data with cascade to handle foreign key constraints
sqlx::query!(
r#"
TRUNCATE TABLE
generated_contracts,
profiles,
users
RESTART IDENTITY CASCADE
"#
)
.execute(pool)
.await?;
Ok(())
}
3 changes: 2 additions & 1 deletion anon/backend/tests/health_test.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::test_config::TestConfig;
mod common;
use axum::http::StatusCode;
use axum_test::TestServer;
use backend::libs::db::AppState;
use backend::routes::health::{db_health, health};
use common::TestConfig;
use sqlx::PgPool;

async fn create_test_app(pool: PgPool) -> axum::Router {
Expand Down
3 changes: 0 additions & 3 deletions anon/backend/tests/mod.rs

This file was deleted.

17 changes: 15 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ services:
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
POSTGRES_DB: main_db
ports:
- "5432:5432"
volumes:
Expand Down Expand Up @@ -75,6 +75,8 @@ services:
environment:
- RUST_LOG=info
- PORT=8080
- DATABASE_URL=postgresql://postgres:postgres@db:5432/starkfinder_rust_test
- TEST_DATABASE_URL=postgresql://postgres:postgres@db:5432/starkfinder_rust_test
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health"]
Expand All @@ -83,6 +85,17 @@ services:
retries: 3
start_period: 10s

py-be-test:
build:
context: .
dockerfile: Dockerfile.py-be-test
environment:
- DATABASE_URL=postgresql://postgres:postgres@db:5432/starkfinder_py_test
- TEST_DATABASE_URL=postgresql://postgres:postgres@db:5432/starkfinder_py_test
depends_on:
db:
condition: service_healthy

volumes:
db_data:
redis_data:
redis_data:
30 changes: 29 additions & 1 deletion py-be/app/api/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from datetime import datetime

from fastapi import Depends, FastAPI, HTTPException, status
from fastapi import Depends, FastAPI, Header, HTTPException, status
from pydantic import BaseModel, ConfigDict, Field, constr, field_validator
from sqlalchemy import or_
from sqlalchemy.orm import Session
Expand All @@ -16,6 +16,18 @@
app = FastAPI()


# Placeholder for authentication - In a real application, this would involve
# proper token validation (e.g., JWT, OAuth2) and user retrieval.
# This is added solely to enable testing of unauthorized access.
async def verify_token(
x_token: str = Header(
None
), # Changed to Header(None) to make it optional for FastAPI's validation
):
if x_token is None or x_token != "fake-super-secret-token":
raise HTTPException(status_code=401, detail="Unauthorized")


class UserCreate(BaseModel):
"""Schema for incoming user registration data."""

Expand Down Expand Up @@ -164,6 +176,22 @@ def generate_contract(
return contract


@app.get("/generated_contracts", response_model=list[GeneratedContractRead])
def get_generated_contracts(
user_id: int | None = None,
skip: int = 0,
limit: int = 100,
db: Session = Depends(get_db),
token: str = Depends(verify_token), # Added authentication dependency
) -> list[GeneratedContract]:
"""Retrieve a list of generated contracts, with optional filtering by user_id and pagination."""
query = db.query(GeneratedContract)
if user_id:
query = query.filter(GeneratedContract.user_id == user_id)
contracts = query.offset(skip).limit(limit).all()
return contracts


@app.get(
"/deployed_contracts",
response_model=list[DeployedContractRead],
Expand Down
4 changes: 4 additions & 0 deletions py-be/app/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .generated_contract import GeneratedContract
from .user import User

# add future models here
10 changes: 6 additions & 4 deletions py-be/app/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@

import os

from dotenv import load_dotenv
from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base, sessionmaker

DATABASE_URL = os.environ.get(
"DATABASE_URL", "postgresql://postgres:Soham2003@localhost:5432/starkfinder_test"
)
load_dotenv()

engine = create_engine(DATABASE_URL)
DATABASE_URL = os.getenv("DATABASE_URL")
if not DATABASE_URL:
raise ValueError("DATABASE_URL environment variable is not set.")

engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()
Expand Down
3 changes: 3 additions & 0 deletions py-be/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ dependencies = [
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.poetry]
packages = [{include = "app"}]

[tool.poetry.group.dev.dependencies]
black = "^25.1.0"
isort = "^6.0.1"
Expand Down
33 changes: 33 additions & 0 deletions py-be/run_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/bash

# Integration Test Runner for StarkFinder Python Backend
# This script sets up the test environment and runs the integration tests

set -e

echo "πŸš€ Starting StarkFinder Python Backend Integration Tests"

# Check if we're in the right directory
if [ ! -f "pyproject.toml" ]; then
echo "❌ Error: Please run this script from the py-be directory"
exit 1
fi

# Set default test database URL if not provided
if [ -z "$TEST_DATABASE_URL" ]; then
export TEST_DATABASE_URL="postgresql://postgres:postgres@localhost:5432/starkfinder_test"
echo "πŸ“ Using default test database URL: $TEST_DATABASE_URL"
fi

# Check if PostgreSQL is running
echo "πŸ” Checking PostgreSQL connection..."

# Run tests
echo "πŸ§ͺ Running integration tests..."
# pytest will automatically use conftest.py to set up the database
poetry run pytest tests/ || {
echo "❌ Error: Pytest failed"
exit 1
}

echo "βœ… Tests completed successfully!"
45 changes: 30 additions & 15 deletions py-be/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,49 @@
import os
import time

import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy_utils import create_database, database_exists, drop_database

# βœ… Import all models so they register with Base
import app.models
from app.models.base import Base
from app.services.base import get_db

TEST_DATABASE_URL = os.getenv(
"TEST_DATABASE_URL",
"sqlite:///./test.db",
)
os.environ["DATABASE_URL"] = TEST_DATABASE_URL

TEST_DATABASE_URL = os.getenv("TEST_DATABASE_URL")
if not TEST_DATABASE_URL:
raise ValueError("TEST_DATABASE_URL environment variable is not set.")

engine = create_engine(TEST_DATABASE_URL)
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)


@pytest.fixture(scope="session", autouse=True)
def setup_test_database():
def setup_db():
"""Create a fresh test database before tests and drop it after."""
if not database_exists(TEST_DATABASE_URL):
create_database(TEST_DATABASE_URL)
print(f"Test database URL: {engine.url}")
print(f"Test database name: {engine.url.database}")
if database_exists(TEST_DATABASE_URL):
drop_database(TEST_DATABASE_URL)
create_database(TEST_DATABASE_URL)

print(f"Tables before create_all: {Base.metadata.tables.keys()}") # Debug print

# ensure all tables are created
Base.metadata.create_all(bind=engine)

print(f"Tables after create_all: {Base.metadata.tables.keys()}") # Debug print

yield

drop_database(TEST_DATABASE_URL)
Base.metadata.drop_all(bind=engine)
drop_database(TEST_DATABASE_URL)
if TEST_DATABASE_URL.startswith("sqlite"):
try:
os.remove("test.db")
Expand All @@ -40,22 +53,24 @@ def setup_test_database():

@pytest.fixture()
def db_session():
"""Provide a SQLAlchemy session for tests."""
"""Provide a test client that uses the test database session."""
session = TestingSessionLocal()
try:
yield session
finally:
session.close()


@pytest.fixture(autouse=True)
def override_get_db(monkeypatch, db_session):
"""Override the get_db dependency in FastAPI with test session."""
@pytest.fixture(name="client")
def client_fixture(db_session):
"""Provide a test client that uses the test database session."""
from fastapi.testclient import TestClient

def _get_db_override():
try:
yield db_session
finally:
pass
from app.api.routes import app
from app.services.base import get_db

monkeypatch.setattr("app.services.base.get_db", _get_db_override)
app.dependency_overrides[get_db] = lambda: db_session
with TestClient(app) as client:
yield client
app.dependency_overrides.clear()
app.dependency_overrides.clear()
2 changes: 1 addition & 1 deletion py-be/tests/test_deployed_contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from fastapi.testclient import TestClient

from app.api import routes
from app.models.deployed_contract import DeployedContract
from app.models.deployed_contracts import DeployedContract

client = TestClient(routes.app)

Expand Down
Loading
Loading