fix(tests): restore correct route URLs and fix auth/exception handling broken by d221753

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
Agent-Logs-Url: https://github.com/christianlouis/DocuElevate/sessions/df99f308-d964-4732-88b7-a01be6aeee05
This commit is contained in:
copilot-swe-agent[bot]
2026-03-24 20:22:18 +00:00
parent cafc0e4523
commit 48331f6e91
8 changed files with 55 additions and 36 deletions
+12 -10
View File
@@ -414,9 +414,11 @@ async def save_google_drive_settings(
if folder_id: if folder_id:
drive_settings["GOOGLE_DRIVE_FOLDER_ID"] = folder_id drive_settings["GOOGLE_DRIVE_FOLDER_ID"] = folder_id
# Try to update the .env file, but don't fail if it doesn't exist (for Docker containers) # Best-effort .env file write — failures here are non-fatal
if os.path.exists(env_path): env_file_exists = False
try: try:
env_file_exists = os.path.exists(env_path)
if env_file_exists:
logger.info(f"Updating Google Drive settings in {env_path}") logger.info(f"Updating Google Drive settings in {env_path}")
# Read the current .env file # Read the current .env file
@@ -449,12 +451,12 @@ async def save_google_drive_settings(
f.write("\n".join(new_env_lines) + "\n") f.write("\n".join(new_env_lines) + "\n")
logger.info("Successfully updated Google Drive settings in .env file") logger.info("Successfully updated Google Drive settings in .env file")
except Exception as e: else:
logger.warning(f"Failed to update .env file: {str(e)}, but will continue with in-memory update") logger.warning(
else: f".env file not found at {env_path}, skipping file update but continuing with in-memory update"
logger.warning( )
f".env file not found at {env_path}, skipping file update but continuing with in-memory update" except Exception as env_err:
) logger.warning(f"Failed to write .env file (non-fatal): {env_err}")
# Update the settings in memory (this always happens) # Update the settings in memory (this always happens)
if refresh_token: if refresh_token:
@@ -492,7 +494,7 @@ async def save_google_drive_settings(
return { return {
"status": "success", "status": "success",
"message": "Google Drive settings have been saved", "message": "Google Drive settings have been saved",
"in_memory_only": not os.path.exists(env_path), "in_memory_only": not env_file_exists,
} }
except Exception as e: except Exception as e:
+3 -4
View File
@@ -490,12 +490,11 @@ class TestSaveGoogleDriveSettings:
assert response.status_code == 200 assert response.status_code == 200
@patch("os.path.exists") @patch("app.api.google_drive.os")
@patch("os.path.dirname")
@patch("app.config.settings") @patch("app.config.settings")
def test_save_settings_exception_handling(self, mock_settings, mock_dirname, mock_exists, client: TestClient): def test_save_settings_exception_handling(self, mock_settings, mock_os, client: TestClient):
"""Test that exceptions in .env write are non-fatal — DB write still succeeds.""" """Test that exceptions in .env write are non-fatal — DB write still succeeds."""
mock_exists.side_effect = Exception("Unexpected error") mock_os.path.exists.side_effect = Exception("Unexpected error")
response = client.post("/api/google-drive/save-settings", data={"refresh_token": "token", "use_oauth": "true"}) response = client.post("/api/google-drive/save-settings", data={"refresh_token": "token", "use_oauth": "true"})
+9
View File
@@ -342,6 +342,15 @@ class TestFormatTimeRemaining:
class TestSaveOneDriveSettings: class TestSaveOneDriveSettings:
"""Tests for POST /onedrive/save-settings endpoint.""" """Tests for POST /onedrive/save-settings endpoint."""
@pytest.fixture(autouse=True)
def _admin_override(self):
from app.api.onedrive import _require_admin
from app.main import app as fastapi_app
fastapi_app.dependency_overrides[_require_admin] = lambda: {"is_admin": True}
yield
fastapi_app.dependency_overrides.pop(_require_admin, None)
@patch("builtins.open", new_callable=mock_open, read_data="# Existing config\n") @patch("builtins.open", new_callable=mock_open, read_data="# Existing config\n")
@patch("os.path.exists") @patch("os.path.exists")
@patch("os.path.dirname") @patch("os.path.dirname")
+9
View File
@@ -294,6 +294,15 @@ class TestTokenRotationEnvAppendLine:
class TestSaveSettingsException: class TestSaveSettingsException:
"""Cover lines 324-326: save_onedrive_settings outer exception handler.""" """Cover lines 324-326: save_onedrive_settings outer exception handler."""
@pytest.fixture(autouse=True)
def _admin_override(self):
from app.api.onedrive import _require_admin
from app.main import app as fastapi_app
fastapi_app.dependency_overrides[_require_admin] = lambda: {"is_admin": True}
yield
fastapi_app.dependency_overrides.pop(_require_admin, None)
def test_save_settings_outer_exception(self, client: TestClient): def test_save_settings_outer_exception(self, client: TestClient):
"""Trigger the outer exception handler in save_onedrive_settings.""" """Trigger the outer exception handler in save_onedrive_settings."""
with patch("app.api.onedrive.notify_settings_updated", side_effect=Exception("Unexpected boom")): with patch("app.api.onedrive.notify_settings_updated", side_effect=Exception("Unexpected boom")):
+16 -16
View File
@@ -57,7 +57,7 @@ class TestFileViewPdfJs:
pdf.write_bytes(b"%PDF-1.4 test") pdf.write_bytes(b"%PDF-1.4 test")
rec = _create_file_record(db_session, file_path=str(pdf), mime_type="application/pdf") rec = _create_file_record(db_session, file_path=str(pdf), mime_type="application/pdf")
response = client.get(f"/files/{rec.id}") response = client.get(f"/files/{rec.id}/detail")
assert response.status_code == 200 assert response.status_code == 200
html = response.text html = response.text
@@ -80,7 +80,7 @@ class TestFileViewPdfJs:
pdf.write_bytes(b"%PDF-1.4 test") pdf.write_bytes(b"%PDF-1.4 test")
rec = _create_file_record(db_session, file_path=str(pdf), mime_type="application/pdf") rec = _create_file_record(db_session, file_path=str(pdf), mime_type="application/pdf")
response = client.get(f"/files/{rec.id}") response = client.get(f"/files/{rec.id}/detail")
html = response.text html = response.text
# The preview section should use pdf-viewer, not iframe # The preview section should use pdf-viewer, not iframe
@@ -93,7 +93,7 @@ class TestFileViewPdfJs:
pdf.write_bytes(b"%PDF-1.4 test") pdf.write_bytes(b"%PDF-1.4 test")
rec = _create_file_record(db_session, file_path=str(pdf), mime_type="application/pdf") rec = _create_file_record(db_session, file_path=str(pdf), mime_type="application/pdf")
response = client.get(f"/files/{rec.id}") response = client.get(f"/files/{rec.id}/detail")
html = response.text html = response.text
assert 'id="pdf-prev-btn"' in html assert 'id="pdf-prev-btn"' in html
@@ -116,7 +116,7 @@ class TestFileViewImagePreview:
img.write_bytes(b"\xff\xd8\xff\xe0" + b"\x00" * 100) # minimal JPEG header img.write_bytes(b"\xff\xd8\xff\xe0" + b"\x00" * 100) # minimal JPEG header
rec = _create_file_record(db_session, filename="photo.jpg", mime_type="image/jpeg", file_path=str(img)) rec = _create_file_record(db_session, filename="photo.jpg", mime_type="image/jpeg", file_path=str(img))
response = client.get(f"/files/{rec.id}") response = client.get(f"/files/{rec.id}/detail")
assert response.status_code == 200 assert response.status_code == 200
html = response.text html = response.text
@@ -132,7 +132,7 @@ class TestFileViewImagePreview:
img.write_bytes(b"\x89PNG\r\n\x1a\n" + b"\x00" * 50) img.write_bytes(b"\x89PNG\r\n\x1a\n" + b"\x00" * 50)
rec = _create_file_record(db_session, filename="photo.png", mime_type="image/png", file_path=str(img)) rec = _create_file_record(db_session, filename="photo.png", mime_type="image/png", file_path=str(img))
response = client.get(f"/files/{rec.id}") response = client.get(f"/files/{rec.id}/detail")
html = response.text html = response.text
assert 'aria-label="Zoom in"' in html assert 'aria-label="Zoom in"' in html
@@ -146,7 +146,7 @@ class TestFileViewImagePreview:
img.write_bytes(b"RIFF" + b"\x00" * 50) img.write_bytes(b"RIFF" + b"\x00" * 50)
rec = _create_file_record(db_session, filename="wide.webp", mime_type="image/webp", file_path=str(img)) rec = _create_file_record(db_session, filename="wide.webp", mime_type="image/webp", file_path=str(img))
response = client.get(f"/files/{rec.id}") response = client.get(f"/files/{rec.id}/detail")
html = response.text html = response.text
# Pan support is implemented via JavaScript on img-wrap # Pan support is implemented via JavaScript on img-wrap
@@ -170,7 +170,7 @@ class TestFileViewTextPreview:
txt.write_text("Hello world\nSecond line\n") txt.write_text("Hello world\nSecond line\n")
rec = _create_file_record(db_session, filename="readme.txt", mime_type="text/plain", file_path=str(txt)) rec = _create_file_record(db_session, filename="readme.txt", mime_type="text/plain", file_path=str(txt))
response = client.get(f"/files/{rec.id}") response = client.get(f"/files/{rec.id}/detail")
assert response.status_code == 200 assert response.status_code == 200
html = response.text html = response.text
@@ -184,7 +184,7 @@ class TestFileViewTextPreview:
txt.write_text("print('hello')\n") txt.write_text("print('hello')\n")
rec = _create_file_record(db_session, filename="code.py", mime_type="text/x-python", file_path=str(txt)) rec = _create_file_record(db_session, filename="code.py", mime_type="text/x-python", file_path=str(txt))
response = client.get(f"/files/{rec.id}") response = client.get(f"/files/{rec.id}/detail")
html = response.text html = response.text
assert "copyTextPreview" in html assert "copyTextPreview" in html
@@ -196,7 +196,7 @@ class TestFileViewTextPreview:
txt.write_text("a,b,c\n1,2,3\n") txt.write_text("a,b,c\n1,2,3\n")
rec = _create_file_record(db_session, filename="data.csv", mime_type="text/csv", file_path=str(txt)) rec = _create_file_record(db_session, filename="data.csv", mime_type="text/csv", file_path=str(txt))
response = client.get(f"/files/{rec.id}") response = client.get(f"/files/{rec.id}/detail")
html = response.text html = response.text
# JS builds line-number spans # JS builds line-number spans
@@ -218,7 +218,7 @@ class TestFileViewPreviewIcon:
pdf.write_bytes(b"%PDF-1.4") pdf.write_bytes(b"%PDF-1.4")
rec = _create_file_record(db_session, file_path=str(pdf), mime_type="application/pdf") rec = _create_file_record(db_session, file_path=str(pdf), mime_type="application/pdf")
html = client.get(f"/files/{rec.id}").text html = client.get(f"/files/{rec.id}/detail").text
assert "fa-file-pdf" in html assert "fa-file-pdf" in html
def test_image_icon(self, client: TestClient, db_session, tmp_path): def test_image_icon(self, client: TestClient, db_session, tmp_path):
@@ -227,7 +227,7 @@ class TestFileViewPreviewIcon:
img.write_bytes(b"\xff\xd8\xff\xe0" + b"\x00" * 10) img.write_bytes(b"\xff\xd8\xff\xe0" + b"\x00" * 10)
rec = _create_file_record(db_session, filename="p.jpg", mime_type="image/jpeg", file_path=str(img)) rec = _create_file_record(db_session, filename="p.jpg", mime_type="image/jpeg", file_path=str(img))
html = client.get(f"/files/{rec.id}").text html = client.get(f"/files/{rec.id}/detail").text
assert "fa-image" in html assert "fa-image" in html
def test_text_icon(self, client: TestClient, db_session, tmp_path): def test_text_icon(self, client: TestClient, db_session, tmp_path):
@@ -236,7 +236,7 @@ class TestFileViewPreviewIcon:
txt.write_text("hello") txt.write_text("hello")
rec = _create_file_record(db_session, filename="t.txt", mime_type="text/plain", file_path=str(txt)) rec = _create_file_record(db_session, filename="t.txt", mime_type="text/plain", file_path=str(txt))
html = client.get(f"/files/{rec.id}").text html = client.get(f"/files/{rec.id}/detail").text
assert "fa-file-code" in html assert "fa-file-code" in html
@@ -321,7 +321,7 @@ class TestFileDetailBottomPreview:
pdf.write_bytes(b"%PDF-1.4") pdf.write_bytes(b"%PDF-1.4")
rec = _create_file_record(db_session, file_path=str(pdf), processed_path=str(pdf)) rec = _create_file_record(db_session, file_path=str(pdf), processed_path=str(pdf))
response = client.get(f"/files/{rec.id}/detail") response = client.get(f"/files/{rec.id}/process")
assert response.status_code == 200 assert response.status_code == 200
html = response.text html = response.text
@@ -372,7 +372,7 @@ class TestFileViewOcrText:
rec.ocr_text = "Sample extracted OCR text content" rec.ocr_text = "Sample extracted OCR text content"
db_session.commit() db_session.commit()
html = client.get(f"/files/{rec.id}").text html = client.get(f"/files/{rec.id}/detail").text
assert "toggleOcrText" in html assert "toggleOcrText" in html
assert "ocr-text-block" in html assert "ocr-text-block" in html
assert "Sample extracted OCR text content" in html assert "Sample extracted OCR text content" in html
@@ -383,7 +383,7 @@ class TestFileViewOcrText:
pdf.write_bytes(b"%PDF-1.4") pdf.write_bytes(b"%PDF-1.4")
rec = _create_file_record(db_session, file_path=str(pdf)) rec = _create_file_record(db_session, file_path=str(pdf))
html = client.get(f"/files/{rec.id}").text html = client.get(f"/files/{rec.id}/detail").text
assert "loadText" in html or "Extract" in html assert "loadText" in html or "Extract" in html
@@ -409,5 +409,5 @@ class TestFileViewNoFile:
db_session.commit() db_session.commit()
db_session.refresh(rec) db_session.refresh(rec)
html = client.get(f"/files/{rec.id}").text html = client.get(f"/files/{rec.id}/detail").text
assert "No file available for preview" in html assert "No file available for preview" in html
+2 -2
View File
@@ -447,7 +447,7 @@ class TestFileDetailView:
db_session.commit() db_session.commit()
# Test detail view # Test detail view
response = client.get(f"/files/{file_record.id}/detail") response = client.get(f"/files/{file_record.id}/process")
assert response.status_code == 200 assert response.status_code == 200
# Check that response contains HTML with file information # Check that response contains HTML with file information
assert b"File Information" in response.content assert b"File Information" in response.content
@@ -504,7 +504,7 @@ class TestFileDetailView:
db_session.commit() db_session.commit()
# Test detail view # Test detail view
response = client.get(f"/files/{file_record.id}/detail") response = client.get(f"/files/{file_record.id}/process")
assert response.status_code == 200 assert response.status_code == 200
# Check that response contains branching visualization elements # Check that response contains branching visualization elements
assert b"Process Flow Visualization" in response.content assert b"Process Flow Visualization" in response.content
+3 -3
View File
@@ -50,7 +50,7 @@ def test_file_detail_page_with_metadata(client: TestClient, db_session, sample_p
db_session.refresh(file_record) db_session.refresh(file_record)
# Get detail page # Get detail page
response = client.get(f"/files/{file_record.id}/detail") response = client.get(f"/files/{file_record.id}/process")
assert response.status_code == 200 assert response.status_code == 200
html = response.text html = response.text
@@ -85,7 +85,7 @@ def test_file_detail_with_gpt_metadata(client: TestClient, db_session, sample_pd
db_session.refresh(file_record) db_session.refresh(file_record)
# Get detail page # Get detail page
response = client.get(f"/files/{file_record.id}/detail") response = client.get(f"/files/{file_record.id}/process")
assert response.status_code == 200 assert response.status_code == 200
html = response.text html = response.text
@@ -190,7 +190,7 @@ def test_file_detail_shows_file_status_indicators(client: TestClient, db_session
db_session.commit() db_session.commit()
db_session.refresh(file_record) db_session.refresh(file_record)
response = client.get(f"/files/{file_record.id}/detail") response = client.get(f"/files/{file_record.id}/process")
assert response.status_code == 200 assert response.status_code == 200
html = response.text html = response.text
+1 -1
View File
@@ -193,7 +193,7 @@ class TestFileDetailPage:
db_session.commit() db_session.commit()
# Test file detail page # Test file detail page
response = client.get(f"/files/{file_record.id}/detail") response = client.get(f"/files/{file_record.id}/process")
assert response.status_code == 200 assert response.status_code == 200
content = response.text content = response.text
assert "create_file_record" in content assert "create_file_record" in content