fix: guard missing env vars in authenticate(), drain queues post-yield
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -50,6 +50,11 @@ def authenticate() -> str:
|
|||||||
"""Initiate Garmin authentication using credentials from environment variables."""
|
"""Initiate Garmin authentication using credentials from environment variables."""
|
||||||
global _client, _auth_state
|
global _client, _auth_state
|
||||||
|
|
||||||
|
email = os.environ.get("GARMIN_EMAIL", "")
|
||||||
|
password = os.environ.get("GARMIN_PASSWORD", "")
|
||||||
|
if not email or not password:
|
||||||
|
return "GARMIN_EMAIL and GARMIN_PASSWORD environment variables are required."
|
||||||
|
|
||||||
def _do_login() -> None:
|
def _do_login() -> None:
|
||||||
try:
|
try:
|
||||||
_client.login()
|
_client.login()
|
||||||
@@ -57,7 +62,7 @@ def authenticate() -> str:
|
|||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
_login_result_queue.put(("error", str(exc)))
|
_login_result_queue.put(("error", str(exc)))
|
||||||
|
|
||||||
_client = Garmin(os.environ.get("GARMIN_EMAIL", ""), os.environ.get("GARMIN_PASSWORD", ""))
|
_client = Garmin(email, password)
|
||||||
_client.prompt_mfa = _prompt_mfa
|
_client.prompt_mfa = _prompt_mfa
|
||||||
threading.Thread(target=_do_login, daemon=True).start()
|
threading.Thread(target=_do_login, daemon=True).start()
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
|
import os
|
||||||
import queue
|
import queue
|
||||||
import threading
|
import threading
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
@@ -21,6 +22,12 @@ def reset_state():
|
|||||||
yield
|
yield
|
||||||
server._auth_state = original_state
|
server._auth_state = original_state
|
||||||
server._client = original_client
|
server._client = original_client
|
||||||
|
for q in (server._mfa_input_queue, server._login_result_queue):
|
||||||
|
while not q.empty():
|
||||||
|
try:
|
||||||
|
q.get_nowait()
|
||||||
|
except queue.Empty:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
def test_check_auth_unauthenticated():
|
def test_check_auth_unauthenticated():
|
||||||
@@ -34,19 +41,23 @@ def test_check_auth_authenticated():
|
|||||||
|
|
||||||
|
|
||||||
def test_authenticate_success():
|
def test_authenticate_success():
|
||||||
with patch("server.Garmin") as mock_garmin_cls:
|
env = {"GARMIN_EMAIL": "test@example.com", "GARMIN_PASSWORD": "secret"}
|
||||||
mock_garmin_cls.return_value = MagicMock()
|
with patch.dict("os.environ", env):
|
||||||
# mock login() returns immediately, thread puts success in queue
|
with patch("server.Garmin") as mock_garmin_cls:
|
||||||
result = server.authenticate()
|
mock_garmin_cls.return_value = MagicMock()
|
||||||
assert result == "Authenticated successfully."
|
# mock login() returns immediately, thread puts success in queue
|
||||||
assert server._auth_state == "authenticated"
|
result = server.authenticate()
|
||||||
|
assert result == "Authenticated successfully."
|
||||||
|
assert server._auth_state == "authenticated"
|
||||||
|
|
||||||
|
|
||||||
def test_authenticate_mfa_required():
|
def test_authenticate_mfa_required():
|
||||||
with patch("server.Garmin") as mock_garmin_cls:
|
env = {"GARMIN_EMAIL": "test@example.com", "GARMIN_PASSWORD": "secret"}
|
||||||
mock_garmin_cls.return_value = MagicMock()
|
with patch.dict("os.environ", env):
|
||||||
with patch.object(server._login_result_queue, "get", side_effect=queue.Empty):
|
with patch("server.Garmin") as mock_garmin_cls:
|
||||||
result = server.authenticate()
|
mock_garmin_cls.return_value = MagicMock()
|
||||||
|
with patch.object(server._login_result_queue, "get", side_effect=queue.Empty):
|
||||||
|
result = server.authenticate()
|
||||||
assert "MFA required" in result
|
assert "MFA required" in result
|
||||||
assert server._auth_state == "mfa_pending"
|
assert server._auth_state == "mfa_pending"
|
||||||
|
|
||||||
@@ -64,3 +75,12 @@ def test_complete_mfa_not_in_progress():
|
|||||||
server._auth_state = "unauthenticated"
|
server._auth_state = "unauthenticated"
|
||||||
result = server.complete_mfa("123456")
|
result = server.complete_mfa("123456")
|
||||||
assert result == "No MFA in progress. Call authenticate() first."
|
assert result == "No MFA in progress. Call authenticate() first."
|
||||||
|
|
||||||
|
|
||||||
|
def test_authenticate_missing_credentials():
|
||||||
|
with patch.dict("os.environ", {}, clear=False):
|
||||||
|
# Ensure the env vars are absent
|
||||||
|
os.environ.pop("GARMIN_EMAIL", None)
|
||||||
|
os.environ.pop("GARMIN_PASSWORD", None)
|
||||||
|
result = server.authenticate()
|
||||||
|
assert result == "GARMIN_EMAIL and GARMIN_PASSWORD environment variables are required."
|
||||||
|
|||||||
Reference in New Issue
Block a user