Refactor code for improved readability and consistency
CI / lint-test-build (push) Successful in 54s
CI / lint-test-build (push) Successful in 54s
- Cleaned up multiline statements and removed unnecessary line breaks in various files. - Ensured consistent formatting in function definitions and calls across the codebase. - Updated docstrings and comments for clarity where applicable. - Removed trailing newlines in module docstrings. - Enhanced logging statements for better clarity in maintenance tasks.
This commit is contained in:
@@ -1 +1 @@
|
||||
"""Integration tests for PostgreSQL schema and connectivity."""
|
||||
"""Integration tests for PostgreSQL schema and connectivity."""
|
||||
|
||||
@@ -11,13 +11,9 @@ import pathlib
|
||||
import pytest
|
||||
|
||||
|
||||
def pytest_ignore_collect(
|
||||
collection_path: pathlib.Path, config: pytest.Config
|
||||
) -> bool:
|
||||
def pytest_ignore_collect(collection_path: pathlib.Path, config: pytest.Config) -> bool:
|
||||
"""Skip integration tests unless --integration is passed."""
|
||||
if "integration" in str(collection_path) and not config.getoption(
|
||||
"--integration", False
|
||||
):
|
||||
if "integration" in str(collection_path) and not config.getoption("--integration", False):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@@ -42,9 +42,24 @@ async def test_metrics_calculator_summarizes_execution_data() -> None:
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9),
|
||||
($10, $11, $12, $13, $14, $15, $16, $17, $18)
|
||||
""",
|
||||
"trade-1", started, finished, "filled", 12.5, 10.0, 100.0, "USD->BTC->ETH->USD", 3,
|
||||
"trade-2", started_two, finished_two, "filled", -
|
||||
4.5, -2.0, 200.0, "USD->ETH->BTC->USD", 3,
|
||||
"trade-1",
|
||||
started,
|
||||
finished,
|
||||
"filled",
|
||||
12.5,
|
||||
10.0,
|
||||
100.0,
|
||||
"USD->BTC->ETH->USD",
|
||||
3,
|
||||
"trade-2",
|
||||
started_two,
|
||||
finished_two,
|
||||
"filled",
|
||||
-4.5,
|
||||
-2.0,
|
||||
200.0,
|
||||
"USD->ETH->BTC->USD",
|
||||
3,
|
||||
)
|
||||
await conn.execute(
|
||||
"""
|
||||
@@ -53,11 +68,24 @@ async def test_metrics_calculator_summarizes_execution_data() -> None:
|
||||
($7, $8, $9, $10, $11, $12),
|
||||
($13, $14, $15, $16, $17, $18)
|
||||
""",
|
||||
started, "USD->BTC->ETH->USD", 4.0, 3.0, 0.03, True,
|
||||
started_two, "USD->ETH->BTC->USD", 2.0, 1.0, 0.01, False,
|
||||
started_two +
|
||||
timedelta(
|
||||
seconds=30), "USD->BTC->ETH->USD", 5.0, 4.0, 0.04, True,
|
||||
started,
|
||||
"USD->BTC->ETH->USD",
|
||||
4.0,
|
||||
3.0,
|
||||
0.03,
|
||||
True,
|
||||
started_two,
|
||||
"USD->ETH->BTC->USD",
|
||||
2.0,
|
||||
1.0,
|
||||
0.01,
|
||||
False,
|
||||
started_two + timedelta(seconds=30),
|
||||
"USD->BTC->ETH->USD",
|
||||
5.0,
|
||||
4.0,
|
||||
0.04,
|
||||
True,
|
||||
)
|
||||
await conn.execute(
|
||||
"""
|
||||
@@ -67,8 +95,30 @@ async def test_metrics_calculator_summarizes_execution_data() -> None:
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12),
|
||||
($13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24)
|
||||
""",
|
||||
"trade-1", "order-1", 0, "BTC/USD", "buy", 2.0, 101, "closed", 2.0, 100.0, "{}", started,
|
||||
"trade-2", "order-2", 0, "ETH/USD", "sell", 4.0, 202, "closed", 3.0, 200.0, "{}", started_two,
|
||||
"trade-1",
|
||||
"order-1",
|
||||
0,
|
||||
"BTC/USD",
|
||||
"buy",
|
||||
2.0,
|
||||
101,
|
||||
"closed",
|
||||
2.0,
|
||||
100.0,
|
||||
"{}",
|
||||
started,
|
||||
"trade-2",
|
||||
"order-2",
|
||||
0,
|
||||
"ETH/USD",
|
||||
"sell",
|
||||
4.0,
|
||||
202,
|
||||
"closed",
|
||||
3.0,
|
||||
200.0,
|
||||
"{}",
|
||||
started_two,
|
||||
)
|
||||
|
||||
metrics = await MetricsCalculator(store).compute()
|
||||
|
||||
@@ -25,50 +25,116 @@ EXPECTED_TABLES: dict[str, list[str]] = {
|
||||
"schema_migrations": ["version", "applied_at"],
|
||||
"config_sections": ["id", "name", "description", "updated_at"],
|
||||
"config_settings": [
|
||||
"key", "section", "value_json", "value_type", "is_secret",
|
||||
"is_runtime_reloadable", "updated_at", "updated_by",
|
||||
"key",
|
||||
"section",
|
||||
"value_json",
|
||||
"value_type",
|
||||
"is_secret",
|
||||
"is_runtime_reloadable",
|
||||
"updated_at",
|
||||
"updated_by",
|
||||
],
|
||||
"config_pairings": [
|
||||
"id", "base_asset", "quote_asset", "enabled", "source",
|
||||
"created_at", "updated_at",
|
||||
"id",
|
||||
"base_asset",
|
||||
"quote_asset",
|
||||
"enabled",
|
||||
"source",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
],
|
||||
"config_backtesting_defaults": [
|
||||
"id", "starting_balances", "trade_capital", "min_profit_threshold",
|
||||
"slippage_bps", "execution_latency_ms", "fee_source",
|
||||
"id",
|
||||
"starting_balances",
|
||||
"trade_capital",
|
||||
"min_profit_threshold",
|
||||
"slippage_bps",
|
||||
"execution_latency_ms",
|
||||
"fee_source",
|
||||
],
|
||||
"opportunities": [
|
||||
"id", "detected_at", "cycle", "gross_pct", "net_pct",
|
||||
"est_profit", "executed",
|
||||
"id",
|
||||
"detected_at",
|
||||
"cycle",
|
||||
"gross_pct",
|
||||
"net_pct",
|
||||
"est_profit",
|
||||
"executed",
|
||||
],
|
||||
"trades": [
|
||||
"id", "trade_ref", "started_at", "finished_at", "status",
|
||||
"realized_pnl", "estimated_pnl", "capital_used", "cycle", "leg_count",
|
||||
"id",
|
||||
"trade_ref",
|
||||
"started_at",
|
||||
"finished_at",
|
||||
"status",
|
||||
"realized_pnl",
|
||||
"estimated_pnl",
|
||||
"capital_used",
|
||||
"cycle",
|
||||
"leg_count",
|
||||
],
|
||||
"orders": [
|
||||
"id", "trade_ref", "order_ref", "leg_index", "pair", "side",
|
||||
"volume", "user_ref", "status", "filled_volume", "avg_price",
|
||||
"raw_response", "recorded_at",
|
||||
"id",
|
||||
"trade_ref",
|
||||
"order_ref",
|
||||
"leg_index",
|
||||
"pair",
|
||||
"side",
|
||||
"volume",
|
||||
"user_ref",
|
||||
"status",
|
||||
"filled_volume",
|
||||
"avg_price",
|
||||
"raw_response",
|
||||
"recorded_at",
|
||||
],
|
||||
"pnl_events": [
|
||||
"id", "trade_ref", "recorded_at", "kind", "pnl_usd", "source",
|
||||
"id",
|
||||
"trade_ref",
|
||||
"recorded_at",
|
||||
"kind",
|
||||
"pnl_usd",
|
||||
"source",
|
||||
],
|
||||
"portfolio_snapshots": ["snapshot_at", "balances", "total_value_usd"],
|
||||
"market_snapshots": ["snapshot_at", "symbol", "source", "payload", "latency_ms"],
|
||||
"audit_events": [
|
||||
"id", "occurred_at", "actor", "event_type", "decision",
|
||||
"payload", "correlation_id",
|
||||
"id",
|
||||
"occurred_at",
|
||||
"actor",
|
||||
"event_type",
|
||||
"decision",
|
||||
"payload",
|
||||
"correlation_id",
|
||||
],
|
||||
"runtime_state_snapshots": [
|
||||
"snapshot_at", "is_running", "kill_switch_active", "kill_switch_reason",
|
||||
"open_trade_count", "last_known_balances", "note",
|
||||
"snapshot_at",
|
||||
"is_running",
|
||||
"kill_switch_active",
|
||||
"kill_switch_reason",
|
||||
"open_trade_count",
|
||||
"last_known_balances",
|
||||
"note",
|
||||
],
|
||||
"kraken_account_snapshots": [
|
||||
"snapshot_at", "fee_tier", "maker_fee", "taker_fee",
|
||||
"thirty_day_volume", "trade_balance_raw", "fee_schedule_raw",
|
||||
"snapshot_at",
|
||||
"fee_tier",
|
||||
"maker_fee",
|
||||
"taker_fee",
|
||||
"thirty_day_volume",
|
||||
"trade_balance_raw",
|
||||
"fee_schedule_raw",
|
||||
],
|
||||
"backtest_jobs": [
|
||||
"id", "status", "events_path", "config", "report", "error",
|
||||
"created_at", "started_at", "finished_at",
|
||||
"id",
|
||||
"status",
|
||||
"events_path",
|
||||
"config",
|
||||
"report",
|
||||
"error",
|
||||
"created_at",
|
||||
"started_at",
|
||||
"finished_at",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -96,6 +162,7 @@ TABLES_WITH_UNIQUE_CONSTRAINTS: dict[str, list[str]] = {
|
||||
|
||||
# ── fixtures ────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def _pg_lifecycle() -> AsyncIterator[PgStore]:
|
||||
"""Connect, yield store, then disconnect."""
|
||||
@@ -116,6 +183,7 @@ async def pg_fixture() -> AsyncIterator[PgStore]:
|
||||
|
||||
# ── helpers ─────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
async def _get_actual_tables(store: PgStore) -> dict[str, list[str]]:
|
||||
"""Return {table_name: [column_name, ...]} for the public schema."""
|
||||
actual: dict[str, list[str]] = {}
|
||||
@@ -139,6 +207,7 @@ async def _table_row_count(store: PgStore, table: str) -> int:
|
||||
|
||||
# ── tests ───────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pg_connect(pg: PgStore) -> None:
|
||||
"""Can connect to PostgreSQL and ping the server."""
|
||||
@@ -165,8 +234,7 @@ async def test_schema_migration_applies(pg: PgStore) -> None:
|
||||
|
||||
for table in EXPECTED_TABLES:
|
||||
assert table in actual, (
|
||||
f"Table '{table}' missing after migration. "
|
||||
f"Found tables: {sorted(actual)}"
|
||||
f"Table '{table}' missing after migration. " f"Found tables: {sorted(actual)}"
|
||||
)
|
||||
|
||||
|
||||
@@ -190,8 +258,7 @@ async def test_table_columns(pg: PgStore) -> None:
|
||||
actual_cols = actual.get(table, [])
|
||||
for col in expected_cols:
|
||||
assert col in actual_cols, (
|
||||
f"Column '{col}' missing from table '{table}'. "
|
||||
f"Actual columns: {actual_cols}"
|
||||
f"Column '{col}' missing from table '{table}'. " f"Actual columns: {actual_cols}"
|
||||
)
|
||||
|
||||
|
||||
@@ -250,8 +317,7 @@ async def test_table_row_count_is_zero(pg: PgStore) -> None:
|
||||
for table in EXPECTED_TABLES:
|
||||
count = await _table_row_count(pg, table)
|
||||
assert count == 0, (
|
||||
f"Table '{table}' should be empty after migration, "
|
||||
f"but has {count} rows"
|
||||
f"Table '{table}' should be empty after migration, " f"but has {count} rows"
|
||||
)
|
||||
|
||||
|
||||
@@ -262,13 +328,10 @@ async def test_schema_migration_version_recorded(pg: PgStore) -> None:
|
||||
|
||||
await pg.migrate()
|
||||
async with pg.pool.acquire() as conn:
|
||||
row = await conn.fetchrow(
|
||||
"SELECT MAX(version) AS v FROM schema_migrations"
|
||||
)
|
||||
row = await conn.fetchrow("SELECT MAX(version) AS v FROM schema_migrations")
|
||||
assert row is not None
|
||||
assert row["v"] == SCHEMA_VERSION, (
|
||||
f"Expected schema version {SCHEMA_VERSION}, "
|
||||
f"got {row['v']}"
|
||||
f"Expected schema version {SCHEMA_VERSION}, " f"got {row['v']}"
|
||||
)
|
||||
|
||||
|
||||
@@ -280,7 +343,8 @@ async def test_create_and_query_row(pg: PgStore) -> None:
|
||||
# ConfigSections round-trip
|
||||
await conn.execute(
|
||||
"INSERT INTO config_sections (name, description) VALUES ($1, $2)",
|
||||
"test_section", "A test section for integration test",
|
||||
"test_section",
|
||||
"A test section for integration test",
|
||||
)
|
||||
row = await conn.fetchrow(
|
||||
"SELECT name, description FROM config_sections WHERE name = $1",
|
||||
@@ -357,4 +421,4 @@ async def test_audit_list_recent(pg: PgStore) -> None:
|
||||
# Verify payload serialization worked
|
||||
first = recent[0]
|
||||
if first.payload:
|
||||
assert "index" in first.payload
|
||||
assert "index" in first.payload
|
||||
|
||||
@@ -39,8 +39,7 @@ async def test_end_to_end_config_workflow():
|
||||
# Mock the setting creation
|
||||
mock_created_setting = Mock()
|
||||
mock_created_setting.updated_at = "2023-01-01T00:00:00"
|
||||
mock_repo_instance.create_setting = AsyncMock(
|
||||
return_value=mock_created_setting)
|
||||
mock_repo_instance.create_setting = AsyncMock(return_value=mock_created_setting)
|
||||
mock_repo_instance.get_setting = AsyncMock(return_value=None)
|
||||
mock_repo_instance.get_latest_updated_at = AsyncMock(return_value=None)
|
||||
mock_repo_instance.list_settings = AsyncMock(return_value=[])
|
||||
|
||||
@@ -136,10 +136,8 @@ async def test_config_setting_repository_list_settings(mock_store):
|
||||
repo = ConfigSettingRepository(mock_store)
|
||||
conn = await mock_store.pool.acquire().__aenter__()
|
||||
|
||||
row1 = _make_row({**SETTING_ROW, "key": "test_key1",
|
||||
"value_json": "test_value1"})
|
||||
row2 = _make_row({**SETTING_ROW, "key": "test_key2",
|
||||
"value_json": "test_value2"})
|
||||
row1 = _make_row({**SETTING_ROW, "key": "test_key1", "value_json": "test_value1"})
|
||||
row2 = _make_row({**SETTING_ROW, "key": "test_key2", "value_json": "test_value2"})
|
||||
conn.fetch = AsyncMock(return_value=[row1, row2])
|
||||
|
||||
result = await repo.list_settings()
|
||||
@@ -176,9 +174,7 @@ async def test_config_pairing_repository_create_pairing(mock_store):
|
||||
conn = await mock_store.pool.acquire().__aenter__()
|
||||
conn.fetchrow = AsyncMock(return_value=_make_row(PAIRING_ROW))
|
||||
|
||||
pairing = ConfigPairing(
|
||||
base_asset="BTC", quote_asset="USD", enabled=True, source="Kraken"
|
||||
)
|
||||
pairing = ConfigPairing(base_asset="BTC", quote_asset="USD", enabled=True, source="Kraken")
|
||||
|
||||
result = await repo.create_pairing(pairing)
|
||||
|
||||
|
||||
@@ -63,8 +63,7 @@ async def test_configuration_service_set_setting(mock_settings, mock_store, mock
|
||||
|
||||
mock_created_setting = Mock()
|
||||
mock_created_setting.updated_at = "2023-01-01T00:00:00"
|
||||
mock_repo_instance.create_setting = AsyncMock(
|
||||
return_value=mock_created_setting)
|
||||
mock_repo_instance.create_setting = AsyncMock(return_value=mock_created_setting)
|
||||
mock_repo_instance.get_setting = AsyncMock(return_value=None)
|
||||
|
||||
await service.set_setting("test_key", "test_value", "test_user")
|
||||
@@ -73,7 +72,9 @@ async def test_configuration_service_set_setting(mock_settings, mock_store, mock
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_configuration_service_hot_reload_detection(mock_settings, mock_store, mock_audit_repo):
|
||||
async def test_configuration_service_hot_reload_detection(
|
||||
mock_settings, mock_store, mock_audit_repo
|
||||
):
|
||||
"""Test hot-reload detection functionality."""
|
||||
service = ConfigurationService(mock_settings, mock_store, mock_audit_repo)
|
||||
|
||||
@@ -86,8 +87,7 @@ async def test_configuration_service_hot_reload_detection(mock_settings, mock_st
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
mock_repo_instance.get_latest_updated_at = AsyncMock(
|
||||
return_value=datetime.now())
|
||||
mock_repo_instance.get_latest_updated_at = AsyncMock(return_value=datetime.now())
|
||||
assert await service.is_config_outdated() is True
|
||||
|
||||
|
||||
@@ -105,8 +105,7 @@ async def test_configuration_service_reload_if_changed(mock_settings, mock_store
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
mock_repo_instance.get_latest_updated_at = AsyncMock(
|
||||
return_value=datetime.now())
|
||||
mock_repo_instance.get_latest_updated_at = AsyncMock(return_value=datetime.now())
|
||||
|
||||
result = await service.reload_if_changed()
|
||||
assert result is True
|
||||
@@ -125,8 +124,7 @@ async def test_configuration_service_get_config_version(mock_settings, mock_stor
|
||||
|
||||
mock_created_setting = Mock()
|
||||
mock_created_setting.updated_at = "2023-01-01T00:00:00"
|
||||
mock_repo_instance.create_setting = AsyncMock(
|
||||
return_value=mock_created_setting)
|
||||
mock_repo_instance.create_setting = AsyncMock(return_value=mock_created_setting)
|
||||
mock_repo_instance.get_setting = AsyncMock(return_value=None)
|
||||
|
||||
await service.set_setting("test_key", "test_value", "test_user")
|
||||
@@ -134,7 +132,9 @@ async def test_configuration_service_get_config_version(mock_settings, mock_stor
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_configuration_service_get_last_updated_at(mock_settings, mock_store, mock_audit_repo):
|
||||
async def test_configuration_service_get_last_updated_at(
|
||||
mock_settings, mock_store, mock_audit_repo
|
||||
):
|
||||
"""Test getting last updated timestamp."""
|
||||
service = ConfigurationService(mock_settings, mock_store, mock_audit_repo)
|
||||
assert service.get_last_updated_at() is None
|
||||
@@ -145,8 +145,7 @@ async def test_configuration_service_get_last_updated_at(mock_settings, mock_sto
|
||||
|
||||
mock_created_setting = Mock()
|
||||
mock_created_setting.updated_at = "2023-01-01T00:00:00"
|
||||
mock_repo_instance.create_setting = AsyncMock(
|
||||
return_value=mock_created_setting)
|
||||
mock_repo_instance.create_setting = AsyncMock(return_value=mock_created_setting)
|
||||
mock_repo_instance.get_setting = AsyncMock(return_value=None)
|
||||
|
||||
await service.set_setting("test_key", "test_value", "test_user")
|
||||
|
||||
@@ -49,9 +49,7 @@ def _mock_pg_store():
|
||||
@pytest.fixture
|
||||
def app():
|
||||
"""Create a test app with a mocked PgStore and audit repository."""
|
||||
a = create_app(
|
||||
Settings(_env_file=None, APP_MODE="paper", paper_trading_mode=True)
|
||||
)
|
||||
a = create_app(Settings(_env_file=None, APP_MODE="paper", paper_trading_mode=True))
|
||||
a.state.store = _mock_pg_store()
|
||||
a.state.runtime_state_repository.insert = AsyncMock()
|
||||
a.state.runtime_state_repository.latest = AsyncMock(return_value=None)
|
||||
@@ -69,16 +67,14 @@ async def test_persist_runtime_snapshot_writes_record(app) -> None:
|
||||
|
||||
# Mock _open_trade_count → 0, _latest_balances → None
|
||||
conn = await app.state.store.pool.acquire().__aenter__()
|
||||
conn.fetchrow = AsyncMock(return_value=MagicMock(
|
||||
**{"__getitem__": lambda s, k: 0}))
|
||||
conn.fetchrow = AsyncMock(return_value=MagicMock(**{"__getitem__": lambda s, k: 0}))
|
||||
|
||||
snapshot = await persist_runtime_snapshot(app, note="unit-test")
|
||||
|
||||
assert snapshot is not None
|
||||
assert snapshot.note == "unit-test"
|
||||
|
||||
app.state.runtime_state_repository.latest = AsyncMock(
|
||||
return_value=snapshot)
|
||||
app.state.runtime_state_repository.latest = AsyncMock(return_value=snapshot)
|
||||
latest = await app.state.runtime_state_repository.latest()
|
||||
assert latest is not None
|
||||
assert latest.note == "unit-test"
|
||||
|
||||
Reference in New Issue
Block a user