hermes-hub/tests/test_add_account_does_not_block.py
Hermes Team 0ad946eccd fix(accounts): мастер подключения замирал на шаге 3
Владелец видел «сохранение аккаунта и запуск проверки» и ждал. Зависанием это
не было: действие честно дожидалось проверки у провайдера. Для Antigravity она
идёт через CLI и в худшем случае складывается из 90 с на захват замка профиля,
65 на каталог моделей и 90 на пробный вызов — около четырёх минут молчания при
обещанной в интерфейсе «минуте на этап».

Сохранение учётных данных и назначение роли занимают миллисекунды. Теперь
действие возвращается сразу, а опрос провайдера ставится в фон; карточка
обновляется, когда он закончится, — снапшот и так опрашивается по таймеру.

Провайдеры с ключом поведения не меняют: их подключение проверяется
предварительной проверкой до сохранения и возвращается сразу, как требует A54.
Если фоновая служба не работает, проверка по-прежнему выполняется на месте —
иначе результата не будет вовсе.

Надпись в мастере исправлена: обещание «до минуты на этап» не соответствовало
действительности.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 13:23:55 +07:00

77 lines
4.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Подключение аккаунта не должно ждать опроса провайдера.
Мастер владельца замирал на шаге 3 с надписью «сохранение аккаунта и запуск
проверки». Зависанием это не было: действие честно ждало проверку Antigravity
через CLI — до 90 с на захват замка профиля, до 65 на каталог моделей и до 90
на пробный вызов. Около четырёх минут молчания при обещанной «минуте на этап».
Сохранение и назначение роли занимают миллисекунды. Опрос провайдера идёт в
фоне, а карточка обновляется, когда он закончится.
"""
from __future__ import annotations
import time
from unittest.mock import patch
from antigravity_provider.router.account_probe_service import AccountProbeService
from antigravity_provider.router.action_handler import ActionExecutor
from antigravity_provider.router.auto_assigner import AutoAssigner
from antigravity_provider.router.profile_manager import ProfileAuthManager
def _connect_authenticated_antigravity():
with patch.object(ProfileAuthManager, "get_profile_status", return_value={"authenticated": True}), \
patch.object(ProfileAuthManager, "load_profile_auth", return_value={"email": "x@gmail.com"}), \
patch.object(ProfileAuthManager, "save_profile_auth", return_value="/tmp/auth.json"), \
patch.object(AutoAssigner, "ensure_profile_definition", return_value=(True, "ok")), \
patch.object(AutoAssigner, "assign_profile_to_role", return_value=(True, "ok")):
return ActionExecutor.execute(
"add_account",
{"provider": "antigravity", "profile_id": "ag-1", "target_role": "orchestrator"},
)
def test_connect_returns_without_waiting_for_provider():
slow_call = []
def _slow_check_now(self, provider, profile_id, models_only=False):
slow_call.append(profile_id)
time.sleep(5) # изображаем опрос провайдера
return {"ok": True, "message": "проверено"}
with patch.object(AccountProbeService, "schedule", return_value=True) as scheduled, \
patch.object(AccountProbeService, "check_now", _slow_check_now):
started = time.monotonic()
res = _connect_authenticated_antigravity()
elapsed = time.monotonic() - started
assert res["ok"], res
assert not slow_call, "действие не должно ждать опрос провайдера"
assert scheduled.called, "проверка обязана быть поставлена в фон"
assert elapsed < 2, f"ответ занял {elapsed:.1f} с"
assert res["data"]["check"] == "running"
def test_result_reaches_owner_when_background_service_is_down():
"""Служба не работает — проверяем здесь, иначе результата не будет вовсе."""
with patch.object(AccountProbeService, "schedule", return_value=False), \
patch.object(AccountProbeService, "state", return_value={"state": "never_checked"}), \
patch.object(
AccountProbeService,
"check_now",
return_value={"ok": False, "message": "провайдер отказал", "data": {}},
) as checked:
res = _connect_authenticated_antigravity()
assert checked.called, "без фоновой службы проверка выполняется на месте"
assert res["message"] == "провайдер отказал"
def test_check_already_running_is_not_awaited():
with patch.object(AccountProbeService, "schedule", return_value=False), \
patch.object(AccountProbeService, "state", return_value={"state": "checking"}), \
patch.object(AccountProbeService, "check_now") as checked:
res = _connect_authenticated_antigravity()
assert not checked.called, "уже идущую проверку не ждём и не дублируем"
assert res["ok"] and res["data"]["check"] == "running"