734 lines
25 KiB
Python
734 lines
25 KiB
Python
"""Integration tests for Portfolio model (Issue #4: DB-3).
|
|
|
|
Tests for Portfolio model integration with:
|
|
- User model relationships
|
|
- Database constraints and transactions
|
|
- Complex query scenarios
|
|
- Concurrent operations
|
|
- Portfolio lifecycle management
|
|
|
|
Follows TDD principles - tests written BEFORE implementation.
|
|
"""
|
|
|
|
import pytest
|
|
from decimal import Decimal
|
|
from sqlalchemy import select, func
|
|
from sqlalchemy.exc import IntegrityError
|
|
|
|
# Mark all tests in this module as asyncio
|
|
pytestmark = pytest.mark.asyncio
|
|
|
|
|
|
class TestPortfolioUserIntegration:
|
|
"""Integration tests for Portfolio-User relationships."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_portfolio_for_user(self, db_session, test_user):
|
|
"""Should create portfolio linked to user."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
portfolio = Portfolio(
|
|
user_id=test_user.id,
|
|
name="Integration Test Portfolio",
|
|
portfolio_type=PortfolioType.PAPER,
|
|
initial_capital=Decimal("25000.0000"),
|
|
)
|
|
|
|
db_session.add(portfolio)
|
|
await db_session.commit()
|
|
await db_session.refresh(portfolio)
|
|
await db_session.refresh(test_user, ["portfolios"])
|
|
|
|
# Verify both sides of relationship
|
|
assert portfolio.user_id == test_user.id
|
|
assert portfolio in test_user.portfolios
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_user_with_multiple_portfolio_types(self, db_session, test_user):
|
|
"""Should allow user to have different portfolio types."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
live = Portfolio(
|
|
user_id=test_user.id,
|
|
name="Live Trading",
|
|
portfolio_type=PortfolioType.LIVE,
|
|
initial_capital=Decimal("100000.0000"),
|
|
currency="USD",
|
|
)
|
|
|
|
paper = Portfolio(
|
|
user_id=test_user.id,
|
|
name="Paper Trading",
|
|
portfolio_type=PortfolioType.PAPER,
|
|
initial_capital=Decimal("10000.0000"),
|
|
currency="USD",
|
|
)
|
|
|
|
backtest = Portfolio(
|
|
user_id=test_user.id,
|
|
name="Historical Backtest",
|
|
portfolio_type=PortfolioType.BACKTEST,
|
|
initial_capital=Decimal("50000.0000"),
|
|
currency="USD",
|
|
)
|
|
|
|
db_session.add_all([live, paper, backtest])
|
|
await db_session.commit()
|
|
|
|
# Refresh and verify
|
|
await db_session.refresh(test_user, ["portfolios"])
|
|
|
|
assert len(test_user.portfolios) == 3
|
|
|
|
types = {p.portfolio_type for p in test_user.portfolios}
|
|
assert PortfolioType.LIVE in types
|
|
assert PortfolioType.PAPER in types
|
|
assert PortfolioType.BACKTEST in types
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_portfolios_deleted_with_user(self, db_session, db_engine):
|
|
"""Should cascade delete portfolios when user is deleted."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
from tradingagents.api.models.user import User
|
|
from tradingagents.api.services.auth_service import hash_password
|
|
|
|
# Create a temporary user
|
|
temp_user = User(
|
|
username="tempuser",
|
|
email="temp@example.com",
|
|
hashed_password=hash_password("TempPass123!"),
|
|
)
|
|
|
|
db_session.add(temp_user)
|
|
await db_session.commit()
|
|
await db_session.refresh(temp_user)
|
|
|
|
# Create portfolios for temp user
|
|
portfolio1 = Portfolio(
|
|
user_id=temp_user.id,
|
|
name="Portfolio 1",
|
|
portfolio_type=PortfolioType.PAPER,
|
|
initial_capital=Decimal("10000.0000"),
|
|
)
|
|
|
|
portfolio2 = Portfolio(
|
|
user_id=temp_user.id,
|
|
name="Portfolio 2",
|
|
portfolio_type=PortfolioType.LIVE,
|
|
initial_capital=Decimal("50000.0000"),
|
|
)
|
|
|
|
db_session.add_all([portfolio1, portfolio2])
|
|
await db_session.commit()
|
|
|
|
portfolio1_id = portfolio1.id
|
|
portfolio2_id = portfolio2.id
|
|
|
|
# Delete the user
|
|
await db_session.delete(temp_user)
|
|
await db_session.commit()
|
|
|
|
# Verify portfolios are deleted
|
|
result = await db_session.execute(
|
|
select(Portfolio).where(
|
|
Portfolio.id.in_([portfolio1_id, portfolio2_id])
|
|
)
|
|
)
|
|
remaining = result.scalars().all()
|
|
|
|
assert len(remaining) == 0
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_multiple_users_same_portfolio_name(self, db_session, test_user, another_user):
|
|
"""Should allow different users to have portfolios with same name."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
common_name = "Main Portfolio"
|
|
|
|
portfolio1 = Portfolio(
|
|
user_id=test_user.id,
|
|
name=common_name,
|
|
portfolio_type=PortfolioType.PAPER,
|
|
initial_capital=Decimal("10000.0000"),
|
|
)
|
|
|
|
portfolio2 = Portfolio(
|
|
user_id=another_user.id,
|
|
name=common_name,
|
|
portfolio_type=PortfolioType.PAPER,
|
|
initial_capital=Decimal("15000.0000"),
|
|
)
|
|
|
|
db_session.add_all([portfolio1, portfolio2])
|
|
await db_session.commit()
|
|
|
|
# Query to verify both exist
|
|
result = await db_session.execute(
|
|
select(Portfolio).where(Portfolio.name == common_name)
|
|
)
|
|
portfolios = result.scalars().all()
|
|
|
|
assert len(portfolios) == 2
|
|
user_ids = {p.user_id for p in portfolios}
|
|
assert test_user.id in user_ids
|
|
assert another_user.id in user_ids
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
|
|
class TestPortfolioTransactions:
|
|
"""Integration tests for portfolio transaction scenarios."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_update_portfolio_value(self, db_session, test_user):
|
|
"""Should update current_value while preserving initial_capital."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
portfolio = Portfolio(
|
|
user_id=test_user.id,
|
|
name="Value Update Test",
|
|
portfolio_type=PortfolioType.LIVE,
|
|
initial_capital=Decimal("10000.0000"),
|
|
)
|
|
|
|
db_session.add(portfolio)
|
|
await db_session.commit()
|
|
await db_session.refresh(portfolio)
|
|
|
|
# Update current value
|
|
original_capital = portfolio.initial_capital
|
|
portfolio.current_value = Decimal("12500.7500")
|
|
await db_session.commit()
|
|
await db_session.refresh(portfolio)
|
|
|
|
# Verify
|
|
assert portfolio.initial_capital == original_capital
|
|
assert portfolio.current_value == Decimal("12500.7500")
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_deactivate_portfolio(self, db_session, test_user):
|
|
"""Should deactivate portfolio without deleting it."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
portfolio = Portfolio(
|
|
user_id=test_user.id,
|
|
name="Deactivation Test",
|
|
portfolio_type=PortfolioType.LIVE,
|
|
initial_capital=Decimal("50000.0000"),
|
|
is_active=True,
|
|
)
|
|
|
|
db_session.add(portfolio)
|
|
await db_session.commit()
|
|
portfolio_id = portfolio.id
|
|
|
|
# Deactivate
|
|
portfolio.is_active = False
|
|
await db_session.commit()
|
|
|
|
# Verify still exists but inactive
|
|
result = await db_session.execute(
|
|
select(Portfolio).where(Portfolio.id == portfolio_id)
|
|
)
|
|
found = result.scalar_one()
|
|
|
|
assert found is not None
|
|
assert found.is_active is False
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_rollback_on_constraint_violation(self, db_session, test_user):
|
|
"""Should rollback transaction on unique constraint violation."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
# Capture user_id BEFORE any operations to avoid lazy load after rollback
|
|
user_id = test_user.id
|
|
|
|
# Create first portfolio
|
|
portfolio1 = Portfolio(
|
|
user_id=user_id,
|
|
name="Unique Test",
|
|
portfolio_type=PortfolioType.PAPER,
|
|
initial_capital=Decimal("10000.0000"),
|
|
)
|
|
|
|
db_session.add(portfolio1)
|
|
await db_session.commit()
|
|
|
|
# Try to create duplicate
|
|
portfolio2 = Portfolio(
|
|
user_id=user_id,
|
|
name="Unique Test",
|
|
portfolio_type=PortfolioType.LIVE,
|
|
initial_capital=Decimal("20000.0000"),
|
|
)
|
|
|
|
db_session.add(portfolio2)
|
|
|
|
with pytest.raises(IntegrityError):
|
|
await db_session.commit()
|
|
|
|
# Rollback
|
|
await db_session.rollback()
|
|
|
|
# Verify only first portfolio exists (use stored user_id to avoid lazy load)
|
|
result = await db_session.execute(
|
|
select(Portfolio).where(
|
|
Portfolio.user_id == user_id,
|
|
Portfolio.name == "Unique Test"
|
|
)
|
|
)
|
|
portfolios = result.scalars().all()
|
|
|
|
assert len(portfolios) == 1
|
|
assert portfolios[0].portfolio_type == PortfolioType.PAPER
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
|
|
class TestPortfolioComplexQueries:
|
|
"""Integration tests for complex portfolio queries."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_aggregate_total_capital_by_user(self, db_session, test_user):
|
|
"""Should calculate total capital across all user portfolios."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
# Create multiple portfolios
|
|
portfolios_data = [
|
|
("Portfolio A", Decimal("10000.0000")),
|
|
("Portfolio B", Decimal("25000.0000")),
|
|
("Portfolio C", Decimal("15000.5000")),
|
|
]
|
|
|
|
for name, capital in portfolios_data:
|
|
portfolio = Portfolio(
|
|
user_id=test_user.id,
|
|
name=name,
|
|
portfolio_type=PortfolioType.PAPER,
|
|
initial_capital=capital,
|
|
)
|
|
db_session.add(portfolio)
|
|
|
|
await db_session.commit()
|
|
|
|
# Aggregate query
|
|
result = await db_session.execute(
|
|
select(func.sum(Portfolio.initial_capital)).where(
|
|
Portfolio.user_id == test_user.id
|
|
)
|
|
)
|
|
total = result.scalar()
|
|
|
|
expected = Decimal("50000.5000")
|
|
assert total == expected
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_count_portfolios_by_type(self, db_session, test_user):
|
|
"""Should count portfolios grouped by type."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
# Create portfolios of different types
|
|
types_count = {
|
|
PortfolioType.LIVE: 2,
|
|
PortfolioType.PAPER: 3,
|
|
PortfolioType.BACKTEST: 1,
|
|
}
|
|
|
|
for ptype, count in types_count.items():
|
|
for i in range(count):
|
|
portfolio = Portfolio(
|
|
user_id=test_user.id,
|
|
name=f"{ptype.value} Portfolio {i}",
|
|
portfolio_type=ptype,
|
|
initial_capital=Decimal("10000.0000"),
|
|
)
|
|
db_session.add(portfolio)
|
|
|
|
await db_session.commit()
|
|
|
|
# Count by type
|
|
for ptype, expected_count in types_count.items():
|
|
result = await db_session.execute(
|
|
select(func.count()).where(
|
|
Portfolio.user_id == test_user.id,
|
|
Portfolio.portfolio_type == ptype
|
|
)
|
|
)
|
|
count = result.scalar()
|
|
assert count == expected_count
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_filter_portfolios_by_value_range(self, db_session, test_user):
|
|
"""Should filter portfolios by current value range."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
# Create portfolios with different values
|
|
portfolios_data = [
|
|
("Small", Decimal("1000.0000")),
|
|
("Medium", Decimal("25000.0000")),
|
|
("Large", Decimal("100000.0000")),
|
|
]
|
|
|
|
for name, capital in portfolios_data:
|
|
portfolio = Portfolio(
|
|
user_id=test_user.id,
|
|
name=name,
|
|
portfolio_type=PortfolioType.PAPER,
|
|
initial_capital=capital,
|
|
current_value=capital,
|
|
)
|
|
db_session.add(portfolio)
|
|
|
|
await db_session.commit()
|
|
|
|
# Query portfolios with value between 10k and 50k
|
|
result = await db_session.execute(
|
|
select(Portfolio).where(
|
|
Portfolio.user_id == test_user.id,
|
|
Portfolio.current_value >= Decimal("10000.0000"),
|
|
Portfolio.current_value <= Decimal("50000.0000")
|
|
)
|
|
)
|
|
filtered = result.scalars().all()
|
|
|
|
assert len(filtered) == 1
|
|
assert filtered[0].name == "Medium"
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_order_portfolios_by_value(self, db_session, test_user):
|
|
"""Should order portfolios by current value."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
# Create portfolios
|
|
portfolios_data = [
|
|
("Portfolio A", Decimal("50000.0000")),
|
|
("Portfolio B", Decimal("10000.0000")),
|
|
("Portfolio C", Decimal("25000.0000")),
|
|
]
|
|
|
|
for name, capital in portfolios_data:
|
|
portfolio = Portfolio(
|
|
user_id=test_user.id,
|
|
name=name,
|
|
portfolio_type=PortfolioType.PAPER,
|
|
initial_capital=capital,
|
|
current_value=capital,
|
|
)
|
|
db_session.add(portfolio)
|
|
|
|
await db_session.commit()
|
|
|
|
# Query ordered by value descending
|
|
result = await db_session.execute(
|
|
select(Portfolio)
|
|
.where(Portfolio.user_id == test_user.id)
|
|
.order_by(Portfolio.current_value.desc())
|
|
)
|
|
ordered = result.scalars().all()
|
|
|
|
assert len(ordered) == 3
|
|
assert ordered[0].name == "Portfolio A"
|
|
assert ordered[1].name == "Portfolio C"
|
|
assert ordered[2].name == "Portfolio B"
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
|
|
class TestPortfolioMultiCurrency:
|
|
"""Integration tests for multi-currency portfolio scenarios."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_portfolios_in_different_currencies(self, db_session, test_user):
|
|
"""Should support portfolios in different currencies."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
currencies = ["USD", "EUR", "GBP", "JPY", "AUD"]
|
|
|
|
for currency in currencies:
|
|
portfolio = Portfolio(
|
|
user_id=test_user.id,
|
|
name=f"{currency} Portfolio",
|
|
portfolio_type=PortfolioType.PAPER,
|
|
initial_capital=Decimal("10000.0000"),
|
|
currency=currency,
|
|
)
|
|
db_session.add(portfolio)
|
|
|
|
await db_session.commit()
|
|
|
|
# Query portfolios by currency
|
|
for currency in currencies:
|
|
result = await db_session.execute(
|
|
select(Portfolio).where(
|
|
Portfolio.user_id == test_user.id,
|
|
Portfolio.currency == currency
|
|
)
|
|
)
|
|
found = result.scalar_one()
|
|
assert found.currency == currency
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_group_portfolios_by_currency(self, db_session, test_user):
|
|
"""Should group and count portfolios by currency."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
# Create portfolios with different currencies
|
|
currency_data = [
|
|
("USD", 3),
|
|
("EUR", 2),
|
|
("AUD", 1),
|
|
]
|
|
|
|
for currency, count in currency_data:
|
|
for i in range(count):
|
|
portfolio = Portfolio(
|
|
user_id=test_user.id,
|
|
name=f"{currency} Portfolio {i}",
|
|
portfolio_type=PortfolioType.PAPER,
|
|
initial_capital=Decimal("10000.0000"),
|
|
currency=currency,
|
|
)
|
|
db_session.add(portfolio)
|
|
|
|
await db_session.commit()
|
|
|
|
# Count by currency
|
|
for currency, expected_count in currency_data:
|
|
result = await db_session.execute(
|
|
select(func.count()).where(
|
|
Portfolio.user_id == test_user.id,
|
|
Portfolio.currency == currency
|
|
)
|
|
)
|
|
count = result.scalar()
|
|
assert count == expected_count
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
|
|
class TestPortfolioLifecycle:
|
|
"""Integration tests for portfolio lifecycle management."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_portfolio_creation_to_deletion_lifecycle(self, db_session, test_user):
|
|
"""Should support full lifecycle: create, update, deactivate, delete."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
# 1. Create
|
|
portfolio = Portfolio(
|
|
user_id=test_user.id,
|
|
name="Lifecycle Test",
|
|
portfolio_type=PortfolioType.PAPER,
|
|
initial_capital=Decimal("10000.0000"),
|
|
)
|
|
|
|
db_session.add(portfolio)
|
|
await db_session.commit()
|
|
await db_session.refresh(portfolio)
|
|
|
|
portfolio_id = portfolio.id
|
|
assert portfolio.is_active is True
|
|
|
|
# 2. Update value
|
|
portfolio.current_value = Decimal("12000.0000")
|
|
await db_session.commit()
|
|
await db_session.refresh(portfolio)
|
|
|
|
assert portfolio.current_value == Decimal("12000.0000")
|
|
|
|
# 3. Deactivate
|
|
portfolio.is_active = False
|
|
await db_session.commit()
|
|
await db_session.refresh(portfolio)
|
|
|
|
assert portfolio.is_active is False
|
|
|
|
# 4. Delete
|
|
await db_session.delete(portfolio)
|
|
await db_session.commit()
|
|
|
|
# Verify deleted
|
|
result = await db_session.execute(
|
|
select(Portfolio).where(Portfolio.id == portfolio_id)
|
|
)
|
|
deleted = result.scalar_one_or_none()
|
|
|
|
assert deleted is None
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_reactivate_deactivated_portfolio(self, db_session, test_user):
|
|
"""Should allow reactivating a deactivated portfolio."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
portfolio = Portfolio(
|
|
user_id=test_user.id,
|
|
name="Reactivation Test",
|
|
portfolio_type=PortfolioType.PAPER,
|
|
initial_capital=Decimal("10000.0000"),
|
|
is_active=False,
|
|
)
|
|
|
|
db_session.add(portfolio)
|
|
await db_session.commit()
|
|
await db_session.refresh(portfolio)
|
|
|
|
assert portfolio.is_active is False
|
|
|
|
# Reactivate
|
|
portfolio.is_active = True
|
|
await db_session.commit()
|
|
await db_session.refresh(portfolio)
|
|
|
|
assert portfolio.is_active is True
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_migrate_portfolio_type(self, db_session, test_user):
|
|
"""Should allow changing portfolio type (e.g., PAPER to LIVE)."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
portfolio = Portfolio(
|
|
user_id=test_user.id,
|
|
name="Migration Test",
|
|
portfolio_type=PortfolioType.PAPER,
|
|
initial_capital=Decimal("10000.0000"),
|
|
)
|
|
|
|
db_session.add(portfolio)
|
|
await db_session.commit()
|
|
await db_session.refresh(portfolio)
|
|
|
|
assert portfolio.portfolio_type == PortfolioType.PAPER
|
|
|
|
# Migrate to LIVE
|
|
portfolio.portfolio_type = PortfolioType.LIVE
|
|
await db_session.commit()
|
|
await db_session.refresh(portfolio)
|
|
|
|
assert portfolio.portfolio_type == PortfolioType.LIVE
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
|
|
class TestPortfolioConcurrency:
|
|
"""Integration tests for concurrent portfolio operations."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_concurrent_value_updates(self, db_session, test_user):
|
|
"""Should handle concurrent updates to portfolio value."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
portfolio = Portfolio(
|
|
user_id=test_user.id,
|
|
name="Concurrency Test",
|
|
portfolio_type=PortfolioType.LIVE,
|
|
initial_capital=Decimal("10000.0000"),
|
|
)
|
|
|
|
db_session.add(portfolio)
|
|
await db_session.commit()
|
|
await db_session.refresh(portfolio)
|
|
|
|
# Simulate concurrent updates
|
|
updates = [
|
|
Decimal("10500.0000"),
|
|
Decimal("11000.0000"),
|
|
Decimal("10750.0000"),
|
|
]
|
|
|
|
for new_value in updates:
|
|
portfolio.current_value = new_value
|
|
await db_session.commit()
|
|
await db_session.refresh(portfolio)
|
|
|
|
# Final value should be last update
|
|
assert portfolio.current_value == Decimal("10750.0000")
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_bulk_portfolio_creation(self, db_session, test_user):
|
|
"""Should handle bulk creation of multiple portfolios."""
|
|
try:
|
|
from tradingagents.api.models.portfolio import Portfolio, PortfolioType
|
|
|
|
# Create 10 portfolios in bulk
|
|
portfolios = []
|
|
for i in range(10):
|
|
portfolio = Portfolio(
|
|
user_id=test_user.id,
|
|
name=f"Bulk Portfolio {i}",
|
|
portfolio_type=PortfolioType.PAPER,
|
|
initial_capital=Decimal(f"{(i + 1) * 1000}.0000"),
|
|
)
|
|
portfolios.append(portfolio)
|
|
|
|
db_session.add_all(portfolios)
|
|
await db_session.commit()
|
|
|
|
# Verify all created
|
|
result = await db_session.execute(
|
|
select(func.count()).where(Portfolio.user_id == test_user.id)
|
|
)
|
|
count = result.scalar()
|
|
|
|
assert count == 10
|
|
|
|
except ImportError:
|
|
pytest.skip("Portfolio model not yet implemented (TDD RED phase)")
|