"""
Test OAuth scope resolution fixes.
This test module validates that the circular import issues and
OAuth scope parameter missing issues have been resolved.
"""
from unittest.mock import patch
class TestCircularImportResolution:
"""Test that circular imports between settings and compatibility_shim are resolved."""
def test_import_settings_without_error(self):
"""Test that settings can be imported without circular import errors."""
# This should not raise any ImportError
from config.settings import settings
assert settings is not None
def test_import_compatibility_shim_without_error(self):
"""Test that CompatibilityShim can be imported without circular import errors."""
# This should not raise any ImportError
from auth.compatibility_shim import CompatibilityShim
assert CompatibilityShim is not None
def test_import_scope_registry_without_error(self):
"""Test that ScopeRegistry can be imported without errors."""
from auth.scope_registry import ScopeRegistry
assert ScopeRegistry is not None
class TestDriveScopesProperty:
"""Test the drive_scopes property functionality."""
def test_drive_scopes_returns_non_empty_list(self):
"""Test that drive_scopes property returns a non-empty list."""
from config.settings import settings
scopes = settings.drive_scopes
assert isinstance(scopes, list)
assert len(scopes) > 0
def test_drive_scopes_contains_required_oauth_scopes(self):
"""Test that drive_scopes contains essential OAuth scopes."""
from config.settings import settings
scopes = settings.drive_scopes
# These are essential for OAuth authentication
required_scopes = ["https://www.googleapis.com/auth/userinfo.email", "openid"]
for required_scope in required_scopes:
assert required_scope in scopes, f"Missing required scope: {required_scope}"
def test_drive_scopes_contains_drive_scopes(self):
"""Test that drive_scopes contains Google Drive scopes."""
from config.settings import settings
scopes = settings.drive_scopes
# Should contain at least some Drive scopes
drive_scope_patterns = [
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/drive.readonly",
]
found_drive_scopes = [
scope
for scope in scopes
if any(pattern in scope for pattern in drive_scope_patterns)
]
assert len(found_drive_scopes) > 0, "No Drive scopes found"
@patch("config.settings._COMPATIBILITY_AVAILABLE", None) # Force lazy loading
def test_drive_scopes_lazy_import_success(self):
"""Test that lazy import of compatibility_shim works correctly."""
from config.settings import settings
# This should trigger the lazy import
scopes = settings.drive_scopes
assert isinstance(scopes, list)
assert len(scopes) > 0
@patch("config.settings._COMPATIBILITY_AVAILABLE", False) # Simulate import failure
def test_drive_scopes_fallback_to_hardcoded(self):
"""Test that drive_scopes falls back to hardcoded scopes when compatibility_shim fails."""
from config.settings import settings
scopes = settings.drive_scopes
# Should fall back to _fallback_drive_scopes
assert isinstance(scopes, list)
assert len(scopes) > 0
# Should contain the hardcoded fallback scopes
assert "https://www.googleapis.com/auth/userinfo.email" in scopes
class TestCompatibilityShimDirect:
"""Test CompatibilityShim direct functionality."""
def test_get_legacy_drive_scopes_returns_valid_scopes(self):
"""Test that CompatibilityShim.get_legacy_drive_scopes() returns valid scopes."""
from auth.compatibility_shim import CompatibilityShim
scopes = CompatibilityShim.get_legacy_drive_scopes()
assert isinstance(scopes, list)
assert len(scopes) > 0
# All scopes should be valid URLs
for scope in scopes:
assert isinstance(scope, str)
# OAuth scopes should either be URLs or simple identifiers like "openid"
assert scope == "openid" or scope.startswith("https://")
def test_get_legacy_dcr_scope_defaults_returns_valid_string(self):
"""Test that DCR scope defaults returns a valid scope string."""
from auth.compatibility_shim import CompatibilityShim
scope_string = CompatibilityShim.get_legacy_dcr_scope_defaults()
assert isinstance(scope_string, str)
assert len(scope_string) > 0
# Should be space-separated scopes
scopes = scope_string.split()
assert len(scopes) > 0
# Should contain essential scopes
assert "openid" in scope_string
assert "https://www.googleapis.com/auth/userinfo.email" in scope_string
class TestScopeRegistry:
"""Test ScopeRegistry functionality."""
def test_scope_registry_has_required_services(self):
"""Test that ScopeRegistry contains required service scopes."""
from auth.scope_registry import ScopeRegistry
# These services should be available in the registry
required_services = ["base", "drive", "gmail", "calendar"]
for service in required_services:
assert (
service in ScopeRegistry.GOOGLE_API_SCOPES
), f"Missing service: {service}"
assert len(ScopeRegistry.GOOGLE_API_SCOPES[service]) > 0
def test_get_oauth_scopes_returns_valid_scopes(self):
"""Test that get_oauth_scopes returns valid combined scopes."""
from auth.scope_registry import ScopeRegistry
services = ["drive", "gmail"]
scopes = ScopeRegistry.get_oauth_scopes(services)
assert isinstance(scopes, list)
assert len(scopes) > 0
# Should contain base OAuth scopes
assert "https://www.googleapis.com/auth/userinfo.email" in scopes
assert "openid" in scopes
class TestOAuthFlowIntegration:
"""Test OAuth flow integration with our fixes."""
def test_settings_accessible_from_oauth_flow(self):
"""Test that OAuth flow modules can access settings without circular import."""
# This simulates what happens in google_auth.py
from config.settings import settings
# Should be able to access drive_scopes without errors
scopes = settings.drive_scopes
assert isinstance(scopes, list)
assert len(scopes) > 0
# Should contain OAuth essentials for authentication
oauth_essentials = ["https://www.googleapis.com/auth/userinfo.email", "openid"]
for essential in oauth_essentials:
assert essential in scopes, f"Missing OAuth essential: {essential}"
def test_server_port_consistency(self):
"""Test that server port is consistently configured (no hardcoded ports)."""
from config.settings import settings
# Server port should be configured (could be 8000, 8002, or other)
assert isinstance(settings.server_port, int)
assert settings.server_port > 0
# OAuth redirect URI should use the configured port consistently
redirect_uri = settings.dynamic_oauth_redirect_uri
assert f":{settings.server_port}" in redirect_uri
# The key test: redirect URI should not have hardcoded values different from server_port
# This ensures dynamic client registration and other components use the same port
expected_port_string = f":{settings.server_port}"
assert expected_port_string in redirect_uri
class TestDeprecationWarningFixes:
"""Test that deprecation warnings have been fixed."""
def test_no_datetime_utcnow_in_dynamic_client_registration(self):
"""Test that datetime.now(UTC) has been replaced in dynamic_client_registration.py"""
# Read the file content to check for the deprecated call
with open("auth/dynamic_client_registration.py", "r") as f:
content = f.read()
# Should not contain the deprecated datetime.now(UTC)
assert "datetime.now(UTC)" not in content
# Should contain the modern replacement
assert "datetime.now(timezone.utc)" in content or "datetime.now(tz=" in content
def test_no_datetime_utcnow_in_calendar_tools(self):
"""Test that datetime.now(UTC) has been replaced in calendar_tools.py"""
# Read the file content to check for the deprecated call
with open("gcalendar/calendar_tools.py", "r") as f:
content = f.read()
# Should not contain the deprecated datetime.now(UTC)
assert "datetime.now(UTC)" not in content
# Should contain the modern replacement
assert "datetime.now(timezone.utc)" in content
# Test execution summary
def test_all_oauth_fixes_working():
"""Integration test to verify all OAuth fixes are working together."""
# Import everything that was problematic before
from config.settings import settings
# Get scopes through the full chain
scopes = settings.drive_scopes
# Validate the complete OAuth scope chain works
assert isinstance(scopes, list)
assert len(scopes) > 0
# Should contain essential OAuth scopes
assert "https://www.googleapis.com/auth/userinfo.email" in scopes
assert "openid" in scopes
# Should contain Google service scopes
has_drive_scope = any("drive" in scope for scope in scopes)
assert has_drive_scope, "No Drive scopes found in the complete OAuth chain"
print(f"✅ All OAuth fixes validated - {len(scopes)} scopes available")