mirror of
https://github.com/elisiariocouto/leggen.git
synced 2025-12-13 11:22:21 +00:00
refactor(api): Update all modified files with dependency injection changes.
This commit is contained in:
committed by
Elisiário Couto
parent
9dc6357905
commit
9e9b1cf15f
@@ -126,6 +126,38 @@ def api_client(fastapi_app):
|
||||
return TestClient(fastapi_app)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_account_repo():
|
||||
"""Create mock AccountRepository for testing."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
return MagicMock()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_balance_repo():
|
||||
"""Create mock BalanceRepository for testing."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
return MagicMock()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_transaction_repo():
|
||||
"""Create mock TransactionRepository for testing."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
return MagicMock()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_analytics_proc():
|
||||
"""Create mock AnalyticsProcessor for testing."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
return MagicMock()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_db_path(temp_db_path):
|
||||
"""Mock the database path to use temporary database for testing."""
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
"""Tests for analytics fixes to ensure all transactions are used in statistics."""
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from unittest.mock import AsyncMock, Mock, patch
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from leggen.api.dependencies import get_transaction_repository
|
||||
from leggen.commands.server import create_app
|
||||
from leggen.services.database_service import DatabaseService
|
||||
|
||||
|
||||
class TestAnalyticsFix:
|
||||
@@ -19,11 +19,11 @@ class TestAnalyticsFix:
|
||||
return TestClient(app)
|
||||
|
||||
@pytest.fixture
|
||||
def mock_database_service(self):
|
||||
return Mock(spec=DatabaseService)
|
||||
def mock_transaction_repo(self):
|
||||
return Mock()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_transaction_stats_uses_all_transactions(self, mock_database_service):
|
||||
async def test_transaction_stats_uses_all_transactions(self, mock_transaction_repo):
|
||||
"""Test that transaction stats endpoint uses all transactions (not limited to 100)"""
|
||||
# Mock data for 600 transactions (simulating the issue)
|
||||
mock_transactions = []
|
||||
@@ -42,53 +42,50 @@ class TestAnalyticsFix:
|
||||
}
|
||||
)
|
||||
|
||||
mock_database_service.get_transactions_from_db = AsyncMock(
|
||||
return_value=mock_transactions
|
||||
mock_transaction_repo.get_transactions.return_value = mock_transactions
|
||||
|
||||
app = create_app()
|
||||
app.dependency_overrides[get_transaction_repository] = (
|
||||
lambda: mock_transaction_repo
|
||||
)
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.get("/api/v1/transactions/stats?days=365")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
|
||||
# Verify that limit=None was passed to get all transactions
|
||||
mock_transaction_repo.get_transactions.assert_called_once()
|
||||
call_args = mock_transaction_repo.get_transactions.call_args
|
||||
assert call_args.kwargs.get("limit") is None, (
|
||||
"Stats endpoint should pass limit=None to get all transactions"
|
||||
)
|
||||
|
||||
# Test that the endpoint calls get_transactions_from_db with limit=None
|
||||
with patch(
|
||||
"leggen.api.routes.transactions.database_service", mock_database_service
|
||||
):
|
||||
app = create_app()
|
||||
client = TestClient(app)
|
||||
# Verify that the response contains stats for all 600 transactions
|
||||
stats = data
|
||||
assert stats["total_transactions"] == 600, (
|
||||
"Should process all 600 transactions, not just 100"
|
||||
)
|
||||
|
||||
response = client.get("/api/v1/transactions/stats?days=365")
|
||||
# Verify calculations are correct for all transactions
|
||||
expected_income = sum(
|
||||
txn["transactionValue"]
|
||||
for txn in mock_transactions
|
||||
if txn["transactionValue"] > 0
|
||||
)
|
||||
expected_expenses = sum(
|
||||
abs(txn["transactionValue"])
|
||||
for txn in mock_transactions
|
||||
if txn["transactionValue"] < 0
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
|
||||
# Verify that limit=None was passed to get all transactions
|
||||
mock_database_service.get_transactions_from_db.assert_called_once()
|
||||
call_args = mock_database_service.get_transactions_from_db.call_args
|
||||
assert call_args.kwargs.get("limit") is None, (
|
||||
"Stats endpoint should pass limit=None to get all transactions"
|
||||
)
|
||||
|
||||
# Verify that the response contains stats for all 600 transactions
|
||||
stats = data
|
||||
assert stats["total_transactions"] == 600, (
|
||||
"Should process all 600 transactions, not just 100"
|
||||
)
|
||||
|
||||
# Verify calculations are correct for all transactions
|
||||
expected_income = sum(
|
||||
txn["transactionValue"]
|
||||
for txn in mock_transactions
|
||||
if txn["transactionValue"] > 0
|
||||
)
|
||||
expected_expenses = sum(
|
||||
abs(txn["transactionValue"])
|
||||
for txn in mock_transactions
|
||||
if txn["transactionValue"] < 0
|
||||
)
|
||||
|
||||
assert stats["total_income"] == expected_income
|
||||
assert stats["total_expenses"] == expected_expenses
|
||||
assert stats["total_income"] == expected_income
|
||||
assert stats["total_expenses"] == expected_expenses
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_analytics_endpoint_returns_all_transactions(
|
||||
self, mock_database_service
|
||||
self, mock_transaction_repo
|
||||
):
|
||||
"""Test that the new analytics endpoint returns all transactions without pagination"""
|
||||
# Mock data for 600 transactions
|
||||
@@ -108,30 +105,28 @@ class TestAnalyticsFix:
|
||||
}
|
||||
)
|
||||
|
||||
mock_database_service.get_transactions_from_db = AsyncMock(
|
||||
return_value=mock_transactions
|
||||
mock_transaction_repo.get_transactions.return_value = mock_transactions
|
||||
|
||||
app = create_app()
|
||||
app.dependency_overrides[get_transaction_repository] = (
|
||||
lambda: mock_transaction_repo
|
||||
)
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.get("/api/v1/transactions/analytics?days=365")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
|
||||
# Verify that limit=None was passed to get all transactions
|
||||
mock_transaction_repo.get_transactions.assert_called_once()
|
||||
call_args = mock_transaction_repo.get_transactions.call_args
|
||||
assert call_args.kwargs.get("limit") is None, (
|
||||
"Analytics endpoint should pass limit=None"
|
||||
)
|
||||
|
||||
with patch(
|
||||
"leggen.api.routes.transactions.database_service", mock_database_service
|
||||
):
|
||||
app = create_app()
|
||||
client = TestClient(app)
|
||||
|
||||
response = client.get("/api/v1/transactions/analytics?days=365")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
|
||||
# Verify that limit=None was passed to get all transactions
|
||||
mock_database_service.get_transactions_from_db.assert_called_once()
|
||||
call_args = mock_database_service.get_transactions_from_db.call_args
|
||||
assert call_args.kwargs.get("limit") is None, (
|
||||
"Analytics endpoint should pass limit=None"
|
||||
)
|
||||
|
||||
# Verify that all 600 transactions are returned
|
||||
transactions_data = data
|
||||
assert len(transactions_data) == 600, (
|
||||
"Analytics endpoint should return all 600 transactions"
|
||||
)
|
||||
# Verify that all 600 transactions are returned
|
||||
transactions_data = data
|
||||
assert len(transactions_data) == 600, (
|
||||
"Analytics endpoint should return all 600 transactions"
|
||||
)
|
||||
|
||||
@@ -4,6 +4,12 @@ from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from leggen.api.dependencies import (
|
||||
get_account_repository,
|
||||
get_balance_repository,
|
||||
get_transaction_repository,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.api
|
||||
class TestAccountsAPI:
|
||||
@@ -11,11 +17,14 @@ class TestAccountsAPI:
|
||||
|
||||
def test_get_all_accounts_success(
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
sample_account_data,
|
||||
mock_db_path,
|
||||
mock_account_repo,
|
||||
mock_balance_repo,
|
||||
):
|
||||
"""Test successful retrieval of all accounts from database."""
|
||||
mock_accounts = [
|
||||
@@ -45,19 +54,21 @@ class TestAccountsAPI:
|
||||
}
|
||||
]
|
||||
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.accounts.database_service.get_accounts_from_db",
|
||||
return_value=mock_accounts,
|
||||
),
|
||||
patch(
|
||||
"leggen.api.routes.accounts.database_service.get_balances_from_db",
|
||||
return_value=mock_balances,
|
||||
),
|
||||
):
|
||||
mock_account_repo.get_accounts.return_value = mock_accounts
|
||||
mock_balance_repo.get_balances.return_value = mock_balances
|
||||
|
||||
fastapi_app.dependency_overrides[get_account_repository] = (
|
||||
lambda: mock_account_repo
|
||||
)
|
||||
fastapi_app.dependency_overrides[get_balance_repository] = (
|
||||
lambda: mock_balance_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get("/api/v1/accounts")
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert len(data) == 1
|
||||
@@ -69,11 +80,14 @@ class TestAccountsAPI:
|
||||
|
||||
def test_get_account_details_success(
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
sample_account_data,
|
||||
mock_db_path,
|
||||
mock_account_repo,
|
||||
mock_balance_repo,
|
||||
):
|
||||
"""Test successful retrieval of specific account details from database."""
|
||||
mock_account = {
|
||||
@@ -101,19 +115,21 @@ class TestAccountsAPI:
|
||||
}
|
||||
]
|
||||
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.accounts.database_service.get_account_details_from_db",
|
||||
return_value=mock_account,
|
||||
),
|
||||
patch(
|
||||
"leggen.api.routes.accounts.database_service.get_balances_from_db",
|
||||
return_value=mock_balances,
|
||||
),
|
||||
):
|
||||
mock_account_repo.get_account.return_value = mock_account
|
||||
mock_balance_repo.get_balances.return_value = mock_balances
|
||||
|
||||
fastapi_app.dependency_overrides[get_account_repository] = (
|
||||
lambda: mock_account_repo
|
||||
)
|
||||
fastapi_app.dependency_overrides[get_balance_repository] = (
|
||||
lambda: mock_balance_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get("/api/v1/accounts/test-account-123")
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["id"] == "test-account-123"
|
||||
@@ -121,7 +137,13 @@ class TestAccountsAPI:
|
||||
assert len(data["balances"]) == 1
|
||||
|
||||
def test_get_account_balances_success(
|
||||
self, api_client, mock_config, mock_auth_token, mock_db_path
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
mock_db_path,
|
||||
mock_balance_repo,
|
||||
):
|
||||
"""Test successful retrieval of account balances from database."""
|
||||
mock_balances = [
|
||||
@@ -149,15 +171,17 @@ class TestAccountsAPI:
|
||||
},
|
||||
]
|
||||
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.accounts.database_service.get_balances_from_db",
|
||||
return_value=mock_balances,
|
||||
),
|
||||
):
|
||||
mock_balance_repo.get_balances.return_value = mock_balances
|
||||
|
||||
fastapi_app.dependency_overrides[get_balance_repository] = (
|
||||
lambda: mock_balance_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get("/api/v1/accounts/test-account-123/balances")
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert len(data) == 2
|
||||
@@ -167,12 +191,14 @@ class TestAccountsAPI:
|
||||
|
||||
def test_get_account_transactions_success(
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
sample_account_data,
|
||||
sample_transaction_data,
|
||||
mock_db_path,
|
||||
mock_transaction_repo,
|
||||
):
|
||||
"""Test successful retrieval of account transactions from database."""
|
||||
mock_transactions = [
|
||||
@@ -191,21 +217,19 @@ class TestAccountsAPI:
|
||||
}
|
||||
]
|
||||
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.accounts.database_service.get_transactions_from_db",
|
||||
return_value=mock_transactions,
|
||||
),
|
||||
patch(
|
||||
"leggen.api.routes.accounts.database_service.get_transaction_count_from_db",
|
||||
return_value=1,
|
||||
),
|
||||
):
|
||||
mock_transaction_repo.get_transactions.return_value = mock_transactions
|
||||
|
||||
fastapi_app.dependency_overrides[get_transaction_repository] = (
|
||||
lambda: mock_transaction_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get(
|
||||
"/api/v1/accounts/test-account-123/transactions?summary_only=true"
|
||||
)
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert len(data) == 1
|
||||
@@ -218,12 +242,14 @@ class TestAccountsAPI:
|
||||
|
||||
def test_get_account_transactions_full_details(
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
sample_account_data,
|
||||
sample_transaction_data,
|
||||
mock_db_path,
|
||||
mock_transaction_repo,
|
||||
):
|
||||
"""Test retrieval of full transaction details from database."""
|
||||
mock_transactions = [
|
||||
@@ -242,21 +268,19 @@ class TestAccountsAPI:
|
||||
}
|
||||
]
|
||||
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.accounts.database_service.get_transactions_from_db",
|
||||
return_value=mock_transactions,
|
||||
),
|
||||
patch(
|
||||
"leggen.api.routes.accounts.database_service.get_transaction_count_from_db",
|
||||
return_value=1,
|
||||
),
|
||||
):
|
||||
mock_transaction_repo.get_transactions.return_value = mock_transactions
|
||||
|
||||
fastapi_app.dependency_overrides[get_transaction_repository] = (
|
||||
lambda: mock_transaction_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get(
|
||||
"/api/v1/accounts/test-account-123/transactions?summary_only=false"
|
||||
)
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert len(data) == 1
|
||||
@@ -268,22 +292,36 @@ class TestAccountsAPI:
|
||||
assert "raw_transaction" in transaction
|
||||
|
||||
def test_get_account_not_found(
|
||||
self, api_client, mock_config, mock_auth_token, mock_db_path
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
mock_db_path,
|
||||
mock_account_repo,
|
||||
):
|
||||
"""Test handling of non-existent account."""
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.accounts.database_service.get_account_details_from_db",
|
||||
return_value=None,
|
||||
),
|
||||
):
|
||||
mock_account_repo.get_account.return_value = None
|
||||
|
||||
fastapi_app.dependency_overrides[get_account_repository] = (
|
||||
lambda: mock_account_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get("/api/v1/accounts/nonexistent")
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_update_account_display_name_success(
|
||||
self, api_client, mock_config, mock_auth_token, mock_db_path
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
mock_db_path,
|
||||
mock_account_repo,
|
||||
):
|
||||
"""Test successful update of account display name."""
|
||||
mock_account = {
|
||||
@@ -297,41 +335,48 @@ class TestAccountsAPI:
|
||||
"last_accessed": "2025-09-01T09:30:00Z",
|
||||
}
|
||||
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.accounts.database_service.get_account_details_from_db",
|
||||
return_value=mock_account,
|
||||
),
|
||||
patch(
|
||||
"leggen.api.routes.accounts.database_service.persist_account_details",
|
||||
return_value=None,
|
||||
),
|
||||
):
|
||||
mock_account_repo.get_account.return_value = mock_account
|
||||
mock_account_repo.persist.return_value = mock_account
|
||||
|
||||
fastapi_app.dependency_overrides[get_account_repository] = (
|
||||
lambda: mock_account_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.put(
|
||||
"/api/v1/accounts/test-account-123",
|
||||
json={"display_name": "My Custom Account Name"},
|
||||
)
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["id"] == "test-account-123"
|
||||
assert data["display_name"] == "My Custom Account Name"
|
||||
|
||||
def test_update_account_not_found(
|
||||
self, api_client, mock_config, mock_auth_token, mock_db_path
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
mock_db_path,
|
||||
mock_account_repo,
|
||||
):
|
||||
"""Test updating non-existent account."""
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.accounts.database_service.get_account_details_from_db",
|
||||
return_value=None,
|
||||
),
|
||||
):
|
||||
mock_account_repo.get_account.return_value = None
|
||||
|
||||
fastapi_app.dependency_overrides[get_account_repository] = (
|
||||
lambda: mock_account_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.put(
|
||||
"/api/v1/accounts/nonexistent",
|
||||
json={"display_name": "New Name"},
|
||||
)
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 404
|
||||
|
||||
@@ -5,13 +5,20 @@ from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from leggen.api.dependencies import get_transaction_repository
|
||||
|
||||
|
||||
@pytest.mark.api
|
||||
class TestTransactionsAPI:
|
||||
"""Test transaction-related API endpoints."""
|
||||
|
||||
def test_get_all_transactions_success(
|
||||
self, api_client, mock_config, mock_auth_token
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
mock_transaction_repo,
|
||||
):
|
||||
"""Test successful retrieval of all transactions from database."""
|
||||
mock_transactions = [
|
||||
@@ -43,19 +50,17 @@ class TestTransactionsAPI:
|
||||
},
|
||||
]
|
||||
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.transactions.database_service.get_transactions_from_db",
|
||||
return_value=mock_transactions,
|
||||
),
|
||||
patch(
|
||||
"leggen.api.routes.transactions.database_service.get_transaction_count_from_db",
|
||||
return_value=2,
|
||||
),
|
||||
):
|
||||
mock_transaction_repo.get_transactions.return_value = mock_transactions
|
||||
mock_transaction_repo.get_count.return_value = len(mock_transactions)
|
||||
fastapi_app.dependency_overrides[get_transaction_repository] = (
|
||||
lambda: mock_transaction_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get("/api/v1/transactions?summary_only=true")
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert len(data["data"]) == 2
|
||||
@@ -70,7 +75,12 @@ class TestTransactionsAPI:
|
||||
assert transaction["account_id"] == "test-account-123"
|
||||
|
||||
def test_get_all_transactions_full_details(
|
||||
self, api_client, mock_config, mock_auth_token
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
mock_transaction_repo,
|
||||
):
|
||||
"""Test retrieval of full transaction details from database."""
|
||||
mock_transactions = [
|
||||
@@ -89,19 +99,17 @@ class TestTransactionsAPI:
|
||||
}
|
||||
]
|
||||
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.transactions.database_service.get_transactions_from_db",
|
||||
return_value=mock_transactions,
|
||||
),
|
||||
patch(
|
||||
"leggen.api.routes.transactions.database_service.get_transaction_count_from_db",
|
||||
return_value=1,
|
||||
),
|
||||
):
|
||||
mock_transaction_repo.get_transactions.return_value = mock_transactions
|
||||
mock_transaction_repo.get_count.return_value = len(mock_transactions)
|
||||
fastapi_app.dependency_overrides[get_transaction_repository] = (
|
||||
lambda: mock_transaction_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get("/api/v1/transactions?summary_only=false")
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert len(data["data"]) == 1
|
||||
@@ -114,7 +122,12 @@ class TestTransactionsAPI:
|
||||
assert "raw_transaction" in transaction
|
||||
|
||||
def test_get_transactions_with_filters(
|
||||
self, api_client, mock_config, mock_auth_token
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
mock_transaction_repo,
|
||||
):
|
||||
"""Test getting transactions with various filters."""
|
||||
mock_transactions = [
|
||||
@@ -133,17 +146,14 @@ class TestTransactionsAPI:
|
||||
}
|
||||
]
|
||||
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.transactions.database_service.get_transactions_from_db",
|
||||
return_value=mock_transactions,
|
||||
) as mock_get_transactions,
|
||||
patch(
|
||||
"leggen.api.routes.transactions.database_service.get_transaction_count_from_db",
|
||||
return_value=1,
|
||||
),
|
||||
):
|
||||
mock_transaction_repo.get_transactions.return_value = mock_transactions
|
||||
mock_transaction_repo.get_count.return_value = 1
|
||||
|
||||
fastapi_app.dependency_overrides[get_transaction_repository] = (
|
||||
lambda: mock_transaction_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get(
|
||||
"/api/v1/transactions?"
|
||||
"account_id=test-account-123&"
|
||||
@@ -156,10 +166,12 @@ class TestTransactionsAPI:
|
||||
"per_page=10"
|
||||
)
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
# Verify the database service was called with correct filters
|
||||
mock_get_transactions.assert_called_once_with(
|
||||
# Verify the repository was called with correct filters
|
||||
mock_transaction_repo.get_transactions.assert_called_once_with(
|
||||
account_id="test-account-123",
|
||||
limit=10,
|
||||
offset=10, # (page-1) * per_page = (2-1) * 10 = 10
|
||||
@@ -171,22 +183,26 @@ class TestTransactionsAPI:
|
||||
)
|
||||
|
||||
def test_get_transactions_empty_result(
|
||||
self, api_client, mock_config, mock_auth_token
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
mock_transaction_repo,
|
||||
):
|
||||
"""Test getting transactions when database returns empty result."""
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.transactions.database_service.get_transactions_from_db",
|
||||
return_value=[],
|
||||
),
|
||||
patch(
|
||||
"leggen.api.routes.transactions.database_service.get_transaction_count_from_db",
|
||||
return_value=0,
|
||||
),
|
||||
):
|
||||
mock_transaction_repo.get_transactions.return_value = []
|
||||
mock_transaction_repo.get_count.return_value = 0
|
||||
|
||||
fastapi_app.dependency_overrides[get_transaction_repository] = (
|
||||
lambda: mock_transaction_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get("/api/v1/transactions")
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert len(data["data"]) == 0
|
||||
@@ -195,23 +211,37 @@ class TestTransactionsAPI:
|
||||
assert data["total_pages"] == 0
|
||||
|
||||
def test_get_transactions_database_error(
|
||||
self, api_client, mock_config, mock_auth_token
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
mock_transaction_repo,
|
||||
):
|
||||
"""Test handling database error when getting transactions."""
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.transactions.database_service.get_transactions_from_db",
|
||||
side_effect=Exception("Database connection failed"),
|
||||
),
|
||||
):
|
||||
mock_transaction_repo.get_transactions.side_effect = Exception(
|
||||
"Database connection failed"
|
||||
)
|
||||
|
||||
fastapi_app.dependency_overrides[get_transaction_repository] = (
|
||||
lambda: mock_transaction_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get("/api/v1/transactions")
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 500
|
||||
assert "Failed to get transactions" in response.json()["detail"]
|
||||
|
||||
def test_get_transaction_stats_success(
|
||||
self, api_client, mock_config, mock_auth_token
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
mock_transaction_repo,
|
||||
):
|
||||
"""Test successful retrieval of transaction statistics from database."""
|
||||
mock_transactions = [
|
||||
@@ -238,15 +268,16 @@ class TestTransactionsAPI:
|
||||
},
|
||||
]
|
||||
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.transactions.database_service.get_transactions_from_db",
|
||||
return_value=mock_transactions,
|
||||
),
|
||||
):
|
||||
mock_transaction_repo.get_transactions.return_value = mock_transactions
|
||||
fastapi_app.dependency_overrides[get_transaction_repository] = (
|
||||
lambda: mock_transaction_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get("/api/v1/transactions/stats?days=30")
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
|
||||
@@ -264,7 +295,12 @@ class TestTransactionsAPI:
|
||||
assert data["average_transaction"] == expected_avg
|
||||
|
||||
def test_get_transaction_stats_with_account_filter(
|
||||
self, api_client, mock_config, mock_auth_token
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
mock_transaction_repo,
|
||||
):
|
||||
"""Test getting transaction stats filtered by account."""
|
||||
mock_transactions = [
|
||||
@@ -277,37 +313,46 @@ class TestTransactionsAPI:
|
||||
}
|
||||
]
|
||||
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.transactions.database_service.get_transactions_from_db",
|
||||
return_value=mock_transactions,
|
||||
) as mock_get_transactions,
|
||||
):
|
||||
mock_transaction_repo.get_transactions.return_value = mock_transactions
|
||||
|
||||
fastapi_app.dependency_overrides[get_transaction_repository] = (
|
||||
lambda: mock_transaction_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get(
|
||||
"/api/v1/transactions/stats?account_id=test-account-123"
|
||||
)
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
# Verify the database service was called with account filter
|
||||
mock_get_transactions.assert_called_once()
|
||||
call_kwargs = mock_get_transactions.call_args.kwargs
|
||||
# Verify the repository was called with account filter
|
||||
mock_transaction_repo.get_transactions.assert_called_once()
|
||||
call_kwargs = mock_transaction_repo.get_transactions.call_args.kwargs
|
||||
assert call_kwargs["account_id"] == "test-account-123"
|
||||
|
||||
def test_get_transaction_stats_empty_result(
|
||||
self, api_client, mock_config, mock_auth_token
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
mock_transaction_repo,
|
||||
):
|
||||
"""Test getting stats when no transactions match criteria."""
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.transactions.database_service.get_transactions_from_db",
|
||||
return_value=[],
|
||||
),
|
||||
):
|
||||
mock_transaction_repo.get_transactions.return_value = []
|
||||
|
||||
fastapi_app.dependency_overrides[get_transaction_repository] = (
|
||||
lambda: mock_transaction_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get("/api/v1/transactions/stats")
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
|
||||
@@ -319,23 +364,37 @@ class TestTransactionsAPI:
|
||||
assert data["accounts_included"] == 0
|
||||
|
||||
def test_get_transaction_stats_database_error(
|
||||
self, api_client, mock_config, mock_auth_token
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
mock_transaction_repo,
|
||||
):
|
||||
"""Test handling database error when getting stats."""
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.transactions.database_service.get_transactions_from_db",
|
||||
side_effect=Exception("Database connection failed"),
|
||||
),
|
||||
):
|
||||
mock_transaction_repo.get_transactions.side_effect = Exception(
|
||||
"Database connection failed"
|
||||
)
|
||||
|
||||
fastapi_app.dependency_overrides[get_transaction_repository] = (
|
||||
lambda: mock_transaction_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get("/api/v1/transactions/stats")
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 500
|
||||
assert "Failed to get transaction stats" in response.json()["detail"]
|
||||
|
||||
def test_get_transaction_stats_custom_period(
|
||||
self, api_client, mock_config, mock_auth_token
|
||||
self,
|
||||
fastapi_app,
|
||||
api_client,
|
||||
mock_config,
|
||||
mock_auth_token,
|
||||
mock_transaction_repo,
|
||||
):
|
||||
"""Test getting transaction stats for custom time period."""
|
||||
mock_transactions = [
|
||||
@@ -348,21 +407,23 @@ class TestTransactionsAPI:
|
||||
}
|
||||
]
|
||||
|
||||
with (
|
||||
patch("leggen.utils.config.config", mock_config),
|
||||
patch(
|
||||
"leggen.api.routes.transactions.database_service.get_transactions_from_db",
|
||||
return_value=mock_transactions,
|
||||
) as mock_get_transactions,
|
||||
):
|
||||
mock_transaction_repo.get_transactions.return_value = mock_transactions
|
||||
|
||||
fastapi_app.dependency_overrides[get_transaction_repository] = (
|
||||
lambda: mock_transaction_repo
|
||||
)
|
||||
|
||||
with patch("leggen.utils.config.config", mock_config):
|
||||
response = api_client.get("/api/v1/transactions/stats?days=7")
|
||||
|
||||
fastapi_app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["period_days"] == 7
|
||||
|
||||
# Verify the date range was calculated correctly for 7 days
|
||||
mock_get_transactions.assert_called_once()
|
||||
call_kwargs = mock_get_transactions.call_args.kwargs
|
||||
mock_transaction_repo.get_transactions.assert_called_once()
|
||||
call_kwargs = mock_transaction_repo.get_transactions.call_args.kwargs
|
||||
assert "date_from" in call_kwargs
|
||||
assert "date_to" in call_kwargs
|
||||
|
||||
@@ -27,9 +27,7 @@ class TestSyncNotifications:
|
||||
patch.object(
|
||||
sync_service.notifications, "send_sync_failure_notification"
|
||||
) as mock_send_notification,
|
||||
patch.object(
|
||||
sync_service.database, "persist_sync_operation", return_value=1
|
||||
),
|
||||
patch.object(sync_service.sync, "persist", return_value=1),
|
||||
):
|
||||
# Setup: One requisition with one account that will fail
|
||||
mock_get_requisitions.return_value = {
|
||||
@@ -69,9 +67,7 @@ class TestSyncNotifications:
|
||||
patch.object(
|
||||
sync_service.notifications, "send_expiry_notification"
|
||||
) as mock_send_expiry,
|
||||
patch.object(
|
||||
sync_service.database, "persist_sync_operation", return_value=1
|
||||
),
|
||||
patch.object(sync_service.sync, "persist", return_value=1),
|
||||
):
|
||||
# Setup: One expired requisition
|
||||
mock_get_requisitions.return_value = {
|
||||
@@ -112,9 +108,7 @@ class TestSyncNotifications:
|
||||
patch.object(
|
||||
sync_service.notifications, "send_sync_failure_notification"
|
||||
) as mock_send_notification,
|
||||
patch.object(
|
||||
sync_service.database, "persist_sync_operation", return_value=1
|
||||
),
|
||||
patch.object(sync_service.sync, "persist", return_value=1),
|
||||
):
|
||||
# Setup: One requisition with two accounts that will fail
|
||||
mock_get_requisitions.return_value = {
|
||||
@@ -160,17 +154,15 @@ class TestSyncNotifications:
|
||||
sync_service.notifications, "send_sync_failure_notification"
|
||||
) as mock_send_notification,
|
||||
patch.object(sync_service.notifications, "send_transaction_notifications"),
|
||||
patch.object(sync_service.database, "persist_account_details"),
|
||||
patch.object(sync_service.database, "persist_balance"),
|
||||
patch.object(sync_service.accounts, "persist"),
|
||||
patch.object(sync_service.balances, "persist"),
|
||||
patch.object(
|
||||
sync_service.database, "process_transactions", return_value=[]
|
||||
),
|
||||
patch.object(
|
||||
sync_service.database, "persist_transactions", return_value=[]
|
||||
),
|
||||
patch.object(
|
||||
sync_service.database, "persist_sync_operation", return_value=1
|
||||
sync_service.transaction_processor,
|
||||
"process_transactions",
|
||||
return_value=[],
|
||||
),
|
||||
patch.object(sync_service.transactions, "persist", return_value=[]),
|
||||
patch.object(sync_service.sync, "persist", return_value=1),
|
||||
):
|
||||
# Setup: One requisition with one account that succeeds
|
||||
mock_get_requisitions.return_value = {
|
||||
@@ -222,9 +214,7 @@ class TestSyncNotifications:
|
||||
patch.object(
|
||||
sync_service.notifications, "_send_telegram_sync_failure"
|
||||
) as mock_telegram_notification,
|
||||
patch.object(
|
||||
sync_service.database, "persist_sync_operation", return_value=1
|
||||
),
|
||||
patch.object(sync_service.sync, "persist", return_value=1),
|
||||
):
|
||||
# Setup: One requisition with one account that will fail
|
||||
mock_get_requisitions.return_value = {
|
||||
|
||||
Reference in New Issue
Block a user