Skip to main content
Glama

Tinder API MCP Server

rate-limiting-integration.test.ts9.23 kB
/** * Rate Limiting Integration Tests * * Tests the integration between rate limiter, request handler, and API endpoints. */ import rateLimiter from '../../services/rate-limiter'; import requestHandler from '../../services/request-handler'; import { ApiError } from '../../utils/error-handler'; import { ErrorCodes } from '../../types'; // Mock dependencies jest.mock('../../utils/logger'); describe('Rate Limiting Integration Tests', () => { beforeEach(() => { jest.clearAllMocks(); // Reset rate limiter state (rateLimiter as any).globalLimits = { requestsPerMinute: 100, currentCount: 0, windowStart: Date.now() }; (rateLimiter as any).userLimits = new Map(); }); describe('Global Rate Limiting', () => { it('should allow requests within the global rate limit', async () => { // Setup const checkRateLimitSpy = jest.spyOn(rateLimiter, 'checkRateLimit'); const processRequestSpy = jest.spyOn(requestHandler, 'processRequest').mockResolvedValue({}); // Execute multiple requests within limit const requests = []; for (let i = 0; i < 10; i++) { requests.push(requestHandler.processRequest({ method: 'GET', endpoint: '/user/123', userId: 'user-123' })); } // Wait for all requests to complete await Promise.all(requests); // Verify expect(checkRateLimitSpy).toHaveBeenCalledTimes(10); expect(processRequestSpy).toHaveBeenCalledTimes(10); expect((rateLimiter as any).globalLimits.currentCount).toBe(10); }); it('should reject requests exceeding the global rate limit', async () => { // Setup - set current count to limit (rateLimiter as any).globalLimits.currentCount = 100; // Execute request that exceeds limit const request = requestHandler.processRequest({ method: 'GET', endpoint: '/user/123', userId: 'user-123' }); // Verify await expect(request).rejects.toThrow(ApiError); await expect(request).rejects.toMatchObject({ code: ErrorCodes.RATE_LIMIT_EXCEEDED, message: expect.stringContaining('Global rate limit exceeded') }); }); it('should reset counter after window expires', async () => { // Setup - set window start to past time (rateLimiter as any).globalLimits.currentCount = 50; (rateLimiter as any).globalLimits.windowStart = Date.now() - 61000; // 61 seconds ago // Execute request await requestHandler.processRequest({ method: 'GET', endpoint: '/user/123', userId: 'user-123' }); // Verify counter was reset expect((rateLimiter as any).globalLimits.currentCount).toBe(1); expect((rateLimiter as any).globalLimits.windowStart).toBeGreaterThan(Date.now() - 1000); }); }); describe('User-Specific Rate Limiting', () => { it('should track like limits per user', async () => { // Setup const userId = 'user-123'; const updateRateLimitsSpy = jest.spyOn(rateLimiter, 'updateRateLimits'); jest.spyOn(requestHandler, 'processRequest').mockResolvedValue({ likes_remaining: 95, rate_limited_until: Date.now() + 3600000 }); // Execute request await requestHandler.processRequest({ method: 'GET', endpoint: '/like/target-456', userId }); // Verify expect(updateRateLimitsSpy).toHaveBeenCalled(); const userLimits = (rateLimiter as any).userLimits.get(userId); expect(userLimits).toBeDefined(); expect(userLimits.likes.remaining).toBe(95); }); it('should track super like limits per user', async () => { // Setup const userId = 'user-123'; const updateRateLimitsSpy = jest.spyOn(rateLimiter, 'updateRateLimits'); jest.spyOn(requestHandler, 'processRequest').mockResolvedValue({ super_likes: { remaining: 4, resets_at: new Date(Date.now() + 86400000).toISOString() } }); // Execute request await requestHandler.processRequest({ method: 'POST', endpoint: '/like/target-456/super', userId }); // Verify expect(updateRateLimitsSpy).toHaveBeenCalled(); const userLimits = (rateLimiter as any).userLimits.get(userId); expect(userLimits).toBeDefined(); expect(userLimits.superLikes.remaining).toBe(4); }); it('should reject requests exceeding like limits', async () => { // Setup const userId = 'user-123'; (rateLimiter as any).userLimits.set(userId, { likes: { remaining: 0, resetAt: Date.now() + 3600000 }, superLikes: { remaining: 5, resetAt: Date.now() + 3600000 }, boosts: { remaining: 1, resetAt: Date.now() + 3600000 } }); // Execute request const request = requestHandler.processRequest({ method: 'GET', endpoint: '/like/target-456', userId }); // Verify await expect(request).rejects.toThrow(ApiError); await expect(request).rejects.toMatchObject({ code: ErrorCodes.RATE_LIMIT_EXCEEDED, message: expect.stringContaining('Like rate limit exceeded') }); }); }); describe('Validation Failure Rate Limiting', () => { it('should track validation failures', () => { // Setup const identifier = 'user-123'; const endpoint = '/auth/sms/validate'; // Execute const result = rateLimiter.trackValidationFailure(identifier, endpoint); // Verify expect(result).toBe(false); // First failure should not trigger blocking const tracking = (rateLimiter as any).validationFailures.get(`${identifier}:${endpoint}`); expect(tracking).toBeDefined(); expect(tracking.failures).toBe(1); }); it('should block after excessive validation failures', () => { // Setup const identifier = 'user-123'; const endpoint = '/auth/sms/validate'; // Simulate multiple failures for (let i = 0; i < 10; i++) { rateLimiter.trackValidationFailure(identifier, endpoint); } // Execute const isLimited = rateLimiter.isValidationRateLimited(identifier, endpoint); // Verify expect(isLimited).toBe(true); }); it('should reset failure count after time window', () => { // Setup const identifier = 'user-123'; const endpoint = '/auth/sms/validate'; // Record a failure rateLimiter.trackValidationFailure(identifier, endpoint); // Simulate time passing const tracking = (rateLimiter as any).validationFailures.get(`${identifier}:${endpoint}`); tracking.lastFailure = Date.now() - 61 * 60 * 1000; // 61 minutes ago // Execute const result = rateLimiter.trackValidationFailure(identifier, endpoint); // Verify expect(result).toBe(false); // Counter should be reset expect(tracking.failures).toBe(1); // Should be reset to 1 }); }); describe('Integration with Request Handler', () => { it('should check rate limits before processing requests', async () => { // Setup const checkRateLimitSpy = jest.spyOn(rateLimiter, 'checkRateLimit'); jest.spyOn(requestHandler as any, 'validateRequest').mockImplementation(() => {}); jest.spyOn(requestHandler as any, 'validateRequestBody').mockImplementation(() => {}); jest.spyOn(requestHandler as any, 'requiresAuthentication').mockReturnValue(false); jest.spyOn(requestHandler as any, 'isCacheable').mockReturnValue(false); const mockAxiosInstance = { request: jest.fn().mockResolvedValue({ data: {} }) }; (requestHandler as any).httpClient = mockAxiosInstance; // Execute await requestHandler.processRequest({ method: 'GET', endpoint: '/user/123' }); // Verify expect(checkRateLimitSpy).toHaveBeenCalledWith('/user/123', undefined); }); it('should update rate limits after successful requests', async () => { // Setup const updateRateLimitsSpy = jest.spyOn(rateLimiter, 'updateRateLimits'); jest.spyOn(requestHandler as any, 'validateRequest').mockImplementation(() => {}); jest.spyOn(requestHandler as any, 'validateRequestBody').mockImplementation(() => {}); jest.spyOn(requestHandler as any, 'requiresAuthentication').mockReturnValue(false); jest.spyOn(requestHandler as any, 'isCacheable').mockReturnValue(false); const mockAxiosInstance = { request: jest.fn().mockResolvedValue({ data: { _id: 'user-123' } }) }; (requestHandler as any).httpClient = mockAxiosInstance; // Execute await requestHandler.processRequest({ method: 'GET', endpoint: '/user/123', userId: 'user-123' }); // Verify expect(updateRateLimitsSpy).toHaveBeenCalledWith( '/user/123', expect.objectContaining({ data: { _id: 'user-123' } }), 'user-123' ); }); }); });

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/glassBead-tc/tinder-mcp-server'

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