mosaic / tests /telemetry /test_utils.py
raylim's picture
feat: implement manual OAuth for HF Spaces Docker SDK
8492a0e
"""Tests for telemetry utility functions."""
import time
import pytest
from mosaic.telemetry.utils import (
StageTimer,
sanitize_error_message,
hash_session_id,
UserInfo,
extract_user_info,
)
class TestStageTimer:
"""Tests for StageTimer context manager."""
def test_basic_timing(self):
"""Test basic timing functionality."""
timings = {}
with StageTimer("test_stage", timings):
time.sleep(0.1)
assert "test_stage_duration_sec" in timings
assert timings["test_stage_duration_sec"] >= 0.1
def test_multiple_stages(self):
"""Test timing multiple stages."""
timings = {}
with StageTimer("stage_a", timings):
time.sleep(0.05)
with StageTimer("stage_b", timings):
time.sleep(0.05)
assert "stage_a_duration_sec" in timings
assert "stage_b_duration_sec" in timings
assert timings["stage_a_duration_sec"] >= 0.05
assert timings["stage_b_duration_sec"] >= 0.05
def test_timing_with_exception(self):
"""Test that timing is recorded even when exception occurs."""
timings = {}
with pytest.raises(ValueError):
with StageTimer("failing_stage", timings):
time.sleep(0.05)
raise ValueError("Test error")
# Timing should still be recorded
assert "failing_stage_duration_sec" in timings
assert timings["failing_stage_duration_sec"] >= 0.05
class TestSanitizeErrorMessage:
"""Tests for error message sanitization."""
def test_sanitize_unix_paths(self):
"""Test sanitization of Unix-style paths."""
message = "File not found: /home/user/data/slide.svs"
sanitized = sanitize_error_message(message)
assert "/home/user" not in sanitized
assert "[PATH]" in sanitized
def test_sanitize_windows_paths(self):
"""Test sanitization of Windows-style paths."""
message = "File not found: C:\\Users\\John\\Documents\\slide.svs"
sanitized = sanitize_error_message(message)
assert "C:\\Users" not in sanitized
assert "[PATH]" in sanitized
def test_sanitize_ip_addresses(self):
"""Test sanitization of IP addresses."""
message = "Connection refused to 192.168.1.100:8080"
sanitized = sanitize_error_message(message)
assert "192.168.1.100" not in sanitized
assert "[IP]" in sanitized
def test_sanitize_email_addresses(self):
"""Test sanitization of email addresses."""
message = "Invalid user: john.doe@example.com"
sanitized = sanitize_error_message(message)
assert "john.doe@example.com" not in sanitized
assert "[EMAIL]" in sanitized
def test_sanitize_urls(self):
"""Test sanitization of URLs."""
message = "Failed to fetch https://api.example.com/data"
sanitized = sanitize_error_message(message)
assert "https://api.example.com" not in sanitized
assert "[URL]" in sanitized
def test_sanitize_multiple_patterns(self):
"""Test sanitization of multiple patterns in one message."""
message = (
"Error at /home/user/app: "
"Could not connect to 10.0.0.1 for user@domain.com"
)
sanitized = sanitize_error_message(message)
assert "/home/user" not in sanitized
assert "10.0.0.1" not in sanitized
assert "user@domain.com" not in sanitized
def test_sanitize_empty_message(self):
"""Test handling of empty message."""
assert sanitize_error_message("") == ""
assert sanitize_error_message(None) is None
def test_sanitize_preserves_error_context(self):
"""Test that error context is preserved."""
message = "ValueError: Invalid configuration"
sanitized = sanitize_error_message(message)
assert "ValueError" in sanitized
assert "Invalid configuration" in sanitized
class TestHashSessionId:
"""Tests for session ID hashing."""
def test_hash_session_id(self):
"""Test basic session ID hashing."""
hashed = hash_session_id("test-session-123")
assert hashed is not None
assert hashed != "test-session-123"
assert len(hashed) == 16 # Truncated to 16 chars
def test_hash_none_returns_none(self):
"""Test that None input returns None."""
assert hash_session_id(None) is None
def test_hash_is_deterministic(self):
"""Test that same input produces same hash."""
hash1 = hash_session_id("session-abc")
hash2 = hash_session_id("session-abc")
assert hash1 == hash2
def test_different_inputs_different_hashes(self):
"""Test that different inputs produce different hashes."""
hash1 = hash_session_id("session-1")
hash2 = hash_session_id("session-2")
assert hash1 != hash2
def test_hash_is_consistent_across_calls(self):
"""Test hash consistency for privacy linking."""
# Same session should always produce same hash
session_id = "user-session-12345"
hashes = [hash_session_id(session_id) for _ in range(10)]
assert len(set(hashes)) == 1 # All hashes should be identical
class TestUserInfo:
"""Tests for UserInfo dataclass."""
def test_default_values(self):
"""Test default UserInfo values."""
user_info = UserInfo()
assert user_info.is_logged_in is False
assert user_info.username is None
def test_custom_values(self):
"""Test UserInfo with custom values."""
user_info = UserInfo(is_logged_in=True, username="testuser")
assert user_info.is_logged_in is True
assert user_info.username == "testuser"
class TestExtractUserInfo:
"""Tests for extract_user_info function."""
def _create_mock_request(self, username: str = None):
"""Helper to create a mock Gradio request object.
In Gradio 6.x+, the request object has a username attribute.
"""
class MockRequest:
def __init__(self, username):
self.username = username
return MockRequest(username)
def test_extract_user_info_with_logged_in_user(self):
"""Test extraction with a logged-in user via OAuthProfile."""
profile = self._create_mock_profile("testuser123")
user_info = extract_user_info(None, is_hf_spaces=True, profile=profile)
assert user_info.is_logged_in is True
assert user_info.username == "testuser123"
def test_extract_user_info_anonymous_user(self):
"""Test extraction for anonymous user (username=None)."""
request = self._create_mock_request(None)
user_info = extract_user_info(request, is_hf_spaces=True)
assert user_info.is_logged_in is False
assert user_info.username is None
def test_extract_user_info_not_hf_spaces(self):
"""Test extraction when not on HF Spaces."""
request = self._create_mock_request("testuser")
# Even with valid username, should return default if is_hf_spaces=False
user_info = extract_user_info(request, is_hf_spaces=False)
assert user_info.is_logged_in is False
assert user_info.username is None
def test_extract_user_info_none_request(self):
"""Test extraction with None request."""
user_info = extract_user_info(None, is_hf_spaces=True)
assert user_info.is_logged_in is False
assert user_info.username is None
def test_extract_user_info_request_without_username_attr(self):
"""Test extraction when request doesn't have username attribute."""
class RequestWithoutUsername:
pass
request = RequestWithoutUsername()
user_info = extract_user_info(request, is_hf_spaces=True)
assert user_info.is_logged_in is False
assert user_info.username is None
def test_extract_user_info_with_special_characters(self):
"""Test extraction with username containing special characters."""
profile = self._create_mock_profile("user-name_123")
user_info = extract_user_info(None, is_hf_spaces=True, profile=profile)
assert user_info.is_logged_in is True
assert user_info.username == "user-name_123"
def test_extract_user_info_empty_string_username(self):
"""Test extraction with empty string username (treated as not logged in)."""
request = self._create_mock_request("")
user_info = extract_user_info(request, is_hf_spaces=True)
assert user_info.is_logged_in is False
assert user_info.username is None
def _create_mock_profile(self, username: str = None):
"""Helper to create a mock OAuthProfile object."""
class MockOAuthProfile:
def __init__(self, username):
self.username = username
if username is None:
return None
return MockOAuthProfile(username)
def test_extract_user_info_from_oauth_profile(self):
"""Test extraction from OAuthProfile (primary path for LoginButton)."""
profile = self._create_mock_profile("oauth_user")
user_info = extract_user_info(None, is_hf_spaces=True, profile=profile)
assert user_info.is_logged_in is True
assert user_info.username == "oauth_user"
def test_extract_user_info_oauth_profile_takes_precedence(self):
"""Test that OAuthProfile takes precedence over request.username."""
request = self._create_mock_request("request_user")
profile = self._create_mock_profile("oauth_user")
user_info = extract_user_info(request, is_hf_spaces=True, profile=profile)
assert user_info.is_logged_in is True
assert user_info.username == "oauth_user"
def test_extract_user_info_ignores_request_username(self):
"""Test that request.username is NOT used (it returns Space owner, not visitor)."""
request = self._create_mock_request("space_owner")
user_info = extract_user_info(request, is_hf_spaces=True, profile=None)
assert user_info.is_logged_in is False
assert user_info.username is None
def test_extract_user_info_no_profile_not_hf_spaces(self):
"""Test that profile is ignored when not on HF Spaces."""
profile = self._create_mock_profile("oauth_user")
user_info = extract_user_info(None, is_hf_spaces=False, profile=profile)
assert user_info.is_logged_in is False
assert user_info.username is None