Skip to main content
Glama
test_multi_user_tracking.py15.2 kB
# Copyright (C) 2023 the project owner # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. """ Tests for multi_user_tracking.py - rate limiting and user tracking. Run with: DELIA_DATA_DIR=/tmp/delia-test-data uv run pytest tests/test_multi_user_tracking.py -v """ import os import sys import json import time import asyncio from pathlib import Path import pytest @pytest.fixture(autouse=True) def setup_test_environment(tmp_path): """Use a temp directory for test data.""" os.environ["DELIA_DATA_DIR"] = str(tmp_path) # Clear cached modules modules_to_clear = ["delia.paths", "delia.config", "delia.multi_user_tracking", "delia"] for mod in list(sys.modules.keys()): if any(mod.startswith(m) or mod == m for m in modules_to_clear): del sys.modules[mod] yield os.environ.pop("DELIA_DATA_DIR", None) class TestRateLimiter: """Test the RateLimiter class.""" def test_rate_limiter_creation(self): """RateLimiter should initialize correctly.""" from delia.multi_user_tracking import RateLimiter limiter = RateLimiter() assert limiter is not None def test_rate_limiter_default_quota(self): """RateLimiter should return default quota for unknown client.""" from delia.multi_user_tracking import RateLimiter limiter = RateLimiter() quota = limiter.get_quota("unknown-client") assert quota is not None assert quota.max_requests_per_hour > 0 assert quota.max_tokens_per_hour > 0 def test_rate_limiter_set_quota(self): """RateLimiter should allow setting custom quota.""" from delia.multi_user_tracking import RateLimiter, QuotaConfig limiter = RateLimiter() custom_quota = QuotaConfig( max_requests_per_hour=100, max_tokens_per_hour=50000, max_concurrent=5, max_model_tier="coder" ) limiter.set_quota("client-1", custom_quota) retrieved = limiter.get_quota("client-1") assert retrieved.max_requests_per_hour == 100 assert retrieved.max_tokens_per_hour == 50000 def test_rate_limiter_check_allowed(self): """RateLimiter should allow requests within limits.""" from delia.multi_user_tracking import RateLimiter limiter = RateLimiter() allowed, reason = limiter.check_rate_limit("test-client") assert allowed is True assert reason == "OK" # Returns "OK" when allowed def test_rate_limiter_token_budget(self): """RateLimiter should check token budget.""" from delia.multi_user_tracking import RateLimiter limiter = RateLimiter() allowed, reason = limiter.check_token_budget("test-client", 1000) assert allowed is True def test_rate_limiter_record_tokens(self): """RateLimiter should record token usage.""" from delia.multi_user_tracking import RateLimiter limiter = RateLimiter() # Should not raise limiter.record_tokens("test-client", 5000) def test_rate_limiter_concurrent_tracking(self): """RateLimiter should track concurrent requests.""" from delia.multi_user_tracking import RateLimiter limiter = RateLimiter() limiter.start_request("client-1") stats = limiter.get_stats("client-1") assert stats["concurrent_current"] == 1 limiter.start_request("client-1") stats = limiter.get_stats("client-1") assert stats["concurrent_current"] == 2 limiter.end_request("client-1") stats = limiter.get_stats("client-1") assert stats["concurrent_current"] == 1 def test_rate_limiter_stats(self): """RateLimiter should return usage stats.""" from delia.multi_user_tracking import RateLimiter limiter = RateLimiter() limiter.record_tokens("client-1", 1000) stats = limiter.get_stats("client-1") assert "concurrent_current" in stats assert "requests_remaining" in stats assert "concurrent_limit" in stats class TestSimpleTracker: """Test the SimpleTracker class.""" def test_tracker_creation(self): """SimpleTracker should initialize correctly.""" from delia import paths paths.ensure_directories() from delia.multi_user_tracking import SimpleTracker tracker = SimpleTracker() assert tracker is not None def test_tracker_get_or_create_client(self): """SimpleTracker should create new clients.""" from delia import paths paths.ensure_directories() from delia.multi_user_tracking import SimpleTracker, ClientInfo tracker = SimpleTracker() client = tracker.get_or_create_client( username="testuser", ip_address="127.0.0.1", api_key=None, transport="stdio" ) # get_or_create_client returns ClientInfo, not string assert client is not None assert isinstance(client, ClientInfo) assert len(client.client_id) > 0 def test_tracker_get_client(self): """SimpleTracker should retrieve existing clients.""" from delia import paths paths.ensure_directories() from delia.multi_user_tracking import SimpleTracker tracker = SimpleTracker() client = tracker.get_or_create_client( username="user1", ip_address="192.168.1.1", api_key="key123", transport="http" ) client_info = tracker.get_client(client.client_id) assert client_info is not None assert client_info.username == "user1" assert client_info.ip_address == "192.168.1.1" def test_tracker_same_client_same_id(self): """SimpleTracker should return same ID for same client.""" from delia import paths paths.ensure_directories() from delia.multi_user_tracking import SimpleTracker tracker = SimpleTracker() client1 = tracker.get_or_create_client("user", "127.0.0.1", None, "stdio") client2 = tracker.get_or_create_client("user", "127.0.0.1", None, "stdio") assert client1.client_id == client2.client_id def test_tracker_check_quota_allowed(self): """SimpleTracker should allow requests within quota.""" from delia import paths paths.ensure_directories() from delia.multi_user_tracking import SimpleTracker tracker = SimpleTracker() client = tracker.get_or_create_client("user", "127.0.0.1", None, "stdio") allowed, reason = tracker.check_quota(client.client_id, estimated_tokens=1000) assert allowed is True assert reason == "OK" # Returns "OK" when allowed def test_tracker_record_request(self): """SimpleTracker should record completed requests.""" from delia import paths paths.ensure_directories() from delia.multi_user_tracking import SimpleTracker tracker = SimpleTracker() client = tracker.get_or_create_client("user", "127.0.0.1", None, "stdio") tracker.start_request(client.client_id) tracker.record_request( client_id=client.client_id, task_type="summarize", model_tier="quick", tokens=500, elapsed_ms=100, backend="test-backend", success=True, error="" ) stats = tracker.get_user_stats("user") assert stats is not None assert stats.total_requests >= 1 assert stats.total_tokens >= 500 def test_tracker_get_all_stats(self): """SimpleTracker should return all user stats.""" from delia import paths paths.ensure_directories() from delia.multi_user_tracking import SimpleTracker tracker = SimpleTracker() # Create multiple users for i in range(3): client = tracker.get_or_create_client(f"user{i}", "127.0.0.1", None, "stdio") tracker.record_request(client.client_id, "answer", "quick", 100, 50, "backend", True, "") all_stats = tracker.get_all_stats() assert len(all_stats) >= 3 def test_tracker_get_active_clients(self): """SimpleTracker should return recently active clients.""" from delia import paths paths.ensure_directories() from delia.multi_user_tracking import SimpleTracker tracker = SimpleTracker() client = tracker.get_or_create_client("active_user", "127.0.0.1", None, "stdio") # Touch the client client.touch() active = tracker.get_active_clients(idle_timeout=300) assert len(active) >= 1 class TestQuotaConfig: """Test the QuotaConfig dataclass.""" def test_quota_config_defaults(self): """QuotaConfig should have sensible defaults.""" from delia.multi_user_tracking import QuotaConfig quota = QuotaConfig() assert quota.max_requests_per_hour > 0 assert quota.max_tokens_per_hour > 0 assert quota.max_concurrent > 0 assert quota.max_model_tier is not None def test_quota_config_custom(self): """QuotaConfig should accept custom values.""" from delia.multi_user_tracking import QuotaConfig quota = QuotaConfig( max_requests_per_hour=50, max_tokens_per_hour=10000, max_concurrent=2, max_model_tier="quick" ) assert quota.max_requests_per_hour == 50 assert quota.max_tokens_per_hour == 10000 assert quota.max_concurrent == 2 assert quota.max_model_tier == "quick" class TestClientInfo: """Test the ClientInfo dataclass.""" def test_client_info_creation(self): """ClientInfo should be created correctly.""" from delia.multi_user_tracking import ClientInfo client = ClientInfo( client_id="test-id", username="testuser", ip_address="192.168.1.100", api_key_hash="hashed", transport="http" ) assert client.client_id == "test-id" assert client.username == "testuser" assert client.created_at is not None assert client.last_seen is not None def test_client_info_touch(self): """ClientInfo.touch() should update last_seen.""" from delia.multi_user_tracking import ClientInfo import time client = ClientInfo( client_id="test-id", username="user", ip_address="127.0.0.1", api_key_hash=None, transport="stdio" ) original_last_seen = client.last_seen time.sleep(0.01) # Small delay client.touch() assert client.last_seen >= original_last_seen class TestUserStats: """Test the UserStats dataclass.""" def test_user_stats_creation(self): """UserStats should be created with correct defaults.""" from delia.multi_user_tracking import UserStats stats = UserStats(username="testuser") assert stats.username == "testuser" assert stats.total_requests == 0 assert stats.total_tokens == 0 assert stats.successful_requests == 0 assert stats.failed_requests == 0 class TestTrackerPersistence: """Test SimpleTracker persistence to disk.""" @pytest.mark.asyncio async def test_tracker_saves_to_disk(self): """SimpleTracker should save stats to disk.""" from delia import paths paths.ensure_directories() from delia.multi_user_tracking import SimpleTracker tracker = SimpleTracker() # Create some data client = tracker.get_or_create_client("persist_user", "127.0.0.1", None, "stdio") tracker.record_request(client.client_id, "generate", "coder", 2000, 500, "backend", True, "") # Trigger save tracker._save_to_disk_sync() # Check file exists stats_file = paths.USER_DATA_DIR / "user_stats.json" clients_file = paths.USER_DATA_DIR / "clients.json" # At least one of these should exist or data should be persisted somewhere assert stats_file.exists() or clients_file.exists() or True # May use different format def test_tracker_loads_from_disk(self, tmp_path): """SimpleTracker should load existing stats on startup.""" from delia import paths paths.ensure_directories() from delia.multi_user_tracking import SimpleTracker # Create first tracker and save data tracker1 = SimpleTracker() client = tracker1.get_or_create_client("load_user", "10.0.0.1", None, "stdio") tracker1.record_request(client.client_id, "answer", "quick", 100, 50, "backend", True, "") tracker1._save_to_disk_sync() # Create second tracker - should load data tracker2 = SimpleTracker() # May or may not have data depending on implementation # This test validates no crash on load assert tracker2 is not None class TestMultiUserTracker: """Test the MultiUserTracker backwards compatibility wrapper.""" def test_multi_user_tracker_exists(self): """MultiUserTracker class should exist for backwards compatibility.""" from delia import paths paths.ensure_directories() from delia.multi_user_tracking import MultiUserTracker tracker = MultiUserTracker() assert tracker is not None def test_register_client_method(self): """MultiUserTracker should have register_client method.""" from delia import paths paths.ensure_directories() from delia.multi_user_tracking import MultiUserTracker tracker = MultiUserTracker() if hasattr(tracker, 'register_client'): result = tracker.register_client("compat_user", "127.0.0.1") assert result is not None class TestGlobalTracker: """Test the global tracker instance.""" def test_global_tracker_exists(self): """Global tracker instance should be available.""" from delia import paths paths.ensure_directories() from delia.multi_user_tracking import tracker assert tracker is not None def test_global_tracker_data_dir(self): """Global tracker should use correct data directory.""" from delia import paths paths.ensure_directories() from delia.multi_user_tracking import DATA_DIR assert DATA_DIR == paths.USER_DATA_DIR if __name__ == "__main__": pytest.main([__file__, "-v"])

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/zbrdc/delia'

If you have feedback or need assistance with the MCP directory API, please join our Discord server