summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/tests/test_cli_backtest.py19
-rw-r--r--cli/tests/test_cli_portfolio.py16
-rw-r--r--cli/tests/test_cli_service.py22
-rw-r--r--cli/tests/test_cli_strategy.py47
-rw-r--r--services/api/tests/test_orders_router.py54
-rw-r--r--services/api/tests/test_portfolio_router.py73
6 files changed, 231 insertions, 0 deletions
diff --git a/cli/tests/test_cli_backtest.py b/cli/tests/test_cli_backtest.py
new file mode 100644
index 0000000..84227a9
--- /dev/null
+++ b/cli/tests/test_cli_backtest.py
@@ -0,0 +1,19 @@
+"""Tests for backtest CLI commands."""
+from click.testing import CliRunner
+from trading_cli.main import cli
+
+
+def test_backtest_run_help():
+ runner = CliRunner()
+ result = runner.invoke(cli, ["backtest", "run", "--help"])
+ assert result.exit_code == 0
+ assert "--strategy" in result.output
+ assert "--symbol" in result.output
+ assert "--balance" in result.output
+
+
+def test_backtest_report_help():
+ runner = CliRunner()
+ result = runner.invoke(cli, ["backtest", "report", "--help"])
+ assert result.exit_code == 0
+ assert "--id" in result.output
diff --git a/cli/tests/test_cli_portfolio.py b/cli/tests/test_cli_portfolio.py
new file mode 100644
index 0000000..351b49f
--- /dev/null
+++ b/cli/tests/test_cli_portfolio.py
@@ -0,0 +1,16 @@
+"""Tests for portfolio CLI commands."""
+from click.testing import CliRunner
+from trading_cli.main import cli
+
+
+def test_portfolio_show_help():
+ runner = CliRunner()
+ result = runner.invoke(cli, ["portfolio", "show", "--help"])
+ assert result.exit_code == 0
+
+
+def test_portfolio_history_help():
+ runner = CliRunner()
+ result = runner.invoke(cli, ["portfolio", "history", "--help"])
+ assert result.exit_code == 0
+ assert "--days" in result.output
diff --git a/cli/tests/test_cli_service.py b/cli/tests/test_cli_service.py
new file mode 100644
index 0000000..08cd396
--- /dev/null
+++ b/cli/tests/test_cli_service.py
@@ -0,0 +1,22 @@
+"""Tests for service CLI commands."""
+from click.testing import CliRunner
+from trading_cli.main import cli
+
+
+def test_service_up_help():
+ runner = CliRunner()
+ result = runner.invoke(cli, ["service", "up", "--help"])
+ assert result.exit_code == 0
+
+
+def test_service_down_help():
+ runner = CliRunner()
+ result = runner.invoke(cli, ["service", "down", "--help"])
+ assert result.exit_code == 0
+
+
+def test_service_logs_help():
+ runner = CliRunner()
+ result = runner.invoke(cli, ["service", "logs", "--help"])
+ assert result.exit_code == 0
+ assert "--name" in result.output
diff --git a/cli/tests/test_cli_strategy.py b/cli/tests/test_cli_strategy.py
new file mode 100644
index 0000000..3c89477
--- /dev/null
+++ b/cli/tests/test_cli_strategy.py
@@ -0,0 +1,47 @@
+"""Tests for strategy CLI commands."""
+from unittest.mock import patch, MagicMock
+from click.testing import CliRunner
+from trading_cli.main import cli
+
+
+def _make_mock_strategy(name, warmup_period=14):
+ s = MagicMock()
+ s.name = name
+ s.warmup_period = warmup_period
+ type(s).__name__ = "MockStrategy"
+ return s
+
+
+def test_strategy_list():
+ mock_strategies = [_make_mock_strategy("rsi"), _make_mock_strategy("macd", 26)]
+ with patch("trading_cli.commands.strategy._load_all_strategies", return_value=mock_strategies):
+ runner = CliRunner()
+ result = runner.invoke(cli, ["strategy", "list"])
+ assert result.exit_code == 0
+ assert "rsi" in result.output.lower() or "Strategy" in result.output
+
+
+def test_strategy_list_empty():
+ with patch("trading_cli.commands.strategy._load_all_strategies", return_value=[]):
+ runner = CliRunner()
+ result = runner.invoke(cli, ["strategy", "list"])
+ assert result.exit_code == 0
+ assert "No strategies found" in result.output
+
+
+def test_strategy_info_rsi():
+ mock_strategies = [_make_mock_strategy("rsi")]
+ with patch("trading_cli.commands.strategy._load_all_strategies", return_value=mock_strategies):
+ runner = CliRunner()
+ result = runner.invoke(cli, ["strategy", "info", "--name", "rsi"])
+ assert result.exit_code == 0
+ assert "rsi" in result.output.lower()
+
+
+def test_strategy_info_unknown():
+ mock_strategies = [_make_mock_strategy("rsi")]
+ with patch("trading_cli.commands.strategy._load_all_strategies", return_value=mock_strategies):
+ runner = CliRunner()
+ result = runner.invoke(cli, ["strategy", "info", "--name", "nonexistent"])
+ # Should handle gracefully (exit 0 or 1 with message)
+ assert "not found" in result.output.lower() or result.exit_code != 0 or "nonexistent" in result.output
diff --git a/services/api/tests/test_orders_router.py b/services/api/tests/test_orders_router.py
new file mode 100644
index 0000000..899fb27
--- /dev/null
+++ b/services/api/tests/test_orders_router.py
@@ -0,0 +1,54 @@
+"""Tests for orders API router."""
+import pytest
+from decimal import Decimal
+from datetime import datetime, timezone
+from unittest.mock import AsyncMock, MagicMock
+from fastapi.testclient import TestClient
+from fastapi import FastAPI
+
+from trading_api.routers.orders import router
+
+
+@pytest.fixture
+def app():
+ app = FastAPI()
+ app.include_router(router, prefix="/orders")
+ return app
+
+
+@pytest.fixture
+def mock_db():
+ db = AsyncMock()
+ mock_session = AsyncMock()
+ mock_session.__aenter__ = AsyncMock(return_value=mock_session)
+ mock_session.__aexit__ = AsyncMock(return_value=False)
+ db.get_session = MagicMock(return_value=mock_session)
+ return db, mock_session
+
+
+def test_get_orders_empty(app, mock_db):
+ db, session = mock_db
+ app.state.db = db
+
+ mock_result = MagicMock()
+ mock_result.scalars.return_value.all.return_value = []
+ session.execute = AsyncMock(return_value=mock_result)
+
+ client = TestClient(app)
+ response = client.get("/orders/")
+ assert response.status_code == 200
+ assert response.json() == []
+
+
+def test_get_signals_empty(app, mock_db):
+ db, session = mock_db
+ app.state.db = db
+
+ mock_result = MagicMock()
+ mock_result.scalars.return_value.all.return_value = []
+ session.execute = AsyncMock(return_value=mock_result)
+
+ client = TestClient(app)
+ response = client.get("/orders/signals")
+ assert response.status_code == 200
+ assert response.json() == []
diff --git a/services/api/tests/test_portfolio_router.py b/services/api/tests/test_portfolio_router.py
new file mode 100644
index 0000000..0993923
--- /dev/null
+++ b/services/api/tests/test_portfolio_router.py
@@ -0,0 +1,73 @@
+"""Tests for portfolio API router."""
+import pytest
+from decimal import Decimal
+from datetime import datetime, timezone
+from unittest.mock import AsyncMock, MagicMock, patch
+from fastapi.testclient import TestClient
+from fastapi import FastAPI
+
+from trading_api.routers.portfolio import router
+
+
+@pytest.fixture
+def app():
+ app = FastAPI()
+ app.include_router(router, prefix="/portfolio")
+ return app
+
+
+@pytest.fixture
+def mock_db():
+ db = AsyncMock()
+ mock_session = AsyncMock()
+ mock_session.__aenter__ = AsyncMock(return_value=mock_session)
+ mock_session.__aexit__ = AsyncMock(return_value=False)
+ db.get_session = MagicMock(return_value=mock_session)
+ return db, mock_session
+
+
+def test_get_positions_empty(app, mock_db):
+ db, session = mock_db
+ app.state.db = db
+
+ mock_result = MagicMock()
+ mock_result.scalars.return_value.all.return_value = []
+ session.execute = AsyncMock(return_value=mock_result)
+
+ client = TestClient(app)
+ response = client.get("/portfolio/positions")
+ assert response.status_code == 200
+ assert response.json() == []
+
+
+def test_get_positions_with_data(app, mock_db):
+ db, session = mock_db
+ app.state.db = db
+
+ mock_row = MagicMock()
+ mock_row.symbol = "BTCUSDT"
+ mock_row.quantity = Decimal("0.1")
+ mock_row.avg_entry_price = Decimal("50000")
+ mock_row.current_price = Decimal("55000")
+
+ mock_result = MagicMock()
+ mock_result.scalars.return_value.all.return_value = [mock_row]
+ session.execute = AsyncMock(return_value=mock_result)
+
+ client = TestClient(app)
+ response = client.get("/portfolio/positions")
+ assert response.status_code == 200
+ data = response.json()
+ assert len(data) == 1
+ assert data[0]["symbol"] == "BTCUSDT"
+
+
+def test_get_snapshots_empty(app, mock_db):
+ db, _ = mock_db
+ app.state.db = db
+ db.get_portfolio_snapshots = AsyncMock(return_value=[])
+
+ client = TestClient(app)
+ response = client.get("/portfolio/snapshots")
+ assert response.status_code == 200
+ assert response.json() == []