Enhance performance tests

This commit is contained in:
Oliver Falk
2025-10-24 13:51:45 +02:00
parent f0c604a523
commit 9cf1cb4745
74 changed files with 965 additions and 578 deletions

View File

@@ -1,5 +1,4 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Libravatar Deployment Verification Script
@@ -18,6 +17,7 @@ Usage:
import argparse
import json
import os
import random
import ssl
import subprocess
@@ -54,12 +54,19 @@ class Colors:
def colored_print(message: str, color: str = Colors.NC) -> None:
"""Print a colored message."""
print(f"{color}{message}{Colors.NC}")
"""Print a colored message with immediate flush."""
print(f"{color}{message}{Colors.NC}", flush=True)
def get_current_commit_hash() -> Optional[str]:
"""Get the current commit hash from git."""
"""Get the current commit hash from git or CI environment."""
# First try GitLab CI environment variable (most reliable in CI)
ci_commit = os.environ.get("CI_COMMIT_SHA")
if ci_commit:
colored_print(f"Using CI commit hash: {ci_commit}", Colors.BLUE)
return ci_commit
# Fallback to git command
try:
result = subprocess.run(
["git", "rev-parse", "HEAD"],
@@ -67,8 +74,11 @@ def get_current_commit_hash() -> Optional[str]:
text=True,
check=True,
)
return result.stdout.strip()
commit_hash = result.stdout.strip()
colored_print(f"Using git commit hash: {commit_hash}", Colors.BLUE)
return commit_hash
except (subprocess.CalledProcessError, FileNotFoundError):
colored_print("Could not determine current commit hash", Colors.RED)
return None
@@ -82,16 +92,44 @@ def is_commit_newer_or_equal(commit1: str, commit2: str) -> Optional[bool]:
None if comparison fails
"""
try:
# Use git merge-base to check if commit1 is reachable from commit2
# If commit1 is newer or equal, it should be reachable from commit2
subprocess.run(
["git", "merge-base", "--is-ancestor", commit2, commit1],
capture_output=True,
check=True,
)
return True
# First try to get commit timestamps for comparison
try:
result1 = subprocess.run(
["git", "show", "-s", "--format=%ct", commit1],
capture_output=True,
text=True,
check=True,
)
result2 = subprocess.run(
["git", "show", "-s", "--format=%ct", commit2],
capture_output=True,
text=True,
check=True,
)
timestamp1 = int(result1.stdout.strip())
timestamp2 = int(result2.stdout.strip())
colored_print(f"Commit {commit1[:8]} timestamp: {timestamp1}", Colors.BLUE)
colored_print(f"Commit {commit2[:8]} timestamp: {timestamp2}", Colors.BLUE)
# commit1 is newer if it has a later timestamp
return timestamp1 >= timestamp2
except (subprocess.CalledProcessError, ValueError):
# Fallback to merge-base if timestamp comparison fails
colored_print("Timestamp comparison failed, trying merge-base", Colors.YELLOW)
# Use git merge-base to check if commit2 is ancestor of commit1
subprocess.run(
["git", "merge-base", "--is-ancestor", commit2, commit1],
capture_output=True,
check=True,
)
return True
except subprocess.CalledProcessError:
# If the above fails, try the reverse - check if commit2 is newer
# If the above fails, try the reverse
try:
subprocess.run(
["git", "merge-base", "--is-ancestor", commit1, commit2],
@@ -100,8 +138,11 @@ def is_commit_newer_or_equal(commit1: str, commit2: str) -> Optional[bool]:
)
return False
except subprocess.CalledProcessError:
# If both fail, we can't determine the relationship
colored_print("Git comparison failed - shallow clone or missing commits", Colors.YELLOW)
return None
except Exception as e:
colored_print(f"Git comparison error: {e}", Colors.RED)
return None
def make_request(
@@ -346,17 +387,30 @@ def test_deployment(
# Check if we're looking for a specific version and compare
current_commit = get_current_commit_hash()
version_ok = True
if current_commit and deployed_commit != "Unknown":
colored_print(f"Expected commit: {current_commit[:8]}...", Colors.BLUE)
colored_print(f"Deployed commit: {deployed_commit[:8]}...", Colors.BLUE)
if deployed_commit == current_commit:
colored_print(
"✅ Exact version match - deployment is up to date!",
Colors.GREEN,
)
elif deployed_commit.startswith(current_commit[:8]) or current_commit.startswith(deployed_commit[:8]):
# Handle case where we have short vs long commit hashes
colored_print(
"✅ Version match (short hash) - deployment is up to date!",
Colors.GREEN,
)
else:
# Check if deployed version is newer
# Check if deployed version is newer using git
comparison = is_commit_newer_or_equal(
deployed_commit, current_commit
)
colored_print(f"Commit comparison result: {comparison}", Colors.BLUE)
if comparison is True:
colored_print(
" Note: A newer version is already deployed (this is fine!)",
@@ -364,43 +418,66 @@ def test_deployment(
)
elif comparison is False:
colored_print(
"⚠️ Warning: Deployed version appears to be older than expected",
f"⚠️ Deployed version ({deployed_commit[:8]}) is older than expected ({current_commit[:8]})",
Colors.YELLOW,
)
else:
colored_print(
"⚠️ Warning: Could not determine version relationship",
f"Waiting for deployment to update... (attempt {attempt}/{max_retries})",
Colors.BLUE,
)
version_ok = False
else:
# Git comparison failed - use simple string comparison as fallback
colored_print(
"⚠️ Git comparison failed - using string comparison fallback",
Colors.YELLOW,
)
# Run functionality tests
colored_print("Running basic functionality tests...", Colors.YELLOW)
# Test avatar redirect
if test_avatar_redirect(base_url):
colored_print("✅ Invalid avatar redirects correctly", Colors.GREEN)
# If commits are different, assume we need to wait
# This is safer than proceeding with wrong version
colored_print(
f"⚠️ Deployed version ({deployed_commit[:8]}) differs from expected ({current_commit[:8]})",
Colors.YELLOW,
)
colored_print(
f"Waiting for deployment to update... (attempt {attempt}/{max_retries})",
Colors.BLUE,
)
version_ok = False
# Only proceed with functionality tests if version is correct
if not version_ok:
# Version is not correct, skip tests and retry
pass # Will continue to retry logic below
else:
colored_print("❌ Invalid avatar redirect failed", Colors.RED)
return False
# Run functionality tests
colored_print("Running basic functionality tests...", Colors.YELLOW)
# Test avatar sizing
if test_avatar_sizing(base_url):
pass # Success messages are printed within the function
else:
return False
# Test avatar redirect
if test_avatar_redirect(base_url):
colored_print("✅ Invalid avatar redirects correctly", Colors.GREEN)
else:
colored_print("❌ Invalid avatar redirect failed", Colors.RED)
return False
# Test stats endpoint
if test_stats_endpoint(base_url):
colored_print("✅ Stats endpoint working", Colors.GREEN)
else:
colored_print("❌ Stats endpoint failed", Colors.RED)
return False
# Test avatar sizing
if test_avatar_sizing(base_url):
pass # Success messages are printed within the function
else:
return False
colored_print(
f"🎉 {name} deployment verification completed successfully!",
Colors.GREEN,
)
return True
# Test stats endpoint
if test_stats_endpoint(base_url):
colored_print("✅ Stats endpoint working", Colors.GREEN)
else:
colored_print("❌ Stats endpoint failed", Colors.RED)
return False
colored_print(
f"🎉 {name} deployment verification completed successfully!",
Colors.GREEN,
)
return True
else:
colored_print(f"{name} site not responding yet...", Colors.YELLOW)
@@ -408,7 +485,11 @@ def test_deployment(
colored_print(
f"Waiting {retry_delay} seconds before next attempt...", Colors.BLUE
)
time.sleep(retry_delay)
# Show progress during wait
for remaining in range(retry_delay, 0, -1):
print(f"\r⏳ Retrying in {remaining:2d} seconds...", end="", flush=True)
time.sleep(1)
print("\r" + " " * 30 + "\r", end="", flush=True) # Clear the line
colored_print(
f"❌ FAILED: {name} deployment verification timed out after {max_retries} attempts",