"""Tests para gsc_auth (sin credenciales reales ni red).""" import os import sys from unittest import mock import pytest sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..")) from functions.infra.gsc_auth import gsc_auth # noqa: E402 _SCOPE = "https://www.googleapis.com/auth/webmasters.readonly" def _patches(): """Devuelve los context managers para mockear creds y build. La funcion importa de forma diferida desde ``google.oauth2.service_account`` y ``googleapiclient.discovery``, por eso se parchea en el modulo de origen. """ creds_patch = mock.patch( "google.oauth2.service_account.Credentials.from_service_account_file" ) build_patch = mock.patch("googleapiclient.discovery.build") return creds_patch, build_patch def test_build_se_llama_con_searchconsole_v1_y_cache_off(): creds_patch, build_patch = _patches() with creds_patch as m_creds, build_patch as m_build: fake_creds = mock.Mock(name="creds") m_creds.return_value = fake_creds fake_service = mock.Mock(name="service") m_build.return_value = fake_service result = gsc_auth(credentials_path="/tmp/sa.json") assert result is fake_service m_build.assert_called_once_with( "searchconsole", "v1", credentials=fake_creds, cache_discovery=False, ) def test_credentials_se_cargan_con_scope_readonly(): creds_patch, build_patch = _patches() with creds_patch as m_creds, build_patch as m_build: m_creds.return_value = mock.Mock() m_build.return_value = mock.Mock() gsc_auth(credentials_path="/tmp/sa.json") m_creds.assert_called_once_with("/tmp/sa.json", scopes=[_SCOPE]) def test_fallback_a_env_var_gsc_sa_json(): creds_patch, build_patch = _patches() with creds_patch as m_creds, build_patch as m_build, mock.patch.dict( os.environ, {"GSC_SA_JSON": "/env/sa.json"}, clear=False ): m_creds.return_value = mock.Mock() m_build.return_value = mock.Mock() gsc_auth(credentials_path="") m_creds.assert_called_once_with("/env/sa.json", scopes=[_SCOPE]) def test_subject_aplica_with_subject(): creds_patch, build_patch = _patches() with creds_patch as m_creds, build_patch as m_build: base_creds = mock.Mock(name="base_creds") delegated = mock.Mock(name="delegated_creds") base_creds.with_subject.return_value = delegated m_creds.return_value = base_creds m_build.return_value = mock.Mock() gsc_auth(credentials_path="/tmp/sa.json", subject="user@dominio.com") base_creds.with_subject.assert_called_once_with("user@dominio.com") _, kwargs = m_build.call_args assert kwargs["credentials"] is delegated def test_error_cuando_falta_credential(): creds_patch, build_patch = _patches() with creds_patch, build_patch, mock.patch.dict( os.environ, {}, clear=True ): with pytest.raises(ValueError) as exc: gsc_auth(credentials_path="") assert "GSC_SA_JSON" in str(exc.value)