test_rotate_runtime.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. from __future__ import annotations
  2. import json
  3. from pathlib import Path
  4. from ops.rotate_runtime import _maybe_reconcile_cpa_runtime
  5. class FakeClient:
  6. def __init__(self) -> None:
  7. self.files: dict[str, dict[str, object]] = {
  8. "remote@example.com.json": {
  9. "email": "remote@example.com",
  10. "access_token": "remote-token",
  11. "account_id": "acct-remote",
  12. }
  13. }
  14. self.uploads: list[tuple[str, dict[str, object]]] = []
  15. def health_check(self) -> bool:
  16. return True
  17. def list_auth_files(self) -> list[dict[str, object]]:
  18. return [{"name": name} for name in self.files]
  19. def get_auth_file(self, name: str) -> dict[str, object] | None:
  20. payload = self.files.get(name)
  21. return dict(payload) if isinstance(payload, dict) else None
  22. def upload_auth_file(self, name: str, payload: dict[str, object]) -> bool:
  23. self.uploads.append((name, dict(payload)))
  24. self.files[name] = dict(payload)
  25. return True
  26. def test_runtime_reconcile_restores_local_backup_and_cpa_inventory(tmp_path: Path) -> None:
  27. pool_dir = tmp_path / "pool"
  28. pool_dir.mkdir()
  29. local_only = pool_dir / "local@example.com.json"
  30. local_only.write_text(
  31. json.dumps(
  32. {
  33. "email": "local@example.com",
  34. "access_token": "local-token",
  35. "account_id": "acct-local",
  36. }
  37. ),
  38. encoding="utf-8",
  39. )
  40. client = FakeClient()
  41. _maybe_reconcile_cpa_runtime(
  42. pool_dir=pool_dir,
  43. management_base_url="http://127.0.0.1:8317/v0/management",
  44. enabled=True,
  45. cooldown_seconds=300,
  46. state_file=tmp_path / "reconcile_state.json",
  47. restart_enabled=False,
  48. client=client,
  49. management_key="secret",
  50. )
  51. remote_backup = json.loads((pool_dir / "remote@example.com.json").read_text(encoding="utf-8"))
  52. local_backup = json.loads(local_only.read_text(encoding="utf-8"))
  53. assert client.uploads == [
  54. (
  55. "local@example.com.json",
  56. {
  57. "email": "local@example.com",
  58. "access_token": "local-token",
  59. "account_id": "acct-local",
  60. "health_status": "unknown",
  61. "source": "register",
  62. "created_at": "",
  63. "backup_written": True,
  64. "cpa_sync_status": "pending",
  65. "last_cpa_sync_at": "",
  66. "last_cpa_sync_error": "",
  67. "last_probe_at": "",
  68. "last_probe_status_code": None,
  69. "last_probe_result": "",
  70. "last_probe_detail": "",
  71. "warmup_required": False,
  72. "warmup_state": "not_required",
  73. "warmup_passed": True,
  74. "warmup_completed_at": "",
  75. "successful_probe_count": 0,
  76. "first_use_proxy_key": "",
  77. "first_use_proxy_region": "",
  78. "first_invalid_proxy_key": "",
  79. "first_invalid_proxy_region": "",
  80. },
  81. )
  82. ]
  83. assert remote_backup["email"] == "remote@example.com"
  84. assert remote_backup["backup_written"] is True
  85. assert remote_backup["cpa_sync_status"] == "synced"
  86. assert local_backup["cpa_sync_status"] == "synced"
  87. def test_runtime_reconcile_ignores_local_warmup_pending_accounts(tmp_path: Path) -> None:
  88. pool_dir = tmp_path / "pool"
  89. pool_dir.mkdir()
  90. local_only = pool_dir / "warmup@example.com.json"
  91. local_only.write_text(
  92. json.dumps(
  93. {
  94. "email": "warmup@example.com",
  95. "access_token": "local-token",
  96. "account_id": "acct-local",
  97. "warmup_required": True,
  98. "warmup_state": "pending",
  99. "warmup_passed": False,
  100. "cpa_sync_status": "warmup_pending",
  101. }
  102. ),
  103. encoding="utf-8",
  104. )
  105. client = FakeClient()
  106. client.files = {}
  107. _maybe_reconcile_cpa_runtime(
  108. pool_dir=pool_dir,
  109. management_base_url="http://127.0.0.1:8317/v0/management",
  110. enabled=True,
  111. cooldown_seconds=300,
  112. state_file=tmp_path / "reconcile_state.json",
  113. restart_enabled=False,
  114. client=client,
  115. management_key="secret",
  116. )
  117. assert client.uploads == []
  118. assert json.loads(local_only.read_text(encoding="utf-8"))["cpa_sync_status"] == "warmup_pending"