fix: merge main branch and renumber migration 027→037

Resolve 3 merge conflicts and renumber the automation_hooks migration
to follow main's migration chain (036_add_document_translation_fields).

Conflicts resolved:
- app/api/__init__.py: add automation_router alongside main's new routers
- app/utils/settings_service.py: add automation_hooks_enabled alongside compliance_enabled
- tests/conftest.py: add AutomationHook alongside AuditLog/ComplianceTemplate imports

Migration renumbered:
- 027_add_automation_hooks → 037_add_automation_hooks
- down_revision: 026_add_scheduled_jobs → 036_add_document_translation_fields

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-16 22:40:15 +00:00
parent 6a83d51d88
commit 204000aabc
318 changed files with 317516 additions and 2858 deletions
+21 -21
View File
@@ -5,7 +5,7 @@ Focuses on uncovered lines: 98-99, 121-143, 160-161, 170-171,
324-326, 400-402, 436-438.
"""
from unittest.mock import MagicMock, PropertyMock, patch
from unittest.mock import AsyncMock, MagicMock, PropertyMock, patch
import pytest
from fastapi.testclient import TestClient
@@ -15,7 +15,7 @@ from fastapi.testclient import TestClient
class TestTestTokenRefreshFailed:
"""Cover lines 98-99: token refresh returns non-200."""
@patch("app.api.onedrive.requests.post")
@patch("httpx.AsyncClient.post", new_callable=AsyncMock)
def test_test_token_refresh_returns_non_200(self, mock_post, client: TestClient):
"""Test token refresh returning a failure status hits the error branch."""
from app.config import settings
@@ -42,8 +42,8 @@ class TestTestTokenRefreshFailed:
class TestTestTokenRotation:
"""Cover lines 121-143, 160-161: token rotation with .env and DB persist."""
@patch("app.api.onedrive.requests.get")
@patch("app.api.onedrive.requests.post")
@patch("httpx.AsyncClient.get", new_callable=AsyncMock)
@patch("httpx.AsyncClient.post", new_callable=AsyncMock)
def test_token_rotation_env_file_exists(self, mock_post, mock_get, client: TestClient, tmp_path):
"""When a new refresh token is received and .env file exists, it should be updated."""
from app.config import settings
@@ -75,8 +75,8 @@ class TestTestTokenRotation:
patch.object(settings, "onedrive_refresh_token", "old_token"),
patch.object(settings, "onedrive_client_id", "cid"),
patch.object(settings, "onedrive_client_secret", "sec"),
patch("app.api.onedrive.os.path.join", return_value=str(env_file)),
patch("app.api.onedrive.os.path.exists", return_value=True),
patch("app.utils.env_utils.os.path.join", return_value=str(env_file)),
patch("app.utils.env_utils.os.path.exists", return_value=True),
patch("app.database.SessionLocal") as mock_session_local,
patch("app.api.onedrive.save_setting_to_db"),
patch("app.api.onedrive.notify_settings_updated"),
@@ -90,8 +90,8 @@ class TestTestTokenRotation:
data = response.json()
assert data["status"] == "success"
@patch("app.api.onedrive.requests.get")
@patch("app.api.onedrive.requests.post")
@patch("httpx.AsyncClient.get", new_callable=AsyncMock)
@patch("httpx.AsyncClient.post", new_callable=AsyncMock)
def test_token_rotation_env_not_existing(self, mock_post, mock_get, client: TestClient):
"""Token rotation when .env doesn't exist still succeeds."""
from app.config import settings
@@ -117,7 +117,7 @@ class TestTestTokenRotation:
patch.object(settings, "onedrive_refresh_token", "old_token"),
patch.object(settings, "onedrive_client_id", "cid"),
patch.object(settings, "onedrive_client_secret", "sec"),
patch("app.api.onedrive.os.path.exists", return_value=False),
patch("app.utils.env_utils.os.path.exists", return_value=False),
patch("app.database.SessionLocal") as mock_session_local,
patch("app.api.onedrive.save_setting_to_db"),
patch("app.api.onedrive.notify_settings_updated"),
@@ -130,8 +130,8 @@ class TestTestTokenRotation:
assert response.status_code == 200
assert response.json()["status"] == "success"
@patch("app.api.onedrive.requests.get")
@patch("app.api.onedrive.requests.post")
@patch("httpx.AsyncClient.get", new_callable=AsyncMock)
@patch("httpx.AsyncClient.post", new_callable=AsyncMock)
def test_token_rotation_env_write_failure(self, mock_post, mock_get, client: TestClient):
"""Token rotation when .env write fails (lines 142-143) still continues."""
from app.config import settings
@@ -157,7 +157,7 @@ class TestTestTokenRotation:
patch.object(settings, "onedrive_refresh_token", "old_token"),
patch.object(settings, "onedrive_client_id", "cid"),
patch.object(settings, "onedrive_client_secret", "sec"),
patch("app.api.onedrive.os.path.exists", return_value=True),
patch("app.utils.env_utils.os.path.exists", return_value=True),
patch("builtins.open", side_effect=PermissionError("Permission denied")),
patch("app.database.SessionLocal") as mock_session_local,
patch("app.api.onedrive.save_setting_to_db"),
@@ -171,8 +171,8 @@ class TestTestTokenRotation:
assert response.status_code == 200
assert response.json()["status"] == "success"
@patch("app.api.onedrive.requests.get")
@patch("app.api.onedrive.requests.post")
@patch("httpx.AsyncClient.get", new_callable=AsyncMock)
@patch("httpx.AsyncClient.post", new_callable=AsyncMock)
def test_token_rotation_db_persist_failure(self, mock_post, mock_get, client: TestClient):
"""Token rotation when DB persist fails (lines 160-161) still continues."""
from app.config import settings
@@ -198,7 +198,7 @@ class TestTestTokenRotation:
patch.object(settings, "onedrive_refresh_token", "old_token"),
patch.object(settings, "onedrive_client_id", "cid"),
patch.object(settings, "onedrive_client_secret", "sec"),
patch("app.api.onedrive.os.path.exists", return_value=False),
patch("app.utils.env_utils.os.path.exists", return_value=False),
patch("app.database.SessionLocal", side_effect=Exception("DB error")),
):
response = client.get("/api/onedrive/test-token")
@@ -211,8 +211,8 @@ class TestTestTokenRotation:
class TestTestTokenUserInfoFailed:
"""Cover lines 170-171: user info request fails."""
@patch("app.api.onedrive.requests.get")
@patch("app.api.onedrive.requests.post")
@patch("httpx.AsyncClient.get", new_callable=AsyncMock)
@patch("httpx.AsyncClient.post", new_callable=AsyncMock)
def test_user_info_returns_non_200(self, mock_post, mock_get, client: TestClient):
"""Test when user info request fails after successful token refresh."""
from app.config import settings
@@ -247,8 +247,8 @@ class TestTestTokenUserInfoFailed:
class TestTokenRotationEnvAppendLine:
"""Cover the branch at line 134 where token line is not found in .env and must be appended."""
@patch("app.api.onedrive.requests.get")
@patch("app.api.onedrive.requests.post")
@patch("httpx.AsyncClient.get", new_callable=AsyncMock)
@patch("httpx.AsyncClient.post", new_callable=AsyncMock)
def test_token_rotation_appends_to_env(self, mock_post, mock_get, client: TestClient, tmp_path):
"""When .env exists but doesn't have ONEDRIVE_REFRESH_TOKEN, it should append."""
from app.config import settings
@@ -277,8 +277,8 @@ class TestTokenRotationEnvAppendLine:
patch.object(settings, "onedrive_refresh_token", "old_token"),
patch.object(settings, "onedrive_client_id", "cid"),
patch.object(settings, "onedrive_client_secret", "sec"),
patch("app.api.onedrive.os.path.join", return_value=str(env_file)),
patch("app.api.onedrive.os.path.exists", return_value=True),
patch("app.utils.env_utils.os.path.join", return_value=str(env_file)),
patch("app.utils.env_utils.os.path.exists", return_value=True),
patch("app.database.SessionLocal") as mock_sl,
patch("app.api.onedrive.save_setting_to_db"),
patch("app.api.onedrive.notify_settings_updated"),