Initial commit: Telegram Management System
Some checks failed
Deploy / deploy (push) Has been cancelled
Some checks failed
Deploy / deploy (push) Has been cancelled
Full-stack web application for Telegram management - Frontend: Vue 3 + Vben Admin - Backend: NestJS - Features: User management, group broadcast, statistics 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
239
marketing-agent/test/integration/api-gateway.test.js
Normal file
239
marketing-agent/test/integration/api-gateway.test.js
Normal file
@@ -0,0 +1,239 @@
|
||||
// API Gateway Integration Tests
|
||||
const TestEnvironment = require('./setup');
|
||||
const TestHelpers = require('./helpers');
|
||||
const apiGatewayApp = require('../../services/api-gateway/src/app');
|
||||
|
||||
describe('API Gateway Integration Tests', () => {
|
||||
let testEnv;
|
||||
let helpers;
|
||||
let apiClient;
|
||||
let testUser;
|
||||
let apiKey;
|
||||
const API_GATEWAY_PORT = 13000;
|
||||
const API_BASE_URL = `http://localhost:${API_GATEWAY_PORT}/api/v1`;
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = new TestEnvironment();
|
||||
helpers = new TestHelpers(testEnv);
|
||||
|
||||
// Setup test environment
|
||||
await testEnv.setup();
|
||||
|
||||
// Setup mocks
|
||||
helpers.setupMocks();
|
||||
|
||||
// Start API Gateway
|
||||
await testEnv.startService('api-gateway', apiGatewayApp, API_GATEWAY_PORT);
|
||||
|
||||
// Create test user and API key
|
||||
testUser = await testEnv.createTestUser();
|
||||
apiKey = await testEnv.createTestApiKey(testUser.id);
|
||||
|
||||
// Create authenticated client
|
||||
apiClient = await helpers.createAuthenticatedClient(`http://localhost:${API_GATEWAY_PORT}`, testUser);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
helpers.cleanupMocks();
|
||||
await testEnv.cleanup();
|
||||
});
|
||||
|
||||
describe('Authentication', () => {
|
||||
test('should authenticate with JWT token', async () => {
|
||||
const response = await apiClient.get('/api/v1/auth/me');
|
||||
const data = helpers.expectApiSuccess(response);
|
||||
|
||||
expect(data.user).toBeDefined();
|
||||
expect(data.user.id).toBe(testUser.id);
|
||||
expect(data.user.username).toBe(testUser.username);
|
||||
});
|
||||
|
||||
test('should reject invalid token', async () => {
|
||||
const invalidClient = require('axios').create({
|
||||
baseURL: `http://localhost:${API_GATEWAY_PORT}`,
|
||||
headers: {
|
||||
'Authorization': 'Bearer invalid-token'
|
||||
},
|
||||
validateStatus: () => true
|
||||
});
|
||||
|
||||
const response = await invalidClient.get('/api/v1/auth/me');
|
||||
helpers.expectApiError(response, 401, 'Invalid token');
|
||||
});
|
||||
|
||||
test('should authenticate with API key', async () => {
|
||||
const apiKeyClient = require('axios').create({
|
||||
baseURL: `http://localhost:${API_GATEWAY_PORT}`,
|
||||
headers: {
|
||||
'X-API-Key': apiKey.apiKey
|
||||
},
|
||||
validateStatus: () => true
|
||||
});
|
||||
|
||||
const response = await apiKeyClient.get('/api/v1/auth/me');
|
||||
const data = helpers.expectApiSuccess(response);
|
||||
|
||||
expect(data.user).toBeDefined();
|
||||
expect(data.apiKey).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Rate Limiting', () => {
|
||||
test('should enforce rate limits', async () => {
|
||||
const requests = [];
|
||||
|
||||
// Make many requests quickly
|
||||
for (let i = 0; i < 105; i++) {
|
||||
requests.push(
|
||||
apiClient.get('/api/v1/health').catch(e => e.response)
|
||||
);
|
||||
}
|
||||
|
||||
const responses = await Promise.all(requests);
|
||||
|
||||
// Check that some requests were rate limited
|
||||
const rateLimited = responses.filter(r => r.status === 429);
|
||||
expect(rateLimited.length).toBeGreaterThan(0);
|
||||
|
||||
// Verify rate limit headers
|
||||
const limitedResponse = rateLimited[0];
|
||||
expect(limitedResponse.headers['x-ratelimit-limit']).toBeDefined();
|
||||
expect(limitedResponse.headers['x-ratelimit-remaining']).toBeDefined();
|
||||
expect(limitedResponse.headers['x-ratelimit-reset']).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Service Routing', () => {
|
||||
test('should route to orchestrator service', async () => {
|
||||
const campaign = await helpers.createTestCampaign();
|
||||
|
||||
const response = await apiClient.get(`/api/v1/campaigns/${campaign.campaignId}`);
|
||||
const data = helpers.expectApiSuccess(response);
|
||||
|
||||
expect(data.campaign).toBeDefined();
|
||||
expect(data.campaign.campaignId).toBe(campaign.campaignId);
|
||||
});
|
||||
|
||||
test('should route to analytics service', async () => {
|
||||
const response = await apiClient.get('/api/v1/analytics/metrics', {
|
||||
params: {
|
||||
startDate: new Date(Date.now() - 86400000).toISOString(),
|
||||
endDate: new Date().toISOString()
|
||||
}
|
||||
});
|
||||
|
||||
const data = helpers.expectApiSuccess(response);
|
||||
expect(data.metrics).toBeDefined();
|
||||
});
|
||||
|
||||
test('should handle service unavailable', async () => {
|
||||
// Try to access a non-existent service endpoint
|
||||
const response = await apiClient.get('/api/v1/nonexistent/endpoint');
|
||||
helpers.expectApiError(response, 404);
|
||||
});
|
||||
});
|
||||
|
||||
describe('CORS', () => {
|
||||
test('should handle CORS preflight requests', async () => {
|
||||
const axios = require('axios');
|
||||
const response = await axios.options(`http://localhost:${API_GATEWAY_PORT}/api/v1/health`, {
|
||||
headers: {
|
||||
'Origin': 'http://localhost:3008',
|
||||
'Access-Control-Request-Method': 'GET',
|
||||
'Access-Control-Request-Headers': 'authorization'
|
||||
},
|
||||
validateStatus: () => true
|
||||
});
|
||||
|
||||
expect(response.status).toBe(204);
|
||||
expect(response.headers['access-control-allow-origin']).toBe('http://localhost:3008');
|
||||
expect(response.headers['access-control-allow-methods']).toContain('GET');
|
||||
expect(response.headers['access-control-allow-headers']).toContain('authorization');
|
||||
});
|
||||
|
||||
test('should reject unauthorized origins', async () => {
|
||||
const axios = require('axios');
|
||||
const response = await axios.get(`http://localhost:${API_GATEWAY_PORT}/api/v1/health`, {
|
||||
headers: {
|
||||
'Origin': 'http://unauthorized.com'
|
||||
},
|
||||
validateStatus: () => true
|
||||
});
|
||||
|
||||
expect(response.headers['access-control-allow-origin']).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error Handling', () => {
|
||||
test('should handle validation errors', async () => {
|
||||
const response = await apiClient.post('/api/v1/campaigns', {
|
||||
// Missing required fields
|
||||
name: 'Test Campaign'
|
||||
});
|
||||
|
||||
helpers.expectApiError(response, 400);
|
||||
expect(response.data.errors).toBeDefined();
|
||||
});
|
||||
|
||||
test('should handle internal server errors gracefully', async () => {
|
||||
// Force an error by sending invalid data type
|
||||
const response = await apiClient.post('/api/v1/campaigns', 'invalid-data-type');
|
||||
|
||||
helpers.expectApiError(response, 400);
|
||||
expect(response.data.error).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Health Checks', () => {
|
||||
test('should return health status', async () => {
|
||||
const response = await apiClient.get('/api/v1/health');
|
||||
const data = helpers.expectApiSuccess(response);
|
||||
|
||||
expect(data.status).toBe('healthy');
|
||||
expect(data.timestamp).toBeDefined();
|
||||
expect(data.version).toBeDefined();
|
||||
});
|
||||
|
||||
test('should return detailed service health', async () => {
|
||||
const response = await apiClient.get('/api/v1/health/services');
|
||||
const data = helpers.expectApiSuccess(response);
|
||||
|
||||
expect(data.services).toBeDefined();
|
||||
expect(data.services['api-gateway']).toBeDefined();
|
||||
expect(data.services['api-gateway'].status).toBe('healthy');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Request Logging', () => {
|
||||
test('should log requests with correlation ID', async () => {
|
||||
const correlationId = 'test-correlation-' + Date.now();
|
||||
|
||||
const response = await apiClient.get('/api/v1/health', {
|
||||
headers: {
|
||||
'X-Correlation-ID': correlationId
|
||||
}
|
||||
});
|
||||
|
||||
helpers.expectApiSuccess(response);
|
||||
expect(response.headers['x-correlation-id']).toBe(correlationId);
|
||||
});
|
||||
});
|
||||
|
||||
describe('API Versioning', () => {
|
||||
test('should support multiple API versions', async () => {
|
||||
// Test v1
|
||||
const v1Response = await apiClient.get('/api/v1/health');
|
||||
helpers.expectApiSuccess(v1Response);
|
||||
|
||||
// Test v2 (if implemented)
|
||||
const v2Response = await apiClient.get('/api/v2/health');
|
||||
if (v2Response.status === 200) {
|
||||
const data = helpers.expectApiSuccess(v2Response);
|
||||
expect(data.apiVersion).toBe('v2');
|
||||
} else {
|
||||
// v2 not implemented yet
|
||||
expect(v2Response.status).toBe(404);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user