Files
2026-01-16 19:04:48 +02:00

181 lines
5.6 KiB
TypeScript

#!/usr/bin/env tsx
/**
* Test Redis connection and functionality
* Tests: Connection, Rate Limiting, Caching
*/
import { Redis } from "ioredis";
import { initRedisRateLimiter, isRedisConnected, checkMusicRateLimit } from "@/lib/rate-limit";
import { getCache, setCache, deleteCache } from "@/lib/cache";
async function testRedisConnection() {
console.log("🔍 Testing Redis Connection...\n");
const redisUrl = process.env.REDIS_URL;
if (!redisUrl) {
console.error("❌ REDIS_URL not set in environment");
return false;
}
console.log(`📍 Redis URL: ${redisUrl.replace(/:[^:@]+@/, ":****@")}`);
try {
const redis = new Redis(redisUrl, {
maxRetriesPerRequest: 3,
retryStrategy: (times) => {
const delay = Math.min(times * 50, 2000);
return delay;
},
});
// Test connection
const pong = await redis.ping();
console.log(`✅ Connection test: ${pong}`);
// Test set/get
await redis.set("test:connection", "success", "EX", 10);
const value = await redis.get("test:connection");
console.log(`✅ Set/Get test: ${value === "success" ? "PASSED" : "FAILED"}`);
// Test delete
await redis.del("test:connection");
const deleted = await redis.get("test:connection");
console.log(`✅ Delete test: ${deleted === null ? "PASSED" : "FAILED"}`);
// Get Redis info
const info = await redis.info("server");
const versionMatch = info.match(/redis_version:([^\r\n]+)/);
const version = versionMatch ? versionMatch[1] : "unknown";
console.log(`📊 Redis version: ${version}`);
await redis.quit();
return true;
} catch (error) {
console.error("❌ Redis connection failed:", error instanceof Error ? error.message : String(error));
return false;
}
}
async function testRateLimiting() {
console.log("\n🔍 Testing Rate Limiting...\n");
try {
await initRedisRateLimiter(process.env.REDIS_URL);
if (!isRedisConnected()) {
console.warn("⚠️ Redis not connected, rate limiting will use in-memory fallback");
} else {
console.log("✅ Rate limiter initialized with Redis");
}
// Test music rate limit
const testIdentifier = `test:${Date.now()}`;
console.log(`📍 Testing with identifier: ${testIdentifier}`);
// Make multiple requests
const results = [];
for (let i = 0; i < 5; i++) {
const result = await checkMusicRateLimit(testIdentifier);
results.push(result);
console.log(` Request ${i + 1}: ${result.allowed ? "✅ Allowed" : "❌ Blocked"} (remaining: ${result.remaining ?? "N/A"})`);
}
const allAllowed = results.every(r => r.allowed);
console.log(`\n${allAllowed ? "✅" : "⚠️"} Rate limiting test: ${allAllowed ? "All requests allowed (within limit)" : "Some requests blocked"}`);
return true;
} catch (error) {
console.error("❌ Rate limiting test failed:", error instanceof Error ? error.message : String(error));
return false;
}
}
async function testCaching() {
console.log("\n🔍 Testing Caching...\n");
try {
const testKey = `test:cache:${Date.now()}`;
const testValue = { message: "Hello Redis!", timestamp: Date.now() };
// Test set
await setCache(testKey, testValue, 60);
console.log(`✅ Set cache: ${testKey}`);
// Test get
const retrieved = await getCache<typeof testValue>(testKey);
if (retrieved && retrieved.message === testValue.message) {
console.log(`✅ Get cache: ${retrieved.message}`);
} else {
console.error(`❌ Get cache failed: Expected "${testValue.message}", got "${retrieved?.message ?? "null"}"`);
return false;
}
// Test delete
await deleteCache(testKey);
const afterDelete = await getCache(testKey);
if (afterDelete === null) {
console.log(`✅ Delete cache: Successfully deleted`);
} else {
console.error(`❌ Delete cache failed: Value still exists`);
return false;
}
return true;
} catch (error) {
console.error("❌ Caching test failed:", error instanceof Error ? error.message : String(error));
return false;
}
}
async function main() {
console.log("🚀 Redis Test Suite\n");
console.log("=" .repeat(50) + "\n");
// Load environment variables
if (process.env.NODE_ENV !== "production") {
// Try to load .env.local
try {
const { config } = await import("dotenv");
const result = config({ path: ".env.local" });
if (result.error) {
console.warn("⚠️ Could not load .env.local, using process.env");
}
} catch (e) {
// dotenv not available or already loaded
}
}
const results = {
connection: false,
rateLimiting: false,
caching: false,
};
// Run tests
results.connection = await testRedisConnection();
results.rateLimiting = await testRateLimiting();
results.caching = await testCaching();
// Summary
console.log("\n" + "=".repeat(50));
console.log("📊 Test Summary\n");
console.log(`Connection: ${results.connection ? "✅ PASSED" : "❌ FAILED"}`);
console.log(`Rate Limiting: ${results.rateLimiting ? "✅ PASSED" : "❌ FAILED"}`);
console.log(`Caching: ${results.caching ? "✅ PASSED" : "❌ FAILED"}`);
console.log("=".repeat(50) + "\n");
const allPassed = Object.values(results).every(r => r);
if (allPassed) {
console.log("🎉 All tests passed! Redis is working correctly.\n");
process.exit(0);
} else {
console.log("⚠️ Some tests failed. Please check the errors above.\n");
process.exit(1);
}
}
main().catch((error) => {
console.error("💥 Test suite crashed:", error);
process.exit(1);
});