import { test, expect } from '../fixtures'; /** * Log Ingestion Tests * Covers: HTTP API ingestion, batch processing, PII detection * Target: 100% coverage on critical paths */ test.describe('Log Ingestion @ingest @critical', () => { test('should ingest single log via HTTP API', async ({ apiClient, testData }) => { // Create a scenario first const scenario = await testData.createScenario({ name: 'Ingest Test', region: 'us-east-1', tags: [], }); // Ingest a log const response = await apiClient.ingestLog(scenario.id, { message: 'Test log message', source: 'e2e-test', level: 'INFO', }); expect(response.status()).toBe(200); }); test('should ingest batch of logs', async ({ apiClient, testData }) => { const scenario = await testData.createScenario({ name: 'Batch Ingest Test', region: 'us-east-1', tags: [], }); // Ingest multiple logs const logs = Array.from({ length: 10 }, (_, i) => ({ message: `Batch log ${i}`, source: 'batch-test', level: 'INFO', })); for (const log of logs) { const response = await apiClient.ingestLog(scenario.id, log); expect(response.status()).toBe(200); } }); test('should detect email PII in logs', async ({ authenticatedPage, testData }) => { const scenario = await testData.createScenario({ name: 'PII Detection Test', region: 'us-east-1', tags: [], }); // Add log with PII await testData.addScenarioLogWithPII(scenario.id); // Navigate to scenario and check PII detection await authenticatedPage.goto(`/scenarios/${scenario.id}`); await authenticatedPage.click('[data-testid="pii-tab"]'); await expect(authenticatedPage.locator('[data-testid="pii-alert-count"]')).toContainText('1'); await expect(authenticatedPage.locator('[data-testid="pii-type-email"]')).toBeVisible(); }); test('should require X-Scenario-ID header', async ({ apiClient }) => { const response = await apiClient.context!.post('/ingest', { data: { message: 'Test without scenario ID', source: 'test', }, }); expect(response.status()).toBe(400); }); test('should reject invalid scenario ID', async ({ apiClient }) => { const response = await apiClient.ingestLog('invalid-uuid', { message: 'Test with invalid ID', source: 'test', }); expect(response.status()).toBe(404); }); test('should handle large log messages', async ({ apiClient, testData }) => { const scenario = await testData.createScenario({ name: 'Large Log Test', region: 'us-east-1', tags: [], }); const largeMessage = 'A'.repeat(10000); const response = await apiClient.ingestLog(scenario.id, { message: largeMessage, source: 'large-test', }); expect(response.status()).toBe(200); }); test('should deduplicate identical logs', async ({ apiClient, testData }) => { const scenario = await testData.createScenario({ name: 'Deduplication Test', region: 'us-east-1', tags: [], }); // Send same log twice const log = { message: 'Duplicate log message', source: 'dedup-test', level: 'INFO', }; await apiClient.ingestLog(scenario.id, log); await apiClient.ingestLog(scenario.id, log); // Navigate to logs tab await testData.apiContext!.get(`/api/v1/scenarios/${scenario.id}/logs`, { headers: { Authorization: `Bearer ${testData.authToken}` }, }); // Check deduplication // This would depend on your specific implementation }); test('should ingest logs with metadata', async ({ apiClient, testData }) => { const scenario = await testData.createScenario({ name: 'Metadata Test', region: 'us-east-1', tags: [], }); const response = await apiClient.ingestLog(scenario.id, { message: 'Log with metadata', source: 'metadata-test', level: 'INFO', metadata: { requestId: 'req-123', userId: 'user-456', traceId: 'trace-789', }, }); expect(response.status()).toBe(200); }); test('should handle different log levels', async ({ apiClient, testData }) => { const scenario = await testData.createScenario({ name: 'Log Levels Test', region: 'us-east-1', tags: [], }); const levels = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL']; for (const level of levels) { const response = await apiClient.ingestLog(scenario.id, { message: `${level} level test`, source: 'levels-test', level, }); expect(response.status()).toBe(200); } }); test('should apply rate limiting on ingest endpoint', async ({ apiClient, testData }) => { const scenario = await testData.createScenario({ name: 'Rate Limit Test', region: 'us-east-1', tags: [], }); // Send many rapid requests const responses = []; for (let i = 0; i < 1100; i++) { const response = await apiClient.ingestLog(scenario.id, { message: `Rate limit test ${i}`, source: 'rate-limit-test', }); responses.push(response.status()); if (response.status() === 429) { break; } } // Should eventually hit rate limit expect(responses).toContain(429); }); }); test.describe('Ingest via Logstash @ingest @integration', () => { test('should accept Logstash-compatible format', async () => { // Test Logstash HTTP output compatibility const logstashFormat = { '@timestamp': new Date().toISOString(), message: 'Logstash format test', host: 'test-host', type: 'application', }; // This would test the actual Logstash integration // Implementation depends on your setup }); test('should handle Logstash batch format', async () => { // Test batch ingestion from Logstash const batch = [ { message: 'Log 1', '@timestamp': new Date().toISOString() }, { message: 'Log 2', '@timestamp': new Date().toISOString() }, { message: 'Log 3', '@timestamp': new Date().toISOString() }, ]; // Implementation depends on your setup }); });