style: Apply Black formatting to modified files

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-02-08 08:16:54 +00:00
parent 0a461343e7
commit 78004cd9a4
5 changed files with 280 additions and 285 deletions
+16 -15
View File
@@ -1,6 +1,7 @@
"""
Integration tests for API endpoints.
"""
import pytest
from fastapi.testclient import TestClient
@@ -8,47 +9,47 @@ from fastapi.testclient import TestClient
@pytest.mark.integration
class TestHealthEndpoints:
"""Tests for health check and status endpoints."""
def test_root_endpoint(self, client: TestClient):
"""Test that root endpoint redirects to UI or setup wizard."""
response = client.get("/", follow_redirects=False)
# Accept 200 (OK), 303 (setup wizard redirect), 307/308 (other redirects)
assert response.status_code in [200, 303, 307, 308]
def test_root_redirects_to_setup_wizard_when_setup_required(self, client: TestClient):
"""Test that GET / redirects to setup wizard when setup is required."""
# With test env vars (OPENAI_API_KEY=test-key, AZURE_AI_KEY=test-key),
# is_setup_required() returns True, so we should get a redirect to /setup
response = client.get("/", follow_redirects=False)
# Should return 303 See Other (setup wizard redirect)
assert response.status_code == 303
# Location header should point to setup wizard
assert "Location" in response.headers
assert response.headers["Location"] == "/setup?step=1"
def test_root_returns_200_when_setup_complete(self, client: TestClient):
"""Test that GET /?setup=complete bypasses the setup wizard check."""
# The ?setup=complete query param should bypass the wizard check
response = client.get("/?setup=complete", follow_redirects=False)
# Should return 200 OK (renders the index page)
assert response.status_code == 200
def test_setup_wizard_page_accessible(self, client: TestClient):
"""Test that GET /setup?step=1 returns 200."""
response = client.get("/setup?step=1")
# Setup wizard page should be accessible
assert response.status_code == 200
def test_docs_endpoint(self, client: TestClient):
"""Test that API documentation is accessible."""
response = client.get("/docs")
assert response.status_code == 200
assert "swagger" in response.text.lower() or "openapi" in response.text.lower()
def test_openapi_schema(self, client: TestClient):
"""Test that OpenAPI schema is accessible."""
response = client.get("/openapi.json")
@@ -62,7 +63,7 @@ class TestHealthEndpoints:
@pytest.mark.integration
class TestFileEndpoints:
"""Tests for file management endpoints."""
def test_list_files_empty(self, client: TestClient):
"""Test listing files when database is empty."""
response = client.get("/api/files")
@@ -73,7 +74,7 @@ class TestFileEndpoints:
assert "pagination" in data
assert isinstance(data["files"], list)
assert len(data["files"]) == 0
def test_get_nonexistent_file(self, client: TestClient):
"""Test getting a file that doesn't exist."""
response = client.get("/api/files/99999")
@@ -84,7 +85,7 @@ class TestFileEndpoints:
@pytest.mark.requires_external
class TestProcessingEndpoints:
"""Tests for document processing endpoints."""
def test_process_endpoint_exists(self, client: TestClient):
"""Test that process endpoint is registered."""
# This will return 422 (validation error) without proper data,
@@ -96,7 +97,7 @@ class TestProcessingEndpoints:
@pytest.mark.integration
class TestConfigEndpoints:
"""Tests for configuration endpoints."""
def test_config_status_endpoint(self, client: TestClient):
"""Test configuration status endpoint if it exists."""
# Some apps have a /status or /config/status endpoint
@@ -108,7 +109,7 @@ class TestConfigEndpoints:
@pytest.mark.integration
class TestAuthEndpoints:
"""Tests for authentication endpoints (when auth is disabled in tests)."""
def test_unauthenticated_access_with_auth_disabled(self, client: TestClient):
"""Test that API is accessible when auth is disabled."""
# With AUTH_ENABLED=False, API should be accessible
+4 -12
View File
@@ -35,9 +35,7 @@ class TestSingleFileOperations:
assert f"File record {file_id} deleted successfully" in data["message"]
# Verify file is deleted
file_record = (
db_session.query(FileRecord).filter(FileRecord.id == file_id).first()
)
file_record = db_session.query(FileRecord).filter(FileRecord.id == file_id).first()
assert file_record is None
def test_single_file_delete_nonexistent(self, client: TestClient, db_session):
@@ -79,9 +77,7 @@ class TestBulkOperations:
# Verify files are deleted
for file_id in file_ids:
file_record = (
db_session.query(FileRecord).filter(FileRecord.id == file_id).first()
)
file_record = db_session.query(FileRecord).filter(FileRecord.id == file_id).first()
assert file_record is None
def test_bulk_delete_empty_list(self, client: TestClient, db_session):
@@ -97,9 +93,7 @@ class TestBulkOperations:
assert response.status_code == 404
@patch("app.api.files.process_document")
def test_bulk_reprocess_success(
self, mock_process_document, client: TestClient, db_session
):
def test_bulk_reprocess_success(self, mock_process_document, client: TestClient, db_session):
"""Test bulk reprocessing of files."""
# Setup mock
mock_task = MagicMock()
@@ -132,9 +126,7 @@ class TestBulkOperations:
assert len(data["task_ids"]) == 2
@patch("app.api.files.process_document")
def test_bulk_reprocess_missing_files(
self, mock_process_document, client: TestClient, db_session
):
def test_bulk_reprocess_missing_files(self, mock_process_document, client: TestClient, db_session):
"""Test bulk reprocessing when some local files are missing."""
# Setup mock
mock_task = MagicMock()
+58 -57
View File
@@ -1,6 +1,7 @@
"""
Tests for file detail view improvements including reprocessing and preview endpoints.
"""
import os
import pytest
from unittest.mock import patch, MagicMock
@@ -11,7 +12,7 @@ from app.models import FileRecord, ProcessingLog
@pytest.mark.integration
class TestFileReprocessing:
"""Tests for single file reprocessing endpoint."""
@patch("app.api.files.process_document")
def test_reprocess_existing_file(self, mock_process_document, client: TestClient, db_session, sample_pdf_path):
"""Test reprocessing an existing file."""
@@ -19,30 +20,30 @@ class TestFileReprocessing:
mock_task = MagicMock()
mock_task.id = "test-task-123"
mock_process_document.delay.return_value = mock_task
# Create a file record
file_record = FileRecord(
filehash="abc123",
original_filename="test.pdf",
local_filename=sample_pdf_path,
file_size=1024,
mime_type="application/pdf"
mime_type="application/pdf",
)
db_session.add(file_record)
db_session.commit()
db_session.refresh(file_record)
# Add a failed processing log
log = ProcessingLog(
file_id=file_record.id,
task_id="test-task-123",
step_name="extract_metadata_with_gpt",
status="failure",
message="API error"
message="API error",
)
db_session.add(log)
db_session.commit()
# Test reprocessing
response = client.post(f"/api/files/{file_record.id}/reprocess")
assert response.status_code == 200
@@ -51,13 +52,13 @@ class TestFileReprocessing:
assert "task_id" in data
assert data["file_id"] == file_record.id
assert data["filename"] == "test.pdf"
def test_reprocess_nonexistent_file(self, client: TestClient):
"""Test reprocessing a file that doesn't exist."""
response = client.post("/api/files/99999/reprocess")
assert response.status_code == 404
assert "not found" in response.json()["detail"].lower()
def test_reprocess_file_missing_on_disk(self, client: TestClient, db_session):
"""Test reprocessing when local file is missing."""
# Create a file record with non-existent local path
@@ -66,12 +67,12 @@ class TestFileReprocessing:
original_filename="missing.pdf",
local_filename="/nonexistent/path/missing.pdf",
file_size=1024,
mime_type="application/pdf"
mime_type="application/pdf",
)
db_session.add(file_record)
db_session.commit()
db_session.refresh(file_record)
# Test reprocessing
response = client.post(f"/api/files/{file_record.id}/reprocess")
assert response.status_code == 400
@@ -81,13 +82,13 @@ class TestFileReprocessing:
@pytest.mark.integration
class TestSubtaskRetry:
"""Tests for per-subtask retry endpoint."""
def test_retry_subtask_invalid_file(self, client: TestClient):
"""Test retrying a subtask for nonexistent file."""
response = client.post("/api/files/99999/retry-subtask?subtask_name=upload_to_dropbox")
assert response.status_code == 404
assert "not found" in response.json()["detail"].lower()
def test_retry_subtask_invalid_task_name(self, client: TestClient, db_session, sample_pdf_path):
"""Test retrying with invalid subtask name."""
# Create a file record
@@ -96,17 +97,17 @@ class TestSubtaskRetry:
original_filename="retry.pdf",
local_filename=sample_pdf_path,
file_size=1024,
mime_type="application/pdf"
mime_type="application/pdf",
)
db_session.add(file_record)
db_session.commit()
db_session.refresh(file_record)
# Test with invalid subtask name
response = client.post(f"/api/files/{file_record.id}/retry-subtask?subtask_name=invalid_task")
assert response.status_code == 400
assert "invalid subtask name" in response.json()["detail"].lower()
def test_retry_subtask_missing_processed_file(self, client: TestClient, db_session, sample_pdf_path):
"""Test retrying when processed file is missing."""
# Create a file record
@@ -115,12 +116,12 @@ class TestSubtaskRetry:
original_filename="retry2.pdf",
local_filename=sample_pdf_path,
file_size=1024,
mime_type="application/pdf"
mime_type="application/pdf",
)
db_session.add(file_record)
db_session.commit()
db_session.refresh(file_record)
# Test retry (processed file won't exist)
response = client.post(f"/api/files/{file_record.id}/retry-subtask?subtask_name=upload_to_dropbox")
assert response.status_code == 400
@@ -130,7 +131,7 @@ class TestSubtaskRetry:
@pytest.mark.integration
class TestFilePreview:
"""Tests for file preview endpoint."""
def test_preview_original_file(self, client: TestClient, db_session, sample_pdf_path):
"""Test getting original file preview."""
# Create a file record
@@ -139,17 +140,17 @@ class TestFilePreview:
original_filename="preview.pdf",
local_filename=sample_pdf_path,
file_size=1024,
mime_type="application/pdf"
mime_type="application/pdf",
)
db_session.add(file_record)
db_session.commit()
db_session.refresh(file_record)
# Test preview
response = client.get(f"/api/files/{file_record.id}/preview?version=original")
assert response.status_code == 200
assert response.headers["content-type"].startswith("application/pdf")
def test_preview_processed_file_not_found(self, client: TestClient, db_session, sample_pdf_path):
"""Test getting processed file preview when it doesn't exist."""
# Create a file record
@@ -158,23 +159,23 @@ class TestFilePreview:
original_filename="processed.pdf",
local_filename=sample_pdf_path,
file_size=1024,
mime_type="application/pdf"
mime_type="application/pdf",
)
db_session.add(file_record)
db_session.commit()
db_session.refresh(file_record)
# Test preview (processed version should not exist)
response = client.get(f"/api/files/{file_record.id}/preview?version=processed")
assert response.status_code == 404
assert "not found" in response.json()["detail"].lower()
def test_preview_nonexistent_file(self, client: TestClient):
"""Test preview for a file that doesn't exist."""
response = client.get("/api/files/99999/preview?version=original")
assert response.status_code == 404
assert "not found" in response.json()["detail"].lower()
def test_preview_invalid_version(self, client: TestClient, db_session, sample_pdf_path):
"""Test preview with invalid version parameter."""
# Create a file record
@@ -183,12 +184,12 @@ class TestFilePreview:
original_filename="test.pdf",
local_filename=sample_pdf_path,
file_size=1024,
mime_type="application/pdf"
mime_type="application/pdf",
)
db_session.add(file_record)
db_session.commit()
db_session.refresh(file_record)
# Test with invalid version
response = client.get(f"/api/files/{file_record.id}/preview?version=invalid")
assert response.status_code == 400
@@ -198,7 +199,7 @@ class TestFilePreview:
@pytest.mark.integration
class TestFileDetailView:
"""Tests for enhanced file detail view."""
def test_file_detail_view_with_logs(self, client: TestClient, db_session, sample_pdf_path):
"""Test file detail view returns enhanced data."""
# Create a file record
@@ -207,12 +208,12 @@ class TestFileDetailView:
original_filename="detail.pdf",
local_filename=sample_pdf_path,
file_size=1024,
mime_type="application/pdf"
mime_type="application/pdf",
)
db_session.add(file_record)
db_session.commit()
db_session.refresh(file_record)
# Add processing logs
logs = [
ProcessingLog(
@@ -220,27 +221,27 @@ class TestFileDetailView:
task_id="task-1",
step_name="hash_file",
status="success",
message="File hashed successfully"
message="File hashed successfully",
),
ProcessingLog(
file_id=file_record.id,
task_id="task-1",
step_name="create_file_record",
status="success",
message="File record created"
message="File record created",
),
ProcessingLog(
file_id=file_record.id,
task_id="task-1",
step_name="extract_metadata_with_gpt",
status="failure",
message="API rate limit exceeded"
)
message="API rate limit exceeded",
),
]
for log in logs:
db_session.add(log)
db_session.commit()
# Test detail view
response = client.get(f"/files/{file_record.id}/detail")
assert response.status_code == 200
@@ -248,7 +249,7 @@ class TestFileDetailView:
assert b"File Information" in response.content
assert b"detail.pdf" in response.content
assert b"Processing History" in response.content
def test_file_detail_view_with_upload_branches(self, client: TestClient, db_session, sample_pdf_path):
"""Test file detail view with upload subtask branches."""
# Create a file record
@@ -257,12 +258,12 @@ class TestFileDetailView:
original_filename="branches.pdf",
local_filename=sample_pdf_path,
file_size=1024,
mime_type="application/pdf"
mime_type="application/pdf",
)
db_session.add(file_record)
db_session.commit()
db_session.refresh(file_record)
# Add processing logs including upload branches
logs = [
ProcessingLog(
@@ -270,34 +271,34 @@ class TestFileDetailView:
task_id="task-1",
step_name="send_to_all_destinations",
status="success",
message="Queued uploads"
message="Queued uploads",
),
ProcessingLog(
file_id=file_record.id,
task_id="task-2",
step_name="upload_to_dropbox",
status="success",
message="Uploaded to Dropbox"
message="Uploaded to Dropbox",
),
ProcessingLog(
file_id=file_record.id,
task_id="task-3",
step_name="upload_to_s3",
status="failure",
message="S3 connection error"
message="S3 connection error",
),
ProcessingLog(
file_id=file_record.id,
task_id="task-4",
step_name="upload_to_nextcloud",
status="success",
message="Uploaded to Nextcloud"
)
message="Uploaded to Nextcloud",
),
]
for log in logs:
db_session.add(log)
db_session.commit()
# Test detail view
response = client.get(f"/files/{file_record.id}/detail")
assert response.status_code == 200
@@ -306,7 +307,7 @@ class TestFileDetailView:
assert b"Processing Status Summary" in response.content
# Should have upload branches
assert b"Dropbox" in response.content or b"dropbox" in response.content
def test_file_detail_view_nonexistent(self, client: TestClient):
"""Test file detail view for nonexistent file."""
response = client.get("/files/99999/detail")
@@ -317,11 +318,11 @@ class TestFileDetailView:
@pytest.mark.unit
class TestProcessingFlowComputation:
"""Tests for the _compute_processing_flow function."""
def test_flow_with_upload_branches(self, db_session):
"""Test that upload tasks are properly grouped as branches."""
from app.views.files import _compute_processing_flow
# Create mock logs
class MockLog:
def __init__(self, step_name, status, message, timestamp, task_id):
@@ -330,27 +331,27 @@ class TestProcessingFlowComputation:
self.message = message
self.timestamp = timestamp
self.task_id = task_id
logs = [
MockLog("hash_file", "success", "Hashed", None, "task-1"),
MockLog("send_to_all_destinations", "success", "Queued", None, "task-2"),
MockLog("upload_to_dropbox", "success", "Uploaded", None, "task-3"),
MockLog("upload_to_s3", "failure", "Failed", None, "task-4"),
]
flow = _compute_processing_flow(logs)
# Find the upload stage
upload_stage = None
for stage in flow:
if stage.get("is_branch_parent"):
upload_stage = stage
break
assert upload_stage is not None
assert "branches" in upload_stage
assert len(upload_stage["branches"]) == 2
# Check branch details
branches = {b["key"]: b for b in upload_stage["branches"]}
assert "upload_to_dropbox" in branches
@@ -363,17 +364,17 @@ class TestProcessingFlowComputation:
@pytest.mark.unit
class TestStepSummary:
"""Tests for the _compute_step_summary function."""
def test_summary_with_mixed_statuses(self):
"""Test step summary with various statuses."""
from app.views.files import _compute_step_summary
# Create mock logs
class MockLog:
def __init__(self, step_name, status):
self.step_name = step_name
self.status = status
logs = [
MockLog("hash_file", "success"),
MockLog("create_file_record", "success"),
@@ -382,9 +383,9 @@ class TestStepSummary:
MockLog("upload_to_s3", "failure"),
MockLog("upload_to_nextcloud", "in_progress"),
]
summary = _compute_step_summary(logs)
assert "main" in summary
assert "uploads" in summary
assert summary["total_main_steps"] == 3