This commit is contained in:
@@ -502,6 +502,10 @@ def test_market_intel_preview_template_uses_safe_fetch_false_endpoint():
|
||||
assert "data-market-intel-live-inventory-tables" in template
|
||||
assert "data-market-intel-live-inventory-platforms" in template
|
||||
assert "data-market-intel-live-inventory-alerts" in template
|
||||
assert "data-market-intel-manual-sample" in template
|
||||
assert "data-market-intel-manual-sample-checks" in template
|
||||
assert "data-market-intel-manual-sample-platforms" in template
|
||||
assert "data-market-intel-manual-sample-sequence" in template
|
||||
assert "data-market-intel-approval" in template
|
||||
assert "data-market-intel-approval-gates" in template
|
||||
assert "data-market-intel-deploy" in template
|
||||
@@ -517,6 +521,7 @@ def test_market_intel_preview_template_uses_safe_fetch_false_endpoint():
|
||||
assert "market_intel.market_intel_mcp_deploy_preflight" in template
|
||||
assert "market_intel.market_intel_mcp_activation_runbook" in template
|
||||
assert "market_intel.market_intel_mcp_fetch_gate" in template
|
||||
assert "market_intel.market_intel_manual_sample_plan" in template
|
||||
assert "market_intel.market_intel_scheduler_plan" in template
|
||||
assert "market_intel.market_intel_match_review_plan" in template
|
||||
assert "market_intel.market_intel_opportunity_plan" in template
|
||||
@@ -552,7 +557,7 @@ def test_legacy_source_bridge_default_is_planned_only():
|
||||
bridge = MarketIntelService().build_legacy_source_bridge()
|
||||
|
||||
assert bridge["mode"] == "legacy_source_bridge_planned"
|
||||
assert bridge["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert bridge["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert bridge["execute_requested"] is False
|
||||
assert bridge["read_only_query_executed"] is False
|
||||
assert bridge["database_connection_opened"] is False
|
||||
@@ -710,7 +715,7 @@ def test_mcp_tool_contract_preview_is_read_only_and_whitelisted():
|
||||
contract = MarketIntelService().build_mcp_tool_contract()
|
||||
|
||||
assert contract["mode"] == "mcp_tool_contract_preview"
|
||||
assert contract["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert contract["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert contract["caller"] == "market_intel"
|
||||
assert contract["contract_ready"] is True
|
||||
assert contract["blocked_reasons"] == []
|
||||
@@ -843,7 +848,7 @@ def test_mcp_activation_runbook_route_is_preview_only():
|
||||
|
||||
assert response.status_code == 200
|
||||
assert data["mode"] == "mcp_activation_runbook_preview"
|
||||
assert data["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert data["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert data["deployment_actions_executed"] is False
|
||||
assert data["docker_command_executed"] is False
|
||||
assert data["ssh_command_executed"] is False
|
||||
@@ -856,7 +861,7 @@ def test_mcp_fetch_gate_default_blocks_external_fetch():
|
||||
gate = MarketIntelService().build_mcp_fetch_gate(fetch_requested=True)
|
||||
|
||||
assert gate["mode"] == "mcp_fetch_gate_planned"
|
||||
assert gate["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert gate["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert gate["fetch_requested"] is True
|
||||
assert gate["manual_fetch_gate_open"] is False
|
||||
assert gate["network_request_allowed"] is False
|
||||
@@ -926,7 +931,7 @@ def test_mcp_fetch_gate_route_is_preview_only():
|
||||
|
||||
assert response.status_code == 200
|
||||
assert data["mode"] == "mcp_fetch_gate_planned"
|
||||
assert data["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert data["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert data["fetch_requested"] is False
|
||||
assert data["network_request_allowed"] is False
|
||||
assert data["external_network_executed"] is False
|
||||
@@ -934,11 +939,70 @@ def test_mcp_fetch_gate_route_is_preview_only():
|
||||
assert data["scheduler_attached"] is False
|
||||
|
||||
|
||||
def test_manual_sample_plan_preview_blocks_fetch_and_write():
|
||||
plan = MarketIntelService().build_manual_sample_plan()
|
||||
|
||||
assert plan["mode"] == "manual_sample_fetch_plan_preview"
|
||||
assert plan["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert plan["ready_for_manual_sample_fetch"] is False
|
||||
assert plan["sample_fetch_executed"] is False
|
||||
assert plan["external_network_executed"] is False
|
||||
assert plan["database_session_created"] is False
|
||||
assert plan["database_write_executed"] is False
|
||||
assert plan["database_commit_executed"] is False
|
||||
assert plan["scheduler_attached"] is False
|
||||
assert plan["writes_executed"] is False
|
||||
assert plan["would_write_database"] is False
|
||||
assert plan["platform_count"] == 4
|
||||
assert plan["sample_source_total"] == 4
|
||||
assert plan["sample_policy"]["max_platforms_per_manual_batch"] == 1
|
||||
assert plan["sample_policy"]["first_batch_platform"] == "pchome"
|
||||
assert [item["platform_code"] for item in plan["sample_platforms"]] == [
|
||||
"pchome",
|
||||
"momo",
|
||||
"coupang",
|
||||
"shopee",
|
||||
]
|
||||
assert all(
|
||||
item["sample_source_count"] == 1
|
||||
and item["network_status"] == "not_executed"
|
||||
and item["write_status"] == "blocked_preview_only"
|
||||
for item in plan["sample_platforms"]
|
||||
)
|
||||
assert "market_intel_enabled" in plan["blocked_reasons"]
|
||||
assert "mcp_fetch_gate_open" in plan["blocked_reasons"]
|
||||
assert "sample_fetch_not_executed_by_api" in plan["blocked_reasons"]
|
||||
assert "do_not_fetch_from_api_preview" in plan["safe_boundaries"]
|
||||
assert "do_not_bypass_anti_bot" in plan["safe_boundaries"]
|
||||
|
||||
|
||||
def test_manual_sample_plan_route_is_preview_only():
|
||||
from routes.market_intel_routes import market_intel_bp
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = "test-secret"
|
||||
app.register_blueprint(market_intel_bp)
|
||||
client = app.test_client()
|
||||
with client.session_transaction() as session:
|
||||
session["logged_in"] = True
|
||||
|
||||
response = client.get("/api/market_intel/manual_sample_plan")
|
||||
data = response.get_json()
|
||||
|
||||
assert response.status_code == 200
|
||||
assert data["mode"] == "manual_sample_fetch_plan_preview"
|
||||
assert data["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert data["sample_fetch_executed"] is False
|
||||
assert data["external_network_executed"] is False
|
||||
assert data["database_write_executed"] is False
|
||||
assert data["scheduler_attached"] is False
|
||||
|
||||
|
||||
def test_scheduler_plan_preview_blocks_job_attachment():
|
||||
plan = MarketIntelService().build_scheduler_plan()
|
||||
|
||||
assert plan["mode"] == "scheduler_attach_plan_preview"
|
||||
assert plan["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert plan["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert plan["ready_to_attach_scheduler"] is False
|
||||
assert plan["scheduler_attached"] is False
|
||||
assert plan["scheduler_registration_executed"] is False
|
||||
@@ -976,7 +1040,7 @@ def test_scheduler_plan_route_is_preview_only():
|
||||
|
||||
assert response.status_code == 200
|
||||
assert data["mode"] == "scheduler_attach_plan_preview"
|
||||
assert data["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert data["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert data["scheduler_registration_executed"] is False
|
||||
assert data["crawler_job_started"] is False
|
||||
assert data["external_network_executed"] is False
|
||||
@@ -987,7 +1051,7 @@ def test_match_review_plan_preview_blocks_auto_confirm():
|
||||
plan = MarketIntelService().build_match_review_plan()
|
||||
|
||||
assert plan["mode"] == "match_review_plan_preview"
|
||||
assert plan["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert plan["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert plan["ready_for_review_queue"] is False
|
||||
assert plan["review_queue_created"] is False
|
||||
assert plan["auto_match_executed"] is False
|
||||
@@ -1023,7 +1087,7 @@ def test_match_review_plan_route_is_preview_only():
|
||||
|
||||
assert response.status_code == 200
|
||||
assert data["mode"] == "match_review_plan_preview"
|
||||
assert data["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert data["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert data["review_queue_created"] is False
|
||||
assert data["auto_confirm_executed"] is False
|
||||
assert data["external_network_executed"] is False
|
||||
@@ -1034,7 +1098,7 @@ def test_opportunity_plan_preview_blocks_alerts_and_ai_summary():
|
||||
plan = MarketIntelService().build_opportunity_plan()
|
||||
|
||||
assert plan["mode"] == "opportunity_plan_preview"
|
||||
assert plan["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert plan["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert plan["ready_for_opportunity_queue"] is False
|
||||
assert plan["opportunity_queue_created"] is False
|
||||
assert plan["threat_alert_dispatched"] is False
|
||||
@@ -1075,7 +1139,7 @@ def test_opportunity_plan_route_is_preview_only():
|
||||
|
||||
assert response.status_code == 200
|
||||
assert data["mode"] == "opportunity_plan_preview"
|
||||
assert data["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert data["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert data["opportunity_queue_created"] is False
|
||||
assert data["threat_alert_dispatched"] is False
|
||||
assert data["ai_summary_generated"] is False
|
||||
@@ -1086,7 +1150,7 @@ def test_opportunity_scoring_plan_preview_blocks_scoring_and_alerts():
|
||||
plan = MarketIntelService().build_opportunity_scoring_plan()
|
||||
|
||||
assert plan["mode"] == "opportunity_scoring_plan_preview"
|
||||
assert plan["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert plan["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert plan["ready_for_scoring_job"] is False
|
||||
assert plan["scoring_job_created"] is False
|
||||
assert plan["score_calculation_executed"] is False
|
||||
@@ -1134,7 +1198,7 @@ def test_opportunity_scoring_plan_route_is_preview_only():
|
||||
|
||||
assert response.status_code == 200
|
||||
assert data["mode"] == "opportunity_scoring_plan_preview"
|
||||
assert data["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert data["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert data["scoring_job_created"] is False
|
||||
assert data["score_calculation_executed"] is False
|
||||
assert data["sample_scores_generated"] is False
|
||||
@@ -1146,7 +1210,7 @@ def test_opportunity_evidence_plan_preview_blocks_queries_and_alerts():
|
||||
plan = MarketIntelService().build_opportunity_evidence_plan()
|
||||
|
||||
assert plan["mode"] == "opportunity_evidence_plan_preview"
|
||||
assert plan["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert plan["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert plan["ready_for_evidence_bundle"] is False
|
||||
assert plan["evidence_bundle_created"] is False
|
||||
assert plan["evidence_query_executed"] is False
|
||||
@@ -1192,7 +1256,7 @@ def test_opportunity_evidence_plan_route_is_preview_only():
|
||||
|
||||
assert response.status_code == 200
|
||||
assert data["mode"] == "opportunity_evidence_plan_preview"
|
||||
assert data["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert data["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert data["evidence_bundle_created"] is False
|
||||
assert data["evidence_query_executed"] is False
|
||||
assert data["sample_evidence_generated"] is False
|
||||
@@ -1205,7 +1269,7 @@ def test_opportunity_alert_plan_preview_blocks_dispatch_and_llm_calls():
|
||||
plan = MarketIntelService().build_opportunity_alert_plan()
|
||||
|
||||
assert plan["mode"] == "opportunity_alert_plan_preview"
|
||||
assert plan["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert plan["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert plan["ready_for_alert_candidates"] is False
|
||||
assert plan["alert_candidate_created"] is False
|
||||
assert plan["alert_queue_created"] is False
|
||||
@@ -1290,7 +1354,7 @@ def test_opportunity_alert_plan_route_is_preview_only():
|
||||
|
||||
assert response.status_code == 200
|
||||
assert data["mode"] == "opportunity_alert_plan_preview"
|
||||
assert data["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert data["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert data["alert_candidate_created"] is False
|
||||
assert data["alert_queue_created"] is False
|
||||
assert data["review_queue_created"] is False
|
||||
@@ -1368,7 +1432,7 @@ def test_mcp_deploy_preflight_route_is_preview_only():
|
||||
|
||||
assert response.status_code == 200
|
||||
assert data["mode"] == "mcp_external_deploy_preflight_preview"
|
||||
assert data["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert data["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert data["deployment_actions_executed"] is False
|
||||
assert data["docker_command_executed"] is False
|
||||
assert data["ssh_command_executed"] is False
|
||||
@@ -1383,7 +1447,7 @@ def test_mcp_readiness_default_is_planned_only(monkeypatch):
|
||||
readiness = MarketIntelService().build_mcp_readiness()
|
||||
|
||||
assert readiness["mode"] == "mcp_readiness_planned"
|
||||
assert readiness["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert readiness["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert readiness["execute_requested"] is False
|
||||
assert readiness["router_enabled"] is False
|
||||
assert readiness["external_mcp_complete"] is False
|
||||
@@ -1771,6 +1835,7 @@ def test_deployment_readiness_reports_app_only_release_gate():
|
||||
assert readiness["checks"]["mcp_activation_runbook_preview_safe"] is True
|
||||
assert readiness["checks"]["mcp_fetch_gate_preview_safe"] is True
|
||||
assert readiness["checks"]["scheduler_plan_preview_safe"] is True
|
||||
assert readiness["checks"]["manual_sample_plan_preview_safe"] is True
|
||||
assert readiness["checks"]["match_review_plan_preview_safe"] is True
|
||||
assert readiness["checks"]["opportunity_plan_preview_safe"] is True
|
||||
assert readiness["checks"]["opportunity_scoring_plan_preview_safe"] is True
|
||||
@@ -1801,6 +1866,7 @@ def test_deployment_readiness_reports_app_only_release_gate():
|
||||
assert "/api/market_intel/mcp_activation_runbook" in readiness["production_smoke_targets"]
|
||||
assert "/api/market_intel/mcp_fetch_gate" in readiness["production_smoke_targets"]
|
||||
assert "/api/market_intel/scheduler_plan" in readiness["production_smoke_targets"]
|
||||
assert "/api/market_intel/manual_sample_plan" in readiness["production_smoke_targets"]
|
||||
assert "/api/market_intel/match_review_plan" in readiness["production_smoke_targets"]
|
||||
assert "/api/market_intel/opportunity_plan" in readiness["production_smoke_targets"]
|
||||
assert "/api/market_intel/opportunity_scoring_plan" in readiness["production_smoke_targets"]
|
||||
@@ -1847,6 +1913,11 @@ def test_deployment_readiness_reports_app_only_release_gate():
|
||||
assert readiness["mcp_activation_runbook"]["docker_command_executed"] is False
|
||||
assert readiness["mcp_fetch_gate"]["network_request_allowed"] is False
|
||||
assert readiness["mcp_fetch_gate"]["external_network_executed"] is False
|
||||
assert readiness["manual_sample_plan"]["mode"] == "manual_sample_fetch_plan_preview"
|
||||
assert readiness["manual_sample_plan"]["sample_fetch_executed"] is False
|
||||
assert readiness["manual_sample_plan"]["external_network_executed"] is False
|
||||
assert readiness["manual_sample_plan"]["database_write_executed"] is False
|
||||
assert readiness["manual_sample_plan"]["scheduler_attached"] is False
|
||||
assert readiness["scheduler_plan"]["scheduler_registration_executed"] is False
|
||||
assert readiness["scheduler_plan"]["crawler_job_started"] is False
|
||||
assert readiness["scheduler_plan"]["database_write_executed"] is False
|
||||
@@ -1951,7 +2022,7 @@ def test_migration_apply_drill_planned_is_safe_and_manual_only():
|
||||
drill = MarketIntelService().build_migration_apply_drill()
|
||||
|
||||
assert drill["mode"] == "migration_apply_drill_preview"
|
||||
assert drill["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert drill["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert drill["execute_requested"] is False
|
||||
assert drill["schema_state"] == "planned_no_db_probe"
|
||||
assert drill["drill_ready_for_operator_review"] is True
|
||||
@@ -2066,7 +2137,7 @@ def test_migration_apply_drill_route_is_preview_only():
|
||||
|
||||
assert response.status_code == 200
|
||||
assert data["mode"] == "migration_apply_drill_preview"
|
||||
assert data["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert data["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert data["execute_requested"] is False
|
||||
assert data["migration_executed"] is False
|
||||
assert data["rollback_executed"] is False
|
||||
@@ -2078,7 +2149,7 @@ def test_migration_catalog_review_planned_is_safe_and_diagnostic():
|
||||
review = MarketIntelService().build_migration_catalog_review()
|
||||
|
||||
assert review["mode"] == "migration_catalog_review_preview"
|
||||
assert review["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert review["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert review["execute_requested"] is False
|
||||
assert review["catalog_state"] == "planned_no_probe"
|
||||
assert review["seed_state"] == "planned_no_probe"
|
||||
@@ -2193,7 +2264,7 @@ def test_migration_catalog_review_route_is_preview_only():
|
||||
|
||||
assert response.status_code == 200
|
||||
assert data["mode"] == "migration_catalog_review_preview"
|
||||
assert data["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert data["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert data["execute_requested"] is False
|
||||
assert data["catalog_state"] == "planned_no_probe"
|
||||
assert data["migration_executed"] is False
|
||||
@@ -2206,7 +2277,7 @@ def test_migration_live_smoke_planned_is_preview_only():
|
||||
smoke = MarketIntelService().build_migration_live_smoke()
|
||||
|
||||
assert smoke["mode"] == "migration_live_smoke_preview"
|
||||
assert smoke["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert smoke["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert smoke["execute_requested"] is False
|
||||
assert smoke["smoke_result"] == "planned_no_execution"
|
||||
assert smoke["live_smoke_passed"] is False
|
||||
@@ -2268,7 +2339,7 @@ def test_migration_live_smoke_route_is_preview_only():
|
||||
|
||||
assert response.status_code == 200
|
||||
assert data["mode"] == "migration_live_smoke_preview"
|
||||
assert data["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert data["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert data["execute_requested"] is False
|
||||
assert data["smoke_result"] == "planned_no_execution"
|
||||
assert data["migration_executed"] is False
|
||||
@@ -2281,7 +2352,7 @@ def test_live_db_inventory_planned_is_preview_only():
|
||||
inventory = MarketIntelService().build_live_db_inventory()
|
||||
|
||||
assert inventory["mode"] == "live_db_inventory_planned"
|
||||
assert inventory["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert inventory["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert inventory["execute_requested"] is False
|
||||
assert inventory["read_only_query_executed"] is False
|
||||
assert inventory["database_connection_opened"] is False
|
||||
@@ -2425,7 +2496,7 @@ def test_live_db_inventory_route_is_preview_only():
|
||||
|
||||
assert response.status_code == 200
|
||||
assert data["mode"] == "live_db_inventory_planned"
|
||||
assert data["phase"] == "phase_46_live_db_inventory_preview"
|
||||
assert data["phase"] == "phase_47_manual_sample_fetch_plan"
|
||||
assert data["execute_requested"] is False
|
||||
assert data["read_only_query_executed"] is False
|
||||
assert data["database_write_executed"] is False
|
||||
|
||||
Reference in New Issue
Block a user