AIstudioProxyAPI / tests /test_smart_rotation_fix.py
peijun1's picture
Deploy AI Studio Proxy API to Hugging Face Spaces
a5784e9
Raw
History Blame Contribute Delete
7.65 kB
"""
Test for smart auth profile rotation fix
Tests that rotation properly considers model-specific cooldowns
"""
import json
import os
import tempfile
import unittest
from datetime import datetime, timedelta
from unittest.mock import patch
# Import the functions we want to test
from browser_utils.auth_rotation import _find_best_profile_in_dirs, _normalize_model_id
class TestSmartRotationFix(unittest.TestCase):
"""Test smart rotation logic with model-specific cooldowns"""
def setUp(self):
"""Set up test environment"""
self.test_dir = tempfile.mkdtemp()
self.saved_dir = os.path.join(self.test_dir, "saved")
self.emergency_dir = os.path.join(self.test_dir, "emergency")
os.makedirs(self.saved_dir, exist_ok=True)
os.makedirs(self.emergency_dir, exist_ok=True)
# Create test profile files
self.profile1 = os.path.join(self.saved_dir, "profile1.json")
self.profile2 = os.path.join(self.saved_dir, "profile2.json")
self.profile3 = os.path.join(self.saved_dir, "profile3.json")
self.emergency_profile = os.path.join(self.emergency_dir, "emergency.json")
# Create dummy profile content
profile_content = {"cookies": [{"name": "test", "value": "test"}]}
for profile_path in [
self.profile1,
self.profile2,
self.profile3,
self.emergency_profile,
]:
with open(profile_path, "w") as f:
json.dump(profile_content, f)
def tearDown(self):
"""Clean up test environment"""
import shutil
shutil.rmtree(self.test_dir, ignore_errors=True)
def test_normalize_model_id(self):
"""Test model ID normalization"""
test_cases = [
("gemini 3 pro preview", "gemini-3-pro-preview"),
("gemini-2.5-pro", "gemini-2.5-pro"),
(
"gemini 2.5 pro",
"gemini-2.5-pro",
), # Should preserve dots for known models
("default", "default"),
("", "default"),
(None, "default"),
]
for input_id, expected in test_cases:
result = _normalize_model_id(input_id)
self.assertEqual(result, expected, f"Failed for input: {input_id}")
def test_find_best_profile_gemini_3_pro_preview(self):
"""Test that profiles with gemini-3-pro-preview cooldown are excluded"""
# Mock cooldown data similar to user's config
cooldown_data = {
self.profile1: {
"gemini-3-pro-preview": (
datetime.now() + timedelta(hours=1)
).timestamp(),
"default": (datetime.now() + timedelta(hours=1)).timestamp(),
},
self.profile2: {
"default": (datetime.now() + timedelta(hours=1)).timestamp()
},
# profile3 has no cooldown - should be selected
# emergency_profile has no cooldown - should be selected
}
with (
patch("browser_utils.auth_rotation._COOLDOWN_PROFILES", cooldown_data),
patch("browser_utils.auth_rotation.get_profile_usage", return_value=1),
):
# Test with gemini-3-pro-preview - should exclude profile1 but include others
best_profile = _find_best_profile_in_dirs(
[self.saved_dir, self.emergency_dir],
target_model_id="gemini 3 pro preview",
)
# Should not be profile1 (has gemini-3-pro-preview cooldown)
self.assertNotEqual(best_profile, self.profile1)
# Should be either profile2, profile3, or emergency_profile
self.assertIn(
best_profile, [self.profile2, self.profile3, self.emergency_profile]
)
def test_find_best_profile_no_model_specific_cooldown(self):
"""Test that profiles without specific model cooldown are included"""
# Mock cooldown data - only default cooldown
cooldown_data = {
self.profile1: {
"default": (datetime.now() + timedelta(hours=1)).timestamp()
},
# Other profiles have no cooldown
}
with (
patch("browser_utils.auth_rotation._COOLDOWN_PROFILES", cooldown_data),
patch("browser_utils.auth_rotation.get_profile_usage", return_value=1),
):
# Test with gemini-3-pro-preview - should include all profiles since none have specific cooldown
best_profile = _find_best_profile_in_dirs(
[self.saved_dir, self.emergency_dir],
target_model_id="gemini 3 pro preview",
)
# Should be able to select any profile (including profile1)
self.assertIsNotNone(best_profile)
def test_find_best_profile_global_cooldown_excludes_all(self):
"""Test that global cooldown excludes all profiles"""
# Mock cooldown data with global cooldown
cooldown_data = {
self.profile1: {
"global": (datetime.now() + timedelta(hours=1)).timestamp()
},
self.profile2: {
"global": (datetime.now() + timedelta(hours=1)).timestamp()
},
self.profile3: {
"global": (datetime.now() + timedelta(hours=1)).timestamp()
},
self.emergency_profile: {
"global": (datetime.now() + timedelta(hours=1)).timestamp()
},
}
with (
patch("browser_utils.auth_rotation._COOLDOWN_PROFILES", cooldown_data),
patch("browser_utils.auth_rotation.get_profile_usage", return_value=1),
):
# Test with any model - should return None since all have global cooldown
best_profile = _find_best_profile_in_dirs(
[self.saved_dir, self.emergency_dir],
target_model_id="gemini 3 pro preview",
)
# Should return None since all profiles are in global cooldown
self.assertIsNone(best_profile)
def test_find_best_profile_expired_cooldown(self):
"""Test that expired cooldowns don't exclude profiles"""
# Mock cooldown data with expired cooldown
cooldown_data = {
self.profile1: {
"gemini-3-pro-preview": (
datetime.now() - timedelta(hours=1)
).timestamp(), # Expired
"default": (datetime.now() - timedelta(hours=1)).timestamp(), # Expired
},
}
with (
patch("browser_utils.auth_rotation._COOLDOWN_PROFILES", cooldown_data),
patch("browser_utils.auth_rotation.get_profile_usage", return_value=1),
):
# Test with gemini-3-pro-preview - should include profile1 since cooldown expired
best_profile = _find_best_profile_in_dirs(
[self.saved_dir, self.emergency_dir],
target_model_id="gemini 3 pro preview",
)
# Should be able to select profile1 since cooldown expired
self.assertIsNotNone(best_profile)
# Profile1 should be selectable since its cooldown expired, but we can't guarantee
# it will be selected over other profiles due to usage-based sorting
valid_profiles = [
self.profile1,
self.profile2,
self.profile3,
self.emergency_profile,
]
self.assertIn(best_profile, valid_profiles)
if __name__ == "__main__":
unittest.main()