Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,4 @@ jobs:
- name: Run unit tests
run: |
set -euo pipefail
PYTHONPATH=. PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run --no-sync python -m pytest -q tests --ignore=tests/test_request_handling.py --ignore=tests/test_event_loop.py --ignore=tests/test_monitor_dispatcher.py --ignore=tests/test_notifications.py --ignore=tests/test_connect_timeout_alert.py || true
PYTHONPATH=. PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run --no-sync python -m pytest -q tests --ignore=tests/test_request_handling.py --ignore=tests/test_event_loop.py --ignore=tests/test_monitor_dispatcher.py --ignore=tests/test_notifications.py --ignore=tests/test_connect_timeout_alert.py
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Local test package to prevent third-party ``tests`` namespace shadowing."""
27 changes: 27 additions & 0 deletions tests/test_ci_unit_test_contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import re
from pathlib import Path


_LEGACY_FULL_SUITE_COMMAND = (
"PYTHONPATH=. PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run --no-sync python -m pytest -q tests "
"--ignore=tests/test_request_handling.py "
"--ignore=tests/test_event_loop.py "
"--ignore=tests/test_monitor_dispatcher.py "
"--ignore=tests/test_notifications.py "
"--ignore=tests/test_connect_timeout_alert.py"
)


def test_ci_runs_unsuppressed_legacy_full_suite() -> None:
workflow = Path(".github/workflows/ci.yml").read_text(encoding="utf-8")
match = re.search(
r"^ - name: Run unit tests\n(?P<block>.*)\Z",
workflow,
flags=re.MULTILINE | re.DOTALL,
)

assert match is not None
step = match.group("block")
assert _LEGACY_FULL_SUITE_COMMAND in step
assert "|| true" not in step
assert "continue-on-error" not in step
3 changes: 2 additions & 1 deletion tests/test_execution_report_heartbeat.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,7 @@ def test_main_rejects_previous_session_report_after_a_new_session_is_due(
):
_clear_runtime_env(monkeypatch)
monkeypatch.setenv("RUNTIME_HEARTBEAT_NAME", "IBKR US runtime")
monkeypatch.setenv("NOTIFY_LANG", "en")
monkeypatch.setenv("RUNTIME_HEARTBEAT_REQUIRED_SERVICES", "svc-us")
monkeypatch.setenv("RUNTIME_HEARTBEAT_GCS_URIS", "gs://bucket/reports")
monkeypatch.setenv(
Expand Down Expand Up @@ -579,7 +580,7 @@ def test_main_rejects_previous_session_report_after_a_new_session_is_due(

assert result == 1
output = capsys.readouterr().out
assert "missing acceptable report for runtime target(s)" in output
assert "Missing acceptable execution report: svc-us" in output
assert "predates latest due schedule" in output


Expand Down
42 changes: 13 additions & 29 deletions tests/test_runtime_config_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@
"russell_top50_leader_rotation",
"soxl_soxx_trend_income",
"tqqq_growth_income",
"us_equity_combo",
"us_equity_combo_leveraged",
"hk_global_etf_tactical_rotation",
"hk_low_vol_dividend_quality_snapshot",
}
Expand Down Expand Up @@ -387,11 +385,11 @@ def test_runtime_target_service_name_overrides_shared_account_group_service(monk
monkeypatch.setenv(
"RUNTIME_TARGET_JSON",
runtime_target_json(
"us_equity_combo_leveraged",
"tqqq_growth_income",
dry_run_only=True,
deployment_selector="us-combo-shadow",
account_scope="us-combo-shadow",
service_name="interactive-brokers-us-combo-shadow-service",
deployment_selector="tqqq-shadow",
account_scope="tqqq-shadow",
service_name="interactive-brokers-tqqq-shadow-service",
),
)
monkeypatch.setenv("ACCOUNT_GROUP", "shared-live")
Expand All @@ -406,7 +404,7 @@ def test_runtime_target_service_name_overrides_shared_account_group_service(monk
settings = load_platform_runtime_settings(project_id_resolver=lambda: "project-1")

assert settings.account_group == "shared-live"
assert settings.service_name == "interactive-brokers-us-combo-shadow-service"
assert settings.service_name == "interactive-brokers-tqqq-shadow-service"


def test_load_platform_runtime_settings_derives_hk_market_from_account_group(monkeypatch):
Expand Down Expand Up @@ -881,7 +879,8 @@ def test_platform_profile_status_matrix_matches_current_ibkr_rollout():
assert by_profile["tqqq_growth_income"]["enabled"] is True
assert "nasdaq_sp500_smart_dca" in by_profile
assert "ibit_smart_dca" in by_profile
assert "us_equity_combo_core" not in by_profile
for profile in ("us_equity_combo", "us_equity_combo_core", "us_equity_combo_leveraged"):
assert profile not in by_profile
assert by_profile["hk_global_etf_tactical_rotation"] == {
"canonical_profile": "hk_global_etf_tactical_rotation",
"display_name": "HK Global ETF Tactical Rotation",
Expand Down Expand Up @@ -928,13 +927,8 @@ def test_print_strategy_profile_status_json_matches_registry():
assert by_profile["global_etf_rotation"]["requires_strategy_config_path"] is False
assert "nasdaq_sp500_smart_dca" in by_profile
assert "ibit_smart_dca" in by_profile
assert by_profile["us_equity_combo"]["profile_group"] == "direct_runtime_inputs"
assert by_profile["us_equity_combo"]["input_mode"] == "current_holdings+russell_snapshot"
assert by_profile["us_equity_combo"]["requires_strategy_config_path"] is False
assert by_profile["us_equity_combo_leveraged"]["profile_group"] == "direct_runtime_inputs"
assert by_profile["us_equity_combo_leveraged"]["input_mode"] == "market_data"
assert by_profile["us_equity_combo_leveraged"]["requires_strategy_config_path"] is False
assert by_profile["us_equity_combo_leveraged"]["config_source_policy"] == "env_only"
for profile in ("us_equity_combo", "us_equity_combo_core", "us_equity_combo_leveraged"):
assert profile not in by_profile
assert "tech_communication_pullback_enhancement" not in by_profile
assert by_profile["russell_top50_leader_rotation"]["profile_group"] == "snapshot_backed"
assert by_profile["russell_top50_leader_rotation"]["display_name_zh"] == "罗素Top50领涨"
Expand Down Expand Up @@ -1028,26 +1022,16 @@ def test_print_strategy_switch_env_plan_for_tqqq_growth_income():
assert "IBKR_FEATURE_SNAPSHOT_PATH" in plan["remove_if_present"]


def test_print_strategy_switch_env_plan_keeps_optional_config_for_leveraged_combo_shadow():
def test_print_strategy_switch_env_plan_rejects_leveraged_combo_shadow():
result = subprocess.run(
[sys.executable, str(SWITCH_PLAN_SCRIPT_PATH), "--profile", "us_equity_combo_leveraged", "--json"],
check=True,
check=False,
capture_output=True,
text=True,
)

plan = json.loads(result.stdout)
assert plan["canonical_profile"] == "us_equity_combo_leveraged"
assert plan["profile_group"] == "direct_runtime_inputs"
assert plan["input_mode"] == "market_data"
assert plan["requires_strategy_config_path"] is False
assert plan["config_source_policy"] == "env_only"
assert "IBKR_STRATEGY_CONFIG_PATH" in plan["optional_env"]
assert "IBKR_STRATEGY_CONFIG_PATH" not in plan["remove_if_present"]
assert "IBKR_FEATURE_SNAPSHOT_PATH" in plan["remove_if_present"]
assert plan["hints"]["shadow_402040_strategy_config_path"].startswith(
"package://us_equity_strategies/"
)
assert result.returncode == 1
assert "Unsupported STRATEGY_PROFILE='us_equity_combo_leveraged'" in result.stderr


def test_print_strategy_switch_env_plan_for_hk_global_etf_dry_run():
Expand Down
5 changes: 4 additions & 1 deletion tests/test_runtime_monitor_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ def test_execution_report_heartbeat_has_market_neutral_daily_schedule() -> None:
assert "RUNTIME_HEARTBEAT_PUBLICATION_GRACE_MINUTES:" in workflow
assert "RUNTIME_HEARTBEAT_SCHEDULER_LOCATION:" in workflow
assert "CLOUD_SCHEDULER_MAIN_TIME:" in workflow
assert "pandas-market-calendars==5.4.0" in workflow
assert "astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78" in workflow
assert "uv sync --frozen --no-dev" in workflow
assert "uv run --no-sync python scripts/execution_report_heartbeat.py" in workflow
assert "python -m pip install" not in workflow


def test_runtime_monitor_workflows_retry_gcp_authentication() -> None:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_scheduler_deadline_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def test_disabled_target_gets_a_paused_canonical_precheck_before_legacy_cleanup(
workflow = WORKFLOW.read_text(encoding="utf-8")

ensure_precheck = workflow.index('if [ -n "${precheck_state}" ]; then')
enabled_state = workflow.index('case "${runtime_target_enabled}" in')
enabled_state = workflow.index('case "${standard_execution_enabled}" in')
pause_precheck = workflow.index('gcloud scheduler jobs pause "${managed_job_name}"')
retire_legacy = workflow.index('python3 scripts/reconcile_cloud_runtime.py "${reconcile_args[@]}"')

Expand Down
8 changes: 8 additions & 0 deletions tests/test_strategy_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,10 @@ def evaluate(self, ctx):

def test_value_target_runtime_builds_semiconductor_inputs(monkeypatch):
captured = {}
monkeypatch.setattr(
"quant_platform_kit.strategy_lifecycle.live_equity.resolve_consecutive_losses",
lambda **_kwargs: 0,
)

class FakeEntrypoint:
manifest = StrategyManifest(
Expand Down Expand Up @@ -1142,6 +1146,10 @@ def fake_loader(_ib, symbol, duration="2 Y", bar_size="1 day"):

def test_value_target_runtime_builds_tqqq_inputs(monkeypatch):
captured = {}
monkeypatch.setattr(
"quant_platform_kit.strategy_lifecycle.live_equity.resolve_consecutive_losses",
lambda **_kwargs: 0,
)

class FakeEntrypoint:
manifest = StrategyManifest(
Expand Down