style: apply ruff auto-fix
- Auto-formatted code with ruff format - Applied ruff linting fixes with --fix Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
@@ -842,8 +842,9 @@ class TestDeleteFileExceptions:
|
|||||||
db_session.commit()
|
db_session.commit()
|
||||||
file_id = file.id
|
file_id = file.id
|
||||||
|
|
||||||
with patch("app.config.settings") as mock_settings, patch.object(
|
with (
|
||||||
db_session, "delete", side_effect=Exception("Database error")
|
patch("app.config.settings") as mock_settings,
|
||||||
|
patch.object(db_session, "delete", side_effect=Exception("Database error")),
|
||||||
):
|
):
|
||||||
mock_settings.allow_file_delete = True
|
mock_settings.allow_file_delete = True
|
||||||
response = client.delete(f"/api/files/{file_id}")
|
response = client.delete(f"/api/files/{file_id}")
|
||||||
@@ -869,8 +870,9 @@ class TestDeleteFileExceptions:
|
|||||||
def failing_commit():
|
def failing_commit():
|
||||||
raise Exception("Database commit error")
|
raise Exception("Database commit error")
|
||||||
|
|
||||||
with patch("app.config.settings") as mock_settings, patch.object(
|
with (
|
||||||
db_session, "commit", side_effect=failing_commit
|
patch("app.config.settings") as mock_settings,
|
||||||
|
patch.object(db_session, "commit", side_effect=failing_commit),
|
||||||
):
|
):
|
||||||
mock_settings.allow_file_delete = True
|
mock_settings.allow_file_delete = True
|
||||||
response = client.post("/api/files/bulk-delete", json=[file_id])
|
response = client.post("/api/files/bulk-delete", json=[file_id])
|
||||||
@@ -948,7 +950,9 @@ class TestRetryPipelineSteps:
|
|||||||
db_session.add(file)
|
db_session.add(file)
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
|
|
||||||
with patch("app.tasks.process_with_azure_document_intelligence.process_with_azure_document_intelligence") as mock_task:
|
with patch(
|
||||||
|
"app.tasks.process_with_azure_document_intelligence.process_with_azure_document_intelligence"
|
||||||
|
) as mock_task:
|
||||||
mock_task.delay.return_value = Mock(id="task-azure")
|
mock_task.delay.return_value = Mock(id="task-azure")
|
||||||
result = _retry_pipeline_step(file, "process_with_azure_document_intelligence", db_session)
|
result = _retry_pipeline_step(file, "process_with_azure_document_intelligence", db_session)
|
||||||
assert result["task_id"] == "task-azure"
|
assert result["task_id"] == "task-azure"
|
||||||
@@ -991,8 +995,9 @@ class TestRetryPipelineSteps:
|
|||||||
db_session.add(file)
|
db_session.add(file)
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
|
|
||||||
with patch("app.tasks.extract_metadata_with_gpt.extract_metadata_with_gpt") as mock_task, patch(
|
with (
|
||||||
"app.api.files._extract_text_from_pdf", return_value="Sample text"
|
patch("app.tasks.extract_metadata_with_gpt.extract_metadata_with_gpt") as mock_task,
|
||||||
|
patch("app.api.files._extract_text_from_pdf", return_value="Sample text"),
|
||||||
):
|
):
|
||||||
mock_task.delay.return_value = Mock(id="task-gpt")
|
mock_task.delay.return_value = Mock(id="task-gpt")
|
||||||
result = _retry_pipeline_step(file, "extract_metadata_with_gpt", db_session)
|
result = _retry_pipeline_step(file, "extract_metadata_with_gpt", db_session)
|
||||||
@@ -1035,8 +1040,9 @@ class TestRetryPipelineSteps:
|
|||||||
db_session.add(file)
|
db_session.add(file)
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
|
|
||||||
with patch("app.tasks.extract_metadata_with_gpt.extract_metadata_with_gpt") as mock_task, patch(
|
with (
|
||||||
"app.api.files._extract_text_from_pdf", return_value="Sample text"
|
patch("app.tasks.extract_metadata_with_gpt.extract_metadata_with_gpt") as mock_task,
|
||||||
|
patch("app.api.files._extract_text_from_pdf", return_value="Sample text"),
|
||||||
):
|
):
|
||||||
mock_task.delay.return_value = Mock(id="task-embed")
|
mock_task.delay.return_value = Mock(id="task-embed")
|
||||||
result = _retry_pipeline_step(file, "embed_metadata_into_pdf", db_session)
|
result = _retry_pipeline_step(file, "embed_metadata_into_pdf", db_session)
|
||||||
@@ -1065,9 +1071,10 @@ class TestRetryUploadTasks:
|
|||||||
db_session.add(file)
|
db_session.add(file)
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
|
|
||||||
with patch("app.api.files.settings") as mock_settings, patch(
|
with (
|
||||||
"app.tasks.upload_to_dropbox.upload_to_dropbox"
|
patch("app.api.files.settings") as mock_settings,
|
||||||
) as mock_task:
|
patch("app.tasks.upload_to_dropbox.upload_to_dropbox") as mock_task,
|
||||||
|
):
|
||||||
mock_settings.workdir = str(tmp_path)
|
mock_settings.workdir = str(tmp_path)
|
||||||
mock_task.delay.return_value = Mock(id="task-dropbox")
|
mock_task.delay.return_value = Mock(id="task-dropbox")
|
||||||
response = client.post(f"/api/files/{file.id}/retry-subtask?subtask_name=upload_to_dropbox")
|
response = client.post(f"/api/files/{file.id}/retry-subtask?subtask_name=upload_to_dropbox")
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
"""Tests for app/api/process.py module."""
|
"""Tests for app/api/process.py module."""
|
||||||
|
|
||||||
import os
|
|
||||||
from pathlib import Path
|
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@@ -169,9 +167,7 @@ class TestProcessEndpoints:
|
|||||||
test_file = tmp_path / "test1.pdf"
|
test_file = tmp_path / "test1.pdf"
|
||||||
test_file.write_text("test content")
|
test_file.write_text("test content")
|
||||||
|
|
||||||
with patch("app.api.process.settings") as mock_settings, patch(
|
with patch("app.api.process.settings") as mock_settings, patch("app.api.process.process_document") as mock_task:
|
||||||
"app.api.process.process_document"
|
|
||||||
) as mock_task:
|
|
||||||
mock_settings.workdir = str(tmp_path)
|
mock_settings.workdir = str(tmp_path)
|
||||||
mock_settings.processall_throttle_threshold = 10
|
mock_settings.processall_throttle_threshold = 10
|
||||||
mock_task.delay.return_value = Mock(id="task-1")
|
mock_task.delay.return_value = Mock(id="task-1")
|
||||||
@@ -192,9 +188,7 @@ class TestProcessEndpoints:
|
|||||||
for i in range(3):
|
for i in range(3):
|
||||||
(tmp_path / f"test{i}.pdf").write_text(f"test content {i}")
|
(tmp_path / f"test{i}.pdf").write_text(f"test content {i}")
|
||||||
|
|
||||||
with patch("app.api.process.settings") as mock_settings, patch(
|
with patch("app.api.process.settings") as mock_settings, patch("app.api.process.process_document") as mock_task:
|
||||||
"app.api.process.process_document"
|
|
||||||
) as mock_task:
|
|
||||||
mock_settings.workdir = str(tmp_path)
|
mock_settings.workdir = str(tmp_path)
|
||||||
mock_settings.processall_throttle_threshold = 10
|
mock_settings.processall_throttle_threshold = 10
|
||||||
mock_task.delay.return_value = Mock(id="task-id")
|
mock_task.delay.return_value = Mock(id="task-id")
|
||||||
@@ -214,9 +208,7 @@ class TestProcessEndpoints:
|
|||||||
for i in range(12):
|
for i in range(12):
|
||||||
(tmp_path / f"test{i}.pdf").write_text(f"test content {i}")
|
(tmp_path / f"test{i}.pdf").write_text(f"test content {i}")
|
||||||
|
|
||||||
with patch("app.api.process.settings") as mock_settings, patch(
|
with patch("app.api.process.settings") as mock_settings, patch("app.api.process.process_document") as mock_task:
|
||||||
"app.api.process.process_document"
|
|
||||||
) as mock_task:
|
|
||||||
mock_settings.workdir = str(tmp_path)
|
mock_settings.workdir = str(tmp_path)
|
||||||
mock_settings.processall_throttle_threshold = 10
|
mock_settings.processall_throttle_threshold = 10
|
||||||
mock_settings.processall_throttle_delay = 5
|
mock_settings.processall_throttle_delay = 5
|
||||||
@@ -246,9 +238,7 @@ class TestProcessEndpoints:
|
|||||||
(tmp_path / "test.docx").write_text("word content")
|
(tmp_path / "test.docx").write_text("word content")
|
||||||
(tmp_path / "test.jpg").write_text("image content")
|
(tmp_path / "test.jpg").write_text("image content")
|
||||||
|
|
||||||
with patch("app.api.process.settings") as mock_settings, patch(
|
with patch("app.api.process.settings") as mock_settings, patch("app.api.process.process_document") as mock_task:
|
||||||
"app.api.process.process_document"
|
|
||||||
) as mock_task:
|
|
||||||
mock_settings.workdir = str(tmp_path)
|
mock_settings.workdir = str(tmp_path)
|
||||||
mock_settings.processall_throttle_threshold = 10
|
mock_settings.processall_throttle_threshold = 10
|
||||||
mock_task.delay.return_value = Mock(id="task-id")
|
mock_task.delay.return_value = Mock(id="task-id")
|
||||||
@@ -270,9 +260,7 @@ class TestProcessEndpoints:
|
|||||||
for i in range(threshold):
|
for i in range(threshold):
|
||||||
(tmp_path / f"at_threshold_{i}.pdf").write_text(f"content {i}")
|
(tmp_path / f"at_threshold_{i}.pdf").write_text(f"content {i}")
|
||||||
|
|
||||||
with patch("app.api.process.settings") as mock_settings, patch(
|
with patch("app.api.process.settings") as mock_settings, patch("app.api.process.process_document") as mock_task:
|
||||||
"app.api.process.process_document"
|
|
||||||
) as mock_task:
|
|
||||||
mock_settings.workdir = str(tmp_path)
|
mock_settings.workdir = str(tmp_path)
|
||||||
mock_settings.processall_throttle_threshold = threshold
|
mock_settings.processall_throttle_threshold = threshold
|
||||||
mock_settings.processall_throttle_delay = 2
|
mock_settings.processall_throttle_delay = 2
|
||||||
@@ -291,9 +279,7 @@ class TestProcessEndpoints:
|
|||||||
for i in range(threshold + 1):
|
for i in range(threshold + 1):
|
||||||
(tmp_path / f"above_threshold_{i}.pdf").write_text(f"content {i}")
|
(tmp_path / f"above_threshold_{i}.pdf").write_text(f"content {i}")
|
||||||
|
|
||||||
with patch("app.api.process.settings") as mock_settings, patch(
|
with patch("app.api.process.settings") as mock_settings, patch("app.api.process.process_document") as mock_task:
|
||||||
"app.api.process.process_document"
|
|
||||||
) as mock_task:
|
|
||||||
mock_settings.workdir = str(tmp_path)
|
mock_settings.workdir = str(tmp_path)
|
||||||
mock_settings.processall_throttle_threshold = threshold
|
mock_settings.processall_throttle_threshold = threshold
|
||||||
mock_settings.processall_throttle_delay = 2
|
mock_settings.processall_throttle_delay = 2
|
||||||
|
|||||||
@@ -211,11 +211,11 @@ class TestTaskFailureHandler:
|
|||||||
mock_settings.notify_on_task_failure = True
|
mock_settings.notify_on_task_failure = True
|
||||||
|
|
||||||
# Import to ensure signal is connected
|
# Import to ensure signal is connected
|
||||||
from app.celery_app import task_failure_handler
|
|
||||||
|
|
||||||
# Import the signal
|
# Import the signal
|
||||||
from celery.signals import task_failure
|
from celery.signals import task_failure
|
||||||
|
|
||||||
|
from app.celery_app import task_failure_handler
|
||||||
|
|
||||||
# The handler should be connected to the signal
|
# The handler should be connected to the signal
|
||||||
# We can test this by verifying the signal has receivers
|
# We can test this by verifying the signal has receivers
|
||||||
receivers = task_failure.receivers
|
receivers = task_failure.receivers
|
||||||
|
|||||||
@@ -200,9 +200,10 @@ class TestGetCipherSuite:
|
|||||||
|
|
||||||
def test_get_cipher_suite_import_error(self):
|
def test_get_cipher_suite_import_error(self):
|
||||||
"""Test _get_cipher_suite when cryptography is not installed"""
|
"""Test _get_cipher_suite when cryptography is not installed"""
|
||||||
import app.utils.encryption
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import app.utils.encryption
|
||||||
|
|
||||||
# Reset the cached cipher suite
|
# Reset the cached cipher suite
|
||||||
original_cipher = app.utils.encryption._cipher_suite
|
original_cipher = app.utils.encryption._cipher_suite
|
||||||
app.utils.encryption._cipher_suite = None
|
app.utils.encryption._cipher_suite = None
|
||||||
@@ -218,6 +219,7 @@ class TestGetCipherSuite:
|
|||||||
|
|
||||||
# Mock the import to raise ImportError
|
# Mock the import to raise ImportError
|
||||||
import builtins
|
import builtins
|
||||||
|
|
||||||
real_import = builtins.__import__
|
real_import = builtins.__import__
|
||||||
|
|
||||||
def mock_import(name, *args, **kwargs):
|
def mock_import(name, *args, **kwargs):
|
||||||
@@ -245,7 +247,6 @@ class TestGetCipherSuite:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Mock Fernet class to raise an exception during initialization
|
# Mock Fernet class to raise an exception during initialization
|
||||||
from unittest.mock import MagicMock
|
|
||||||
|
|
||||||
with patch("app.utils.encryption.hashlib.sha256", side_effect=RuntimeError("Hash error")):
|
with patch("app.utils.encryption.hashlib.sha256", side_effect=RuntimeError("Hash error")):
|
||||||
result = app.utils.encryption._get_cipher_suite()
|
result = app.utils.encryption._get_cipher_suite()
|
||||||
|
|||||||
+54
-44
@@ -5,11 +5,11 @@ Tests FastAPI application initialization, middleware, error handlers,
|
|||||||
and lifecycle management.
|
and lifecycle management.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from unittest.mock import Mock, patch, MagicMock
|
|
||||||
import os
|
import os
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from fastapi import HTTPException, status
|
from fastapi import HTTPException
|
||||||
from fastapi.testclient import TestClient
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
@@ -39,20 +39,21 @@ class TestLifespanEvents:
|
|||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_lifespan_context_manager_executes(self):
|
async def test_lifespan_context_manager_executes(self):
|
||||||
"""Test that lifespan context manager can be executed"""
|
"""Test that lifespan context manager can be executed"""
|
||||||
with patch("app.database.init_db"), \
|
with (
|
||||||
patch("app.database.SessionLocal") as mock_session_cls, \
|
patch("app.database.init_db"),
|
||||||
patch("app.utils.config_loader.load_settings_from_db"), \
|
patch("app.database.SessionLocal") as mock_session_cls,
|
||||||
patch("app.utils.config_validator.dump_all_settings"), \
|
patch("app.utils.config_loader.load_settings_from_db"),
|
||||||
patch("app.utils.config_validator.check_all_configs", return_value={"email": [], "storage": {}}), \
|
patch("app.utils.config_validator.dump_all_settings"),
|
||||||
patch("app.utils.notification.init_apprise"), \
|
patch("app.utils.config_validator.check_all_configs", return_value={"email": [], "storage": {}}),
|
||||||
patch("app.utils.notification.notify_startup"), \
|
patch("app.utils.notification.init_apprise"),
|
||||||
patch("app.utils.notification.notify_shutdown"):
|
patch("app.utils.notification.notify_startup"),
|
||||||
|
patch("app.utils.notification.notify_shutdown"),
|
||||||
|
):
|
||||||
# Mock database session
|
# Mock database session
|
||||||
mock_db = MagicMock()
|
mock_db = MagicMock()
|
||||||
mock_session_cls.return_value = mock_db
|
mock_session_cls.return_value = mock_db
|
||||||
|
|
||||||
from app.main import lifespan, app
|
from app.main import app, lifespan
|
||||||
|
|
||||||
# Execute the startup and shutdown
|
# Execute the startup and shutdown
|
||||||
async with lifespan(app):
|
async with lifespan(app):
|
||||||
@@ -64,25 +65,23 @@ class TestLifespanEvents:
|
|||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_lifespan_startup_with_config_issues(self):
|
async def test_lifespan_startup_with_config_issues(self):
|
||||||
"""Test that lifespan logs warning when there are config issues"""
|
"""Test that lifespan logs warning when there are config issues"""
|
||||||
with patch("app.database.init_db"), \
|
with (
|
||||||
patch("app.database.SessionLocal") as mock_session_cls, \
|
patch("app.database.init_db"),
|
||||||
patch("app.utils.config_loader.load_settings_from_db"), \
|
patch("app.database.SessionLocal") as mock_session_cls,
|
||||||
patch("app.utils.config_validator.dump_all_settings"), \
|
patch("app.utils.config_loader.load_settings_from_db"),
|
||||||
patch("app.utils.config_validator.check_all_configs") as mock_check, \
|
patch("app.utils.config_validator.dump_all_settings"),
|
||||||
patch("app.utils.notification.init_apprise"), \
|
patch("app.utils.config_validator.check_all_configs") as mock_check,
|
||||||
patch("app.utils.notification.notify_startup"), \
|
patch("app.utils.notification.init_apprise"),
|
||||||
patch("app.utils.notification.notify_shutdown"), \
|
patch("app.utils.notification.notify_startup"),
|
||||||
patch("logging.warning") as mock_warning:
|
patch("app.utils.notification.notify_shutdown"),
|
||||||
|
patch("logging.warning") as mock_warning,
|
||||||
|
):
|
||||||
mock_db = MagicMock()
|
mock_db = MagicMock()
|
||||||
mock_session_cls.return_value = mock_db
|
mock_session_cls.return_value = mock_db
|
||||||
# Return config with issues
|
# Return config with issues
|
||||||
mock_check.return_value = {
|
mock_check.return_value = {"email": ["Invalid email config"], "storage": {"dropbox": ["Missing token"]}}
|
||||||
"email": ["Invalid email config"],
|
|
||||||
"storage": {"dropbox": ["Missing token"]}
|
|
||||||
}
|
|
||||||
|
|
||||||
from app.main import lifespan, app
|
from app.main import app, lifespan
|
||||||
|
|
||||||
async with lifespan(app):
|
async with lifespan(app):
|
||||||
pass
|
pass
|
||||||
@@ -93,20 +92,21 @@ class TestLifespanEvents:
|
|||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_lifespan_startup_handles_db_settings_load_failure(self):
|
async def test_lifespan_startup_handles_db_settings_load_failure(self):
|
||||||
"""Test that lifespan handles failures when loading settings from DB"""
|
"""Test that lifespan handles failures when loading settings from DB"""
|
||||||
with patch("app.database.init_db"), \
|
with (
|
||||||
patch("app.database.SessionLocal") as mock_session_cls, \
|
patch("app.database.init_db"),
|
||||||
patch("app.utils.config_loader.load_settings_from_db", side_effect=Exception("DB error")), \
|
patch("app.database.SessionLocal") as mock_session_cls,
|
||||||
patch("app.utils.config_validator.dump_all_settings"), \
|
patch("app.utils.config_loader.load_settings_from_db", side_effect=Exception("DB error")),
|
||||||
patch("app.utils.config_validator.check_all_configs", return_value={"email": [], "storage": {}}), \
|
patch("app.utils.config_validator.dump_all_settings"),
|
||||||
patch("app.utils.notification.init_apprise"), \
|
patch("app.utils.config_validator.check_all_configs", return_value={"email": [], "storage": {}}),
|
||||||
patch("app.utils.notification.notify_startup"), \
|
patch("app.utils.notification.init_apprise"),
|
||||||
patch("app.utils.notification.notify_shutdown"), \
|
patch("app.utils.notification.notify_startup"),
|
||||||
patch("logging.error") as mock_error:
|
patch("app.utils.notification.notify_shutdown"),
|
||||||
|
patch("logging.error") as mock_error,
|
||||||
|
):
|
||||||
mock_db = MagicMock()
|
mock_db = MagicMock()
|
||||||
mock_session_cls.return_value = mock_db
|
mock_session_cls.return_value = mock_db
|
||||||
|
|
||||||
from app.main import lifespan, app
|
from app.main import app, lifespan
|
||||||
|
|
||||||
# Should not raise exception, just log error
|
# Should not raise exception, just log error
|
||||||
async with lifespan(app):
|
async with lifespan(app):
|
||||||
@@ -121,9 +121,10 @@ class TestExceptionHandlers:
|
|||||||
|
|
||||||
def test_http_exception_handler_frontend_route_404(self):
|
def test_http_exception_handler_frontend_route_404(self):
|
||||||
"""Test that HTTPException returns HTML for frontend 404 errors"""
|
"""Test that HTTPException returns HTML for frontend 404 errors"""
|
||||||
from app.main import app, http_exception_handler
|
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
|
|
||||||
|
from app.main import http_exception_handler
|
||||||
|
|
||||||
# Create a mock request for a frontend route
|
# Create a mock request for a frontend route
|
||||||
mock_request = MagicMock(spec=Request)
|
mock_request = MagicMock(spec=Request)
|
||||||
mock_request.url.path = "/nonexistent"
|
mock_request.url.path = "/nonexistent"
|
||||||
@@ -132,15 +133,17 @@ class TestExceptionHandlers:
|
|||||||
|
|
||||||
# Call the handler directly
|
# Call the handler directly
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
response = asyncio.run(http_exception_handler(mock_request, exc))
|
response = asyncio.run(http_exception_handler(mock_request, exc))
|
||||||
|
|
||||||
assert response.status_code == 404
|
assert response.status_code == 404
|
||||||
|
|
||||||
def test_http_exception_handler_frontend_route_other_error(self):
|
def test_http_exception_handler_frontend_route_other_error(self):
|
||||||
"""Test that HTTPException returns HTML for other frontend errors"""
|
"""Test that HTTPException returns HTML for other frontend errors"""
|
||||||
from app.main import app, http_exception_handler
|
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
|
|
||||||
|
from app.main import http_exception_handler
|
||||||
|
|
||||||
# Create a mock request for a frontend route
|
# Create a mock request for a frontend route
|
||||||
mock_request = MagicMock(spec=Request)
|
mock_request = MagicMock(spec=Request)
|
||||||
mock_request.url.path = "/some-page"
|
mock_request.url.path = "/some-page"
|
||||||
@@ -149,15 +152,17 @@ class TestExceptionHandlers:
|
|||||||
|
|
||||||
# Call the handler directly
|
# Call the handler directly
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
response = asyncio.run(http_exception_handler(mock_request, exc))
|
response = asyncio.run(http_exception_handler(mock_request, exc))
|
||||||
|
|
||||||
assert response.status_code == 403
|
assert response.status_code == 403
|
||||||
|
|
||||||
def test_custom_500_handler_api_route(self):
|
def test_custom_500_handler_api_route(self):
|
||||||
"""Test that 500 error returns JSON for API routes"""
|
"""Test that 500 error returns JSON for API routes"""
|
||||||
from app.main import app, custom_500_handler
|
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
|
|
||||||
|
from app.main import custom_500_handler
|
||||||
|
|
||||||
# Create a mock request for an API route
|
# Create a mock request for an API route
|
||||||
mock_request = MagicMock(spec=Request)
|
mock_request = MagicMock(spec=Request)
|
||||||
mock_request.url.path = "/api/something"
|
mock_request.url.path = "/api/something"
|
||||||
@@ -166,19 +171,22 @@ class TestExceptionHandlers:
|
|||||||
|
|
||||||
# Call the handler directly
|
# Call the handler directly
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
response = asyncio.run(custom_500_handler(mock_request, exc))
|
response = asyncio.run(custom_500_handler(mock_request, exc))
|
||||||
|
|
||||||
assert response.status_code == 500
|
assert response.status_code == 500
|
||||||
# Parse JSON response
|
# Parse JSON response
|
||||||
import json
|
import json
|
||||||
|
|
||||||
content = json.loads(response.body.decode())
|
content = json.loads(response.body.decode())
|
||||||
assert content["detail"] == "Internal server error"
|
assert content["detail"] == "Internal server error"
|
||||||
|
|
||||||
def test_custom_500_handler_frontend_route(self):
|
def test_custom_500_handler_frontend_route(self):
|
||||||
"""Test that 500 error returns HTML for frontend routes"""
|
"""Test that 500 error returns HTML for frontend routes"""
|
||||||
from app.main import app, custom_500_handler
|
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
|
|
||||||
|
from app.main import custom_500_handler
|
||||||
|
|
||||||
# Create a mock request for a frontend route
|
# Create a mock request for a frontend route
|
||||||
mock_request = MagicMock(spec=Request)
|
mock_request = MagicMock(spec=Request)
|
||||||
mock_request.url.path = "/dashboard"
|
mock_request.url.path = "/dashboard"
|
||||||
@@ -187,6 +195,7 @@ class TestExceptionHandlers:
|
|||||||
|
|
||||||
# Call the handler directly
|
# Call the handler directly
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
response = asyncio.run(custom_500_handler(mock_request, exc))
|
response = asyncio.run(custom_500_handler(mock_request, exc))
|
||||||
|
|
||||||
assert response.status_code == 500
|
assert response.status_code == 500
|
||||||
@@ -211,9 +220,10 @@ class TestStaticFileMount:
|
|||||||
|
|
||||||
def test_static_files_mounted_when_directory_exists(self):
|
def test_static_files_mounted_when_directory_exists(self):
|
||||||
"""Test that static files are served when directory exists"""
|
"""Test that static files are served when directory exists"""
|
||||||
from app.main import app
|
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
||||||
|
from app.main import app
|
||||||
|
|
||||||
# Check if static directory exists
|
# Check if static directory exists
|
||||||
static_dir = pathlib.Path(__file__).parents[1] / "frontend" / "static"
|
static_dir = pathlib.Path(__file__).parents[1] / "frontend" / "static"
|
||||||
|
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ class TestAttachLogo:
|
|||||||
@patch("builtins.open", new_callable=mock_open, read_data=b"fake_svg_data")
|
@patch("builtins.open", new_callable=mock_open, read_data=b"fake_svg_data")
|
||||||
def test_attaches_svg_logo_with_correct_mime_type(self, mock_file, mock_exists):
|
def test_attaches_svg_logo_with_correct_mime_type(self, mock_file, mock_exists):
|
||||||
"""Test attaches SVG logo with correct MIME type (image/svg+xml)."""
|
"""Test attaches SVG logo with correct MIME type (image/svg+xml)."""
|
||||||
|
|
||||||
# Create a custom side effect that returns True only for SVG path
|
# Create a custom side effect that returns True only for SVG path
|
||||||
def custom_exists(path):
|
def custom_exists(path):
|
||||||
return "logo.svg" in path
|
return "logo.svg" in path
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
"""Tests for app/views/google_drive.py module."""
|
"""Tests for app/views/google_drive.py module."""
|
||||||
|
|
||||||
import pytest
|
|
||||||
from unittest.mock import patch
|
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.integration
|
@pytest.mark.integration
|
||||||
@@ -39,8 +40,7 @@ class TestGoogleDriveViews:
|
|||||||
client_id = "test_client_id_123"
|
client_id = "test_client_id_123"
|
||||||
redirect_uri = "https://example.com/callback"
|
redirect_uri = "https://example.com/callback"
|
||||||
response = client.get(
|
response = client.get(
|
||||||
f"/google-drive-auth-start?client_id={client_id}&redirect_uri={redirect_uri}",
|
f"/google-drive-auth-start?client_id={client_id}&redirect_uri={redirect_uri}", follow_redirects=False
|
||||||
follow_redirects=False
|
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response.status_code in [302, 307] # Redirect status codes
|
assert response.status_code in [302, 307] # Redirect status codes
|
||||||
@@ -60,10 +60,7 @@ class TestGoogleDriveViews:
|
|||||||
def test_google_drive_auth_start_without_redirect_uri(self, client):
|
def test_google_drive_auth_start_without_redirect_uri(self, client):
|
||||||
"""Test starting Google Drive OAuth flow without explicit redirect_uri."""
|
"""Test starting Google Drive OAuth flow without explicit redirect_uri."""
|
||||||
client_id = "test_client_id_456"
|
client_id = "test_client_id_456"
|
||||||
response = client.get(
|
response = client.get(f"/google-drive-auth-start?client_id={client_id}", follow_redirects=False)
|
||||||
f"/google-drive-auth-start?client_id={client_id}",
|
|
||||||
follow_redirects=False
|
|
||||||
)
|
|
||||||
|
|
||||||
assert response.status_code in [302, 307] # Redirect status codes
|
assert response.status_code in [302, 307] # Redirect status codes
|
||||||
|
|
||||||
@@ -78,10 +75,7 @@ class TestGoogleDriveViews:
|
|||||||
def test_google_drive_auth_start_scope_configuration(self, client):
|
def test_google_drive_auth_start_scope_configuration(self, client):
|
||||||
"""Test that Google Drive auth start uses correct OAuth scope."""
|
"""Test that Google Drive auth start uses correct OAuth scope."""
|
||||||
client_id = "test_client_id_789"
|
client_id = "test_client_id_789"
|
||||||
response = client.get(
|
response = client.get(f"/google-drive-auth-start?client_id={client_id}", follow_redirects=False)
|
||||||
f"/google-drive-auth-start?client_id={client_id}",
|
|
||||||
follow_redirects=False
|
|
||||||
)
|
|
||||||
|
|
||||||
location = response.headers.get("location")
|
location = response.headers.get("location")
|
||||||
assert location is not None
|
assert location is not None
|
||||||
|
|||||||
Reference in New Issue
Block a user