diff --git a/server.py b/server.py index 4614c54..c7ac702 100644 --- a/server.py +++ b/server.py @@ -50,6 +50,11 @@ def authenticate() -> str: """Initiate Garmin authentication using credentials from environment variables.""" 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: try: _client.login() @@ -57,7 +62,7 @@ def authenticate() -> str: except Exception as 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 threading.Thread(target=_do_login, daemon=True).start() diff --git a/tests/test_server.py b/tests/test_server.py index 3d06de0..caff357 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -1,4 +1,5 @@ import json +import os import queue import threading from unittest.mock import MagicMock, patch @@ -21,6 +22,12 @@ def reset_state(): yield server._auth_state = original_state 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(): @@ -34,19 +41,23 @@ def test_check_auth_authenticated(): def test_authenticate_success(): - with patch("server.Garmin") as mock_garmin_cls: - mock_garmin_cls.return_value = MagicMock() - # mock login() returns immediately, thread puts success in queue - result = server.authenticate() - assert result == "Authenticated successfully." - assert server._auth_state == "authenticated" + env = {"GARMIN_EMAIL": "test@example.com", "GARMIN_PASSWORD": "secret"} + with patch.dict("os.environ", env): + with patch("server.Garmin") as mock_garmin_cls: + mock_garmin_cls.return_value = MagicMock() + # mock login() returns immediately, thread puts success in queue + result = server.authenticate() + assert result == "Authenticated successfully." + assert server._auth_state == "authenticated" def test_authenticate_mfa_required(): - with patch("server.Garmin") as mock_garmin_cls: - mock_garmin_cls.return_value = MagicMock() - with patch.object(server._login_result_queue, "get", side_effect=queue.Empty): - result = server.authenticate() + env = {"GARMIN_EMAIL": "test@example.com", "GARMIN_PASSWORD": "secret"} + with patch.dict("os.environ", env): + with patch("server.Garmin") as mock_garmin_cls: + 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 server._auth_state == "mfa_pending" @@ -64,3 +75,12 @@ def test_complete_mfa_not_in_progress(): server._auth_state = "unauthenticated" result = server.complete_mfa("123456") 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."