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
8 changes: 6 additions & 2 deletions src/server/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
""" Main module for the FastAPI application. """

import os
from pathlib import Path

from api_analytics.fastapi import Analytics
from dotenv import load_dotenv
Expand All @@ -24,8 +25,11 @@
# Register the custom exception handler for rate limits
app.add_exception_handler(RateLimitExceeded, rate_limit_exception_handler)

# Mount static files to serve CSS, JS, and other static assets
app.mount("/static", StaticFiles(directory="static"), name="static")

# Mount static files dynamically to serve CSS, JS, and other static assets
static_dir = Path(__file__).parent.parent / "static"
app.mount("/static", StaticFiles(directory=static_dir), name="static")


# Set up API analytics middleware if an API key is provided
if app_analytics_key := os.getenv("API_ANALYTICS_KEY"):
Expand Down
159 changes: 159 additions & 0 deletions tests/test_flow_integration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
"""
Integration tests for GitIngest.
These tests cover core functionalities, edge cases, and concurrency handling.
"""

import shutil
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
from unittest.mock import patch

import pytest
from fastapi.testclient import TestClient

from src.server.main import app

BASE_DIR = Path(__file__).resolve().parent.parent
TEMPLATE_DIR = BASE_DIR / "src" / "templates"


@pytest.fixture(scope="module")
def test_client():
"""Create a test client fixture."""
with TestClient(app) as client_instance:
client_instance.headers.update({"Host": "localhost"})
yield client_instance


@pytest.fixture(scope="module", autouse=True)
def mock_static_files():
"""Mock the static file mount to avoid directory errors."""
with patch("src.server.main.StaticFiles") as mock_static:
mock_static.return_value = None # Mocks the StaticFiles response
yield mock_static


@pytest.fixture(scope="module", autouse=True)
def mock_templates():
"""Mock Jinja2 template rendering to bypass actual file loading."""
with patch("starlette.templating.Jinja2Templates.TemplateResponse") as mock_template:
mock_template.return_value = "Mocked Template Response"
yield mock_template


def cleanup_temp_directories():
temp_dir = Path("/tmp/gitingest")
if temp_dir.exists():
try:
shutil.rmtree(temp_dir)
except PermissionError as e:
print(f"Error cleaning up {temp_dir}: {e}")


@pytest.fixture(scope="module", autouse=True)
def cleanup():
"""Cleanup temporary directories after tests."""
yield
cleanup_temp_directories()


@pytest.mark.asyncio
async def test_remote_repository_analysis(request):
"""Test the complete flow of analyzing a remote repository."""
client = request.getfixturevalue("test_client")
form_data = {
"input_text": "https://github.com/octocat/Hello-World",
"max_file_size": "243",
"pattern_type": "exclude",
"pattern": "",
}

response = client.post("/", data=form_data)
assert response.status_code == 200, f"Form submission failed: {response.text}"
assert "Mocked Template Response" in response.text


@pytest.mark.asyncio
async def test_invalid_repository_url(request):
"""Test handling of an invalid repository URL."""
client = request.getfixturevalue("test_client")
form_data = {
"input_text": "https://github.com/nonexistent/repo",
"max_file_size": "243",
"pattern_type": "exclude",
"pattern": "",
}

response = client.post("/", data=form_data)
assert response.status_code == 200, f"Request failed: {response.text}"
assert "Mocked Template Response" in response.text


@pytest.mark.asyncio
async def test_large_repository(request):
"""Simulate analysis of a large repository with nested folders."""
client = request.getfixturevalue("test_client")
form_data = {
"input_text": "https://github.com/large/repo-with-many-files",
"max_file_size": "243",
"pattern_type": "exclude",
"pattern": "",
}

response = client.post("/", data=form_data)
assert response.status_code == 200, f"Request failed: {response.text}"
assert "Mocked Template Response" in response.text


@pytest.mark.asyncio
async def test_concurrent_requests(request):
"""Test handling of multiple concurrent requests."""
client = request.getfixturevalue("test_client")

def make_request():
form_data = {
"input_text": "https://github.com/octocat/Hello-World",
"max_file_size": "243",
"pattern_type": "exclude",
"pattern": "",
}
response = client.post("/", data=form_data)
assert response.status_code == 200, f"Request failed: {response.text}"
assert "Mocked Template Response" in response.text

with ThreadPoolExecutor(max_workers=5) as executor:
futures = [executor.submit(make_request) for _ in range(5)]
for future in futures:
future.result()


@pytest.mark.asyncio
async def test_large_file_handling(request):
"""Test handling of repositories with large files."""
client = request.getfixturevalue("test_client")
form_data = {
"input_text": "https://github.com/octocat/Hello-World",
"max_file_size": "1",
"pattern_type": "exclude",
"pattern": "",
}

response = client.post("/", data=form_data)
assert response.status_code == 200, f"Request failed: {response.text}"
assert "Mocked Template Response" in response.text


@pytest.mark.asyncio
async def test_repository_with_patterns(request):
"""Test repository analysis with include/exclude patterns."""
client = request.getfixturevalue("test_client")
form_data = {
"input_text": "https://github.com/octocat/Hello-World",
"max_file_size": "243",
"pattern_type": "include",
"pattern": "*.md",
}

response = client.post("/", data=form_data)
assert response.status_code == 200, f"Request failed: {response.text}"
assert "Mocked Template Response" in response.text
Loading