chore: import upstream snapshot with attribution
docs / deploy (push) Has been cancelled
docs / changes (push) Has been cancelled
docs / check-and-build (push) Has been cancelled
build container image / cpu (push) Has been cancelled
build container image / cuda (push) Has been cancelled
build container image / rocm (push) Has been cancelled
frontend checks / frontend-checks (push) Has been cancelled
frontend tests / frontend-tests (push) Has been cancelled
lfs checks / lfs-check (push) Has been cancelled
python checks / python-checks (push) Has been cancelled
python tests / py3.12: macos-default (push) Has been cancelled
python tests / py3.11: windows-cpu (push) Has been cancelled
python tests / py3.12: windows-cpu (push) Has been cancelled
python tests / py3.11: linux-cpu (push) Has been cancelled
typegen checks / typegen-checks (push) Has been cancelled
uv lock checks / uv-lock-checks (push) Has been cancelled
openapi checks / openapi-checks (push) Has been cancelled
python tests / py3.11: macos-default (push) Has been cancelled
python tests / py3.12: linux-cpu (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:22:06 +08:00
commit cddb07a176
3370 changed files with 685519 additions and 0 deletions
+474
View File
@@ -0,0 +1,474 @@
"""Performance tests for multiuser authentication system.
These tests measure the performance overhead of authentication and
ensure the system performs acceptably under load.
"""
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from logging import Logger
import pytest
from invokeai.app.services.auth.password_utils import hash_password, verify_password
from invokeai.app.services.auth.token_service import TokenData, create_access_token, verify_token
from invokeai.app.services.shared.sqlite.sqlite_database import SqliteDatabase
from invokeai.app.services.users.users_common import UserCreateRequest
from invokeai.app.services.users.users_default import UserService
@pytest.fixture
def logger() -> Logger:
"""Create a logger for testing."""
return Logger("test_performance")
@pytest.fixture
def user_service(logger: Logger) -> UserService:
"""Create a user service with in-memory database for testing."""
db = SqliteDatabase(db_path=None, logger=logger, verbose=False)
# Create users table
db._conn.execute("""
CREATE TABLE users (
user_id TEXT NOT NULL PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
display_name TEXT,
password_hash TEXT NOT NULL,
is_admin BOOLEAN NOT NULL DEFAULT FALSE,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')),
updated_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')),
last_login_at DATETIME
);
""")
db._conn.commit()
return UserService(db)
class TestPasswordPerformance:
"""Tests for password hashing and verification performance."""
def test_password_hashing_performance(self):
"""Test that password hashing completes in reasonable time.
bcrypt is intentionally slow for security. Each hash should take
approximately 50-100ms on modern hardware.
"""
password = "TestPassword123"
iterations = 10
start_time = time.time()
for _ in range(iterations):
hash_password(password)
elapsed_time = time.time() - start_time
avg_time_ms = (elapsed_time / iterations) * 1000
# Each hash should take between 10ms and 500ms
# (bcrypt is designed to be slow, 50-100ms is typical)
assert 10 < avg_time_ms < 500, f"Password hashing took {avg_time_ms:.2f}ms per hash"
# Log performance for reference
print(f"\nPassword hashing performance: {avg_time_ms:.2f}ms per hash")
def test_password_verification_performance(self):
"""Test that password verification completes in reasonable time."""
password = "TestPassword123"
hashed = hash_password(password)
iterations = 10
start_time = time.time()
for _ in range(iterations):
verify_password(password, hashed)
elapsed_time = time.time() - start_time
avg_time_ms = (elapsed_time / iterations) * 1000
# Verification should take similar time to hashing
assert 10 < avg_time_ms < 500, f"Password verification took {avg_time_ms:.2f}ms per verification"
print(f"Password verification performance: {avg_time_ms:.2f}ms per verification")
def test_concurrent_password_operations(self):
"""Test password operations under concurrent load."""
password = "TestPassword123"
num_operations = 20
def hash_and_verify():
hashed = hash_password(password)
return verify_password(password, hashed)
start_time = time.time()
with ThreadPoolExecutor(max_workers=4) as executor:
futures = [executor.submit(hash_and_verify) for _ in range(num_operations)]
results = [future.result() for future in as_completed(futures)]
elapsed_time = time.time() - start_time
# All operations should succeed
assert all(results)
# Total time should be less than sequential time due to parallelization
print(f"Concurrent password operations ({num_operations}): {elapsed_time:.2f}s total")
class TestTokenPerformance:
"""Tests for JWT token performance."""
def test_token_creation_performance(self):
"""Test that token creation is fast."""
token_data = TokenData(
user_id="user123",
email="test@example.com",
is_admin=False,
)
iterations = 1000
start_time = time.time()
for _ in range(iterations):
create_access_token(token_data)
elapsed_time = time.time() - start_time
avg_time_ms = (elapsed_time / iterations) * 1000
# Token creation should be very fast (< 1ms per token)
assert avg_time_ms < 1.0, f"Token creation took {avg_time_ms:.3f}ms per token"
print(f"\nToken creation performance: {avg_time_ms:.3f}ms per token")
def test_token_verification_performance(self):
"""Test that token verification is fast."""
token_data = TokenData(
user_id="user123",
email="test@example.com",
is_admin=False,
)
token = create_access_token(token_data)
iterations = 1000
start_time = time.time()
for _ in range(iterations):
verify_token(token)
elapsed_time = time.time() - start_time
avg_time_ms = (elapsed_time / iterations) * 1000
# Token verification should be very fast (< 1ms per verification)
assert avg_time_ms < 1.0, f"Token verification took {avg_time_ms:.3f}ms per verification"
print(f"Token verification performance: {avg_time_ms:.3f}ms per verification")
def test_concurrent_token_operations(self):
"""Test token operations under concurrent load."""
token_data = TokenData(
user_id="user123",
email="test@example.com",
is_admin=False,
)
num_operations = 1000
def create_and_verify():
token = create_access_token(token_data)
verified = verify_token(token)
return verified is not None
start_time = time.time()
with ThreadPoolExecutor(max_workers=10) as executor:
futures = [executor.submit(create_and_verify) for _ in range(num_operations)]
results = [future.result() for future in as_completed(futures)]
elapsed_time = time.time() - start_time
# All operations should succeed
assert all(results)
ops_per_second = num_operations / elapsed_time
print(f"Concurrent token operations: {ops_per_second:.0f} ops/second")
# Should handle at least 1000 operations per second
assert ops_per_second > 1000, f"Only {ops_per_second:.0f} ops/second"
class TestAuthenticationOverhead:
"""Tests for overall authentication system overhead."""
def test_login_flow_performance(self, user_service: UserService):
"""Test complete login flow performance."""
# Create a user
user_data = UserCreateRequest(
email="perf@example.com",
display_name="Performance Test",
password="TestPass123",
is_admin=False,
)
user_service.create(user_data)
iterations = 10
start_time = time.time()
for _ in range(iterations):
# Simulate login flow
user = user_service.authenticate("perf@example.com", "TestPass123")
assert user is not None
# Create token
token_data = TokenData(
user_id=user.user_id,
email=user.email,
is_admin=user.is_admin,
)
token = create_access_token(token_data)
# Verify token
verified = verify_token(token)
assert verified is not None
elapsed_time = time.time() - start_time
avg_time_ms = (elapsed_time / iterations) * 1000
# Complete login flow should complete in reasonable time
# Most of the time is spent on password verification (50-100ms)
assert avg_time_ms < 500, f"Login flow took {avg_time_ms:.2f}ms"
print(f"\nComplete login flow performance: {avg_time_ms:.2f}ms per login")
def test_token_verification_overhead(self):
"""Measure overhead of token verification vs no auth."""
token_data = TokenData(
user_id="user123",
email="test@example.com",
is_admin=False,
)
token = create_access_token(token_data)
iterations = 10000
# Measure token verification time
start_time = time.time()
for _ in range(iterations):
verify_token(token)
verification_time = time.time() - start_time
# Measure baseline (minimal operation)
start_time = time.time()
for _ in range(iterations):
# Simulate minimal auth check
_ = token is not None
baseline_time = time.time() - start_time
overhead_ms = ((verification_time - baseline_time) / iterations) * 1000
# Overhead should be minimal (< 0.1ms per request)
assert overhead_ms < 0.1, f"Token verification adds {overhead_ms:.4f}ms overhead per request"
print(f"Token verification overhead: {overhead_ms:.4f}ms per request")
class TestUserServicePerformance:
"""Tests for user service performance."""
def test_user_creation_performance(self, user_service: UserService):
"""Test user creation performance."""
iterations = 10
start_time = time.time()
for i in range(iterations):
user_data = UserCreateRequest(
email=f"user{i}@example.com",
display_name=f"User {i}",
password="TestPass123",
is_admin=False,
)
user_service.create(user_data)
elapsed_time = time.time() - start_time
avg_time_ms = (elapsed_time / iterations) * 1000
# User creation includes password hashing, so should be ~50-150ms
assert avg_time_ms < 500, f"User creation took {avg_time_ms:.2f}ms per user"
print(f"\nUser creation performance: {avg_time_ms:.2f}ms per user")
def test_user_lookup_performance(self, user_service: UserService):
"""Test user lookup performance."""
# Create some users
for i in range(10):
user_data = UserCreateRequest(
email=f"lookup{i}@example.com",
display_name=f"Lookup User {i}",
password="TestPass123",
is_admin=False,
)
user_service.create(user_data)
iterations = 1000
# Test lookup by email
start_time = time.time()
for _ in range(iterations):
user_service.get_by_email("lookup5@example.com")
elapsed_time = time.time() - start_time
avg_time_ms = (elapsed_time / iterations) * 1000
# Lookup should be fast (< 1ms with proper indexing)
assert avg_time_ms < 5.0, f"User lookup took {avg_time_ms:.3f}ms per lookup"
print(f"User lookup by email performance: {avg_time_ms:.3f}ms per lookup")
def test_user_list_performance(self, user_service: UserService):
"""Test user list performance with many users."""
# Create many users
num_users = 100
for i in range(num_users):
user_data = UserCreateRequest(
email=f"listuser{i}@example.com",
display_name=f"List User {i}",
password="TestPass123",
is_admin=False,
)
user_service.create(user_data)
# Test listing users
iterations = 10
start_time = time.time()
for _ in range(iterations):
user_service.list_users(limit=50)
elapsed_time = time.time() - start_time
avg_time_ms = (elapsed_time / iterations) * 1000
# Listing users should be fast (< 10ms for reasonable page size)
assert avg_time_ms < 50.0, f"User listing took {avg_time_ms:.2f}ms"
print(f"User listing performance (50 users): {avg_time_ms:.2f}ms per query")
class TestConcurrentUserSessions:
"""Tests for concurrent user session handling."""
def test_multiple_concurrent_logins(self, user_service: UserService):
"""Test handling multiple concurrent user logins."""
# Create test users
num_users = 20
for i in range(num_users):
user_data = UserCreateRequest(
email=f"concurrent{i}@example.com",
display_name=f"Concurrent User {i}",
password="TestPass123",
is_admin=False,
)
user_service.create(user_data)
def authenticate_user(user_index: int):
# Authenticate
user = user_service.authenticate(f"concurrent{user_index}@example.com", "TestPass123")
if user is None:
return False
# Create token
token_data = TokenData(
user_id=user.user_id,
email=user.email,
is_admin=user.is_admin,
)
token = create_access_token(token_data)
# Verify token
verified = verify_token(token)
return verified is not None
start_time = time.time()
# Simulate concurrent logins
with ThreadPoolExecutor(max_workers=10) as executor:
futures = [executor.submit(authenticate_user, i) for i in range(num_users)]
results = [future.result() for future in as_completed(futures)]
elapsed_time = time.time() - start_time
# All logins should succeed
assert all(results), "Some concurrent logins failed"
print(f"\nConcurrent logins ({num_users} users): {elapsed_time:.2f}s total")
# Should complete in reasonable time
assert elapsed_time < 10.0, f"Concurrent logins took {elapsed_time:.2f}s"
@pytest.mark.slow
class TestScalabilityBenchmarks:
"""Scalability benchmarks (marked as slow tests)."""
def test_authentication_under_load(self, user_service: UserService):
"""Test authentication system under sustained load."""
# Create test users
num_users = 50
for i in range(num_users):
user_data = UserCreateRequest(
email=f"load{i}@example.com",
display_name=f"Load User {i}",
password="TestPass123",
is_admin=False,
)
user_service.create(user_data)
def simulate_user_activity(user_index: int, num_requests: int):
success_count = 0
for _ in range(num_requests):
# Authenticate
user = user_service.authenticate(f"load{user_index}@example.com", "TestPass123")
if user is None:
continue
# Create and verify token
token_data = TokenData(user_id=user.user_id, email=user.email, is_admin=user.is_admin)
token = create_access_token(token_data)
verified = verify_token(token)
if verified is not None:
success_count += 1
return success_count
# Simulate sustained load
requests_per_user = 5
total_requests = num_users * requests_per_user
start_time = time.time()
with ThreadPoolExecutor(max_workers=10) as executor:
futures = [executor.submit(simulate_user_activity, i, requests_per_user) for i in range(num_users)]
success_counts = [future.result() for future in as_completed(futures)]
elapsed_time = time.time() - start_time
total_success = sum(success_counts)
success_rate = (total_success / total_requests) * 100
requests_per_second = total_requests / elapsed_time
print("\nLoad test results:")
print(f" Total requests: {total_requests}")
print(f" Success rate: {success_rate:.1f}%")
print(f" Requests/second: {requests_per_second:.0f}")
print(f" Total time: {elapsed_time:.2f}s")
# Should maintain high success rate under load
assert success_rate > 95.0, f"Success rate only {success_rate:.1f}%"
# Should handle reasonable throughput
# Note: This is limited by bcrypt hashing speed
assert requests_per_second > 5.0, f"Only {requests_per_second:.1f} req/s"