From a397231b0e7ca71bda27303aacf0f87d86fe1886 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Thu, 3 Sep 2026 03:30:23 +0800 Subject: [PATCH] test: repair legacy suite baseline Co-Authored-By: Codex --- .github/workflows/ci.yml | 2 +- tests/__init__.py | 1 + tests/test_ci_unit_test_contract.py | 27 +++++++++++++++ tests/test_execution_report_heartbeat.py | 3 +- tests/test_runtime_config_support.py | 42 +++++++---------------- tests/test_runtime_monitor_workflows.py | 5 ++- tests/test_scheduler_deadline_contract.py | 2 +- tests/test_strategy_runtime.py | 8 +++++ 8 files changed, 57 insertions(+), 33 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/test_ci_unit_test_contract.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3a0f741..9f18031 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..5796f12 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +"""Local test package to prevent third-party ``tests`` namespace shadowing.""" diff --git a/tests/test_ci_unit_test_contract.py b/tests/test_ci_unit_test_contract.py new file mode 100644 index 0000000..e2c93e2 --- /dev/null +++ b/tests/test_ci_unit_test_contract.py @@ -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.*)\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 diff --git a/tests/test_execution_report_heartbeat.py b/tests/test_execution_report_heartbeat.py index 3ee13fe..b20269f 100644 --- a/tests/test_execution_report_heartbeat.py +++ b/tests/test_execution_report_heartbeat.py @@ -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( @@ -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 diff --git a/tests/test_runtime_config_support.py b/tests/test_runtime_config_support.py index 2b3ad01..ac47145 100644 --- a/tests/test_runtime_config_support.py +++ b/tests/test_runtime_config_support.py @@ -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", } @@ -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") @@ -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): @@ -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", @@ -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领涨" @@ -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(): diff --git a/tests/test_runtime_monitor_workflows.py b/tests/test_runtime_monitor_workflows.py index 01dc2f5..b8fc0ec 100644 --- a/tests/test_runtime_monitor_workflows.py +++ b/tests/test_runtime_monitor_workflows.py @@ -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: diff --git a/tests/test_scheduler_deadline_contract.py b/tests/test_scheduler_deadline_contract.py index 7620263..c02b733 100644 --- a/tests/test_scheduler_deadline_contract.py +++ b/tests/test_scheduler_deadline_contract.py @@ -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[@]}"') diff --git a/tests/test_strategy_runtime.py b/tests/test_strategy_runtime.py index d7f4562..c8c8caa 100644 --- a/tests/test_strategy_runtime.py +++ b/tests/test_strategy_runtime.py @@ -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( @@ -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(