89 lines
3.2 KiB
Python
89 lines
3.2 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""test_onboard_pipeline.py — Unit tests for the onboarding and invite salvage pipeline."""
|
||
|
|
|
||
|
|
import json
|
||
|
|
import sys
|
||
|
|
import unittest
|
||
|
|
from pathlib import Path
|
||
|
|
from unittest.mock import MagicMock, patch
|
||
|
|
|
||
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||
|
|
sys.path.insert(0, str(REPO_ROOT / "bin"))
|
||
|
|
|
||
|
|
from onboard_pipeline import (
|
||
|
|
OnboardState,
|
||
|
|
finish_onboarding_redemption,
|
||
|
|
select_urgent_beneficiary,
|
||
|
|
start_onboarding,
|
||
|
|
submit_onboarding_otp,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
class TestOnboardPipeline(unittest.TestCase):
|
||
|
|
def test_select_urgent_beneficiary_explicit(self):
|
||
|
|
b_node, code, reason = select_urgent_beneficiary("dev", "TEST01")
|
||
|
|
self.assertEqual(b_node, "dev")
|
||
|
|
self.assertEqual(code, "TEST01")
|
||
|
|
self.assertIn("Explicit", reason)
|
||
|
|
|
||
|
|
@patch("invite.fleet_invite_status")
|
||
|
|
@patch("invite.fleet_usage")
|
||
|
|
def test_select_urgent_beneficiary_blocked_first(self, mock_usage, mock_invite):
|
||
|
|
mock_usage.return_value = {
|
||
|
|
"646": {"weekly_used_pct": 100, "additional_used_pct": 100, "additional_left": "0 tokens left"},
|
||
|
|
"pip": {"weekly_used_pct": 100, "additional_used_pct": 10, "additional_left": "890M tokens left"},
|
||
|
|
"muse": {"weekly_used_pct": 50, "additional_used_pct": 0, "additional_left": "950M tokens left"},
|
||
|
|
}
|
||
|
|
mock_invite.return_value = {
|
||
|
|
"646": {"code": "REDCJ7"},
|
||
|
|
"pip": {"code": "F4BGHN"},
|
||
|
|
"muse": {"code": "81MDIR"},
|
||
|
|
}
|
||
|
|
|
||
|
|
b_node, code, reason = select_urgent_beneficiary()
|
||
|
|
self.assertEqual(b_node, "646")
|
||
|
|
self.assertEqual(code, "REDCJ7")
|
||
|
|
self.assertIn("BLOCKED", reason)
|
||
|
|
|
||
|
|
@patch("onboard_pipeline.provision_node_infra")
|
||
|
|
@patch("onboard_pipeline.CredClient")
|
||
|
|
@patch("onboard_pipeline.select_urgent_beneficiary")
|
||
|
|
def test_start_onboarding_awaiting_otp(self, mock_select, mock_cred_cls, mock_infra):
|
||
|
|
mock_select.return_value = ("646", "REDCJ7", "Blocked test")
|
||
|
|
mock_infra.return_value = {"ok": True}
|
||
|
|
|
||
|
|
mock_client = MagicMock()
|
||
|
|
mock_client.initiate.return_value = {
|
||
|
|
"status": "awaiting_otp",
|
||
|
|
"message": "OTP sent",
|
||
|
|
}
|
||
|
|
mock_cred_cls.return_value = mock_client
|
||
|
|
|
||
|
|
res = start_onboarding("testnode", "client@test.com")
|
||
|
|
self.assertTrue(res["ok"])
|
||
|
|
self.assertEqual(res["status"], "awaiting_otp")
|
||
|
|
self.assertEqual(res["beneficiary_node"], "646")
|
||
|
|
self.assertEqual(res["invite_code_queued"], "REDCJ7")
|
||
|
|
|
||
|
|
@patch("invite.redeem_invite")
|
||
|
|
@patch("subprocess.run")
|
||
|
|
def test_finish_onboarding_redemption_success(self, mock_subproc, mock_redeem):
|
||
|
|
mock_redeem.return_value = {"ok": True, "redemption_status": "redeemed"}
|
||
|
|
state = OnboardState(
|
||
|
|
node="testnode",
|
||
|
|
email="client@test.com",
|
||
|
|
beneficiary_node="646",
|
||
|
|
invite_code="REDCJ7",
|
||
|
|
stage="auth_active",
|
||
|
|
)
|
||
|
|
|
||
|
|
res = finish_onboarding_redemption(state)
|
||
|
|
self.assertTrue(res["ok"])
|
||
|
|
self.assertEqual(res["status"], "completed")
|
||
|
|
self.assertEqual(res["beneficiary_node"], "646")
|
||
|
|
mock_redeem.assert_called_once_with("testnode", "REDCJ7", timeout=20.0)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
unittest.main()
|