feat: add ops center and node onboarding flow
This commit is contained in:
169
domain-api/tests/test_ops_service_go_live_review.py
Normal file
169
domain-api/tests/test_ops_service_go_live_review.py
Normal file
@@ -0,0 +1,169 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
from app.services.ops_service import get_ops_go_live_review
|
||||
|
||||
|
||||
class OpsServiceGoLiveReviewTests(unittest.TestCase):
|
||||
@patch("app.services.ops_service.get_ops_contract_registry")
|
||||
def test_go_live_review_marks_missing_when_no_manifest_exists(self, mock_get_ops_contract_registry) -> None:
|
||||
mock_get_ops_contract_registry.return_value = {
|
||||
"contracts_by_key": {
|
||||
"ops_go_live_review_contract": {"version": "v1"},
|
||||
}
|
||||
}
|
||||
|
||||
with patch("app.services.ops_service._find_latest_go_live_bundle_manifest", return_value=(None, Path("/tmp/go-live-bundles"))):
|
||||
payload = get_ops_go_live_review(base_url="http://127.0.0.1:8100")
|
||||
|
||||
self.assertEqual("missing", payload["status"])
|
||||
self.assertEqual("待导出", payload["status_label"])
|
||||
self.assertIn("go-live-export", payload["recommended_commands"]["go_live_export"])
|
||||
|
||||
@patch("app.services.ops_service.get_ops_contract_registry")
|
||||
def test_go_live_review_reads_manifest_and_alignment(self, mock_get_ops_contract_registry) -> None:
|
||||
mock_get_ops_contract_registry.return_value = {
|
||||
"contracts_by_key": {
|
||||
"ops_go_live_review_contract": {"version": "v1"},
|
||||
}
|
||||
}
|
||||
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
report_dir = Path(temp_dir) / "go-live-bundle-001"
|
||||
report_dir.mkdir(parents=True, exist_ok=True)
|
||||
env_audit_path = report_dir / "00_env_audit.txt"
|
||||
env_audit_path.write_text(
|
||||
"[8/8] condensed env audit summary\n"
|
||||
+ json.dumps(
|
||||
{
|
||||
"status": "attention",
|
||||
"headline": "环境仍有轻微缺口",
|
||||
"missing_items": ["missing_tool:jq"],
|
||||
"recommended_actions": ["bash runtime-refresh-recover"],
|
||||
},
|
||||
ensure_ascii=False,
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
go_live_summary_path = report_dir / "02_go_live_summary.json"
|
||||
go_live_summary_path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"go_live_status": "attention",
|
||||
"publish_status": "attention",
|
||||
"operator_title": "先补接入缺口",
|
||||
"next_step_action_code": "fix_managed_nodes",
|
||||
"launchpad_recommended_target_node_code": "mainland-worker-01",
|
||||
"launchpad_recommended_recovery_label": "先补接入缺口",
|
||||
"launchpad_recommended_recovery_summary": "mainland-worker-01 还缺接入收口。",
|
||||
"launchpad_onboarding_bootstrap_pending_nodes": 1,
|
||||
"launchpad_onboarding_acceptance_ready_nodes": 0,
|
||||
},
|
||||
ensure_ascii=False,
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
stack_diagnosis_path = report_dir / "03_stack_diagnosis.json"
|
||||
stack_diagnosis_path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"diagnosis": {
|
||||
"stack_status": "attention",
|
||||
"operator_decision": {"title": "先补接入缺口"},
|
||||
"next_step": {"action_code": "fix_managed_nodes"},
|
||||
"launchpad_recommended_target_node_code": "mainland-worker-02",
|
||||
"launchpad_recommended_recovery_label": "先看节点接管",
|
||||
"launchpad_recommended_recovery_summary": "stack 与 summary 存在漂移。",
|
||||
"launchpad_onboarding_bootstrap_pending_nodes": 1,
|
||||
"launchpad_onboarding_acceptance_ready_nodes": 0,
|
||||
}
|
||||
},
|
||||
ensure_ascii=False,
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
driver_feed_path = report_dir / "04_driver_feed.json"
|
||||
driver_feed_path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"headline": "driver ok",
|
||||
"summary": {
|
||||
"launchpad_recommended_target_node_code": "mainland-worker-01",
|
||||
"launchpad_recommended_recovery_label": "先补接入缺口",
|
||||
"launchpad_recommended_recovery_summary": "mainland-worker-01 还缺接入收口。",
|
||||
"launchpad_onboarding_bootstrap_pending_nodes": 1,
|
||||
"launchpad_onboarding_acceptance_ready_nodes": 0,
|
||||
},
|
||||
"automation_coverage": {"launch_status": "attention", "launch_ready": False},
|
||||
},
|
||||
ensure_ascii=False,
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
codex_brief_path = report_dir / "05_codex_brief.json"
|
||||
codex_brief_path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"headline": "codex ok",
|
||||
"summary": {
|
||||
"launchpad_recommended_target_node_code": "mainland-worker-01",
|
||||
"launchpad_recommended_recovery_label": "先补接入缺口",
|
||||
"launchpad_recommended_recovery_summary": "mainland-worker-01 还缺接入收口。",
|
||||
"launchpad_onboarding_bootstrap_pending_nodes": 1,
|
||||
"launchpad_onboarding_acceptance_ready_nodes": 0,
|
||||
},
|
||||
"automation_coverage": {"launch_status": "attention", "launch_ready": False},
|
||||
"focus": {"entry_key": "fix_managed_nodes"},
|
||||
},
|
||||
ensure_ascii=False,
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
manifest_path = report_dir / "manifest.json"
|
||||
manifest_path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"report_dir": str(report_dir),
|
||||
"artifacts": [
|
||||
{"key": "env_audit", "path": str(env_audit_path), "ok": True},
|
||||
{"key": "go_live_summary", "path": str(go_live_summary_path), "ok": True},
|
||||
{"key": "stack_diagnosis", "path": str(stack_diagnosis_path), "ok": True},
|
||||
{"key": "driver_feed", "path": str(driver_feed_path), "ok": True},
|
||||
{"key": "codex_brief", "path": str(codex_brief_path), "ok": True},
|
||||
{"key": "release_launchpad", "path": str(report_dir / "06_release_launchpad.json"), "ok": True},
|
||||
],
|
||||
"failures": ["doctor_export"],
|
||||
"summary": {
|
||||
"artifact_total": 9,
|
||||
"failure_total": 1,
|
||||
"recommended_reading_order": ["00_env_audit.txt", "02_go_live_summary.json"],
|
||||
},
|
||||
},
|
||||
ensure_ascii=False,
|
||||
indent=2,
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
with patch(
|
||||
"app.services.ops_service._find_latest_go_live_bundle_manifest",
|
||||
return_value=(manifest_path, report_dir),
|
||||
):
|
||||
payload = get_ops_go_live_review(base_url="http://127.0.0.1:8100")
|
||||
|
||||
self.assertEqual("attention", payload["status"])
|
||||
self.assertEqual(9, payload["artifact_total"])
|
||||
self.assertEqual(["doctor_export"], payload["noncritical_failures"])
|
||||
self.assertFalse(payload["launchpad_alignment"]["consistent"])
|
||||
self.assertIn("go_live_summary", payload["launchpad_alignment"]["available_sources"])
|
||||
self.assertIn("mainland-worker-01", payload["recommended_next_steps"][0] + "".join(payload["recommended_next_steps"]))
|
||||
self.assertIn(str(manifest_path), payload["recommended_commands"]["go_live_review"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user