/* global describe, it, before, after, beforeEach */ const assert = require('assert').strict; const http = require('http'); const { promisify } = require('util'); const { exec } = require('child_process'); const execAsync = promisify(exec); const path = require('path'); const fs = require('fs'); // Use absolute paths to avoid any path resolution issues const rootDir = path.resolve(__dirname, '../..'); const DocumentHandler = require(path.join(rootDir, 'lib/document_handler')); const Generator = require(path.join(rootDir, 'lib/key_generators/random')); const PORT = 7777; const HOST = 'localhost'; const SERVER_START_WAIT = 2000; describe('Hastebin Core Functionality', function() { let testServer; // Increase timeout for slower operations this.timeout(10000); before(async function() { // Start server before tests const testServerPath = path.join(rootDir, 'test/utils/test-local.js'); try { testServer = require(testServerPath); // Wait for server to start await new Promise(resolve => setTimeout(resolve, SERVER_START_WAIT)); } catch (err) { console.error('Error starting test server:', err); throw err; } }); after(async function() { this.timeout(5000); console.log('Shutting down test server...'); if (testServer && testServer.server && typeof testServer.server.close === 'function') { await new Promise((resolve) => { testServer.server.close(() => { console.log('Server closed successfully'); resolve(); }); }); } else if (testServer && testServer.cleanup) { await testServer.cleanup(false); } // Force process termination if needed setTimeout(() => { console.log('Forcing process exit...'); process.exit(0); }, 1000); }); beforeEach(function() { // Clean test data before each test if (testServer && testServer.cleanTestData) { testServer.cleanTestData(); } }); describe('Document Handler', function() { describe('Key Generation', function() { it('should generate keys of the specified length', function() { const gen = new Generator(); const dh = new DocumentHandler({ keyLength: 6, keyGenerator: gen }); assert.equal(6, dh.acceptableKey().length); }); it('should use the default key length when not specified', function() { const gen = new Generator(); const dh = new DocumentHandler({ keyGenerator: gen }); assert.equal(dh.keyLength, DocumentHandler.defaultKeyLength); }); }); }); describe('Document Operations', function() { describe('Document Creation', function() { it('should create a new document', async function() { const testContent = 'Test document content'; try { const { stdout } = await execAsync( `curl -s -X POST http://${HOST}:${PORT}/documents -d "${testContent}"` ); const response = JSON.parse(stdout); assert(response.key && typeof response.key === 'string', 'Should return a valid document key'); assert.equal(response.key.length, DocumentHandler.defaultKeyLength); } catch (error) { console.error('Error in create document test:', error); throw error; } }); it('should handle empty documents', async function() { // The server should reject empty documents try { const { stdout, stderr } = await execAsync( `curl -s -i -X POST http://${HOST}:${PORT}/documents -d "" || echo "Error occurred"` ); // If we get here, check if the response indicates an error const hasError = stdout.includes('400') || stdout.includes('Bad Request') || stderr.includes('Error'); assert(hasError, 'Should return error status for empty document'); } catch (error) { // If curl fails, that's also a valid test result assert(true, 'Error occurred as expected'); } }); }); describe('Document Retrieval', function() { let documentKey; beforeEach(async function() { // Create a test document try { const { stdout } = await execAsync( `curl -s -X POST http://${HOST}:${PORT}/documents -d "Test retrieval content"` ); const response = JSON.parse(stdout); documentKey = response.key; } catch (error) { console.error('Error creating test document:', error); throw error; } }); it('should retrieve an existing document', async function() { try { const { stdout } = await execAsync( `curl -s http://${HOST}:${PORT}/raw/${documentKey}` ); assert.equal(stdout, 'Test retrieval content'); } catch (error) { console.error('Error retrieving document:', error); throw error; } }); it('should handle non-existent documents', async function() { // The server should return 404 for non-existent documents try { const { stdout, stderr } = await execAsync( `curl -s -i http://${HOST}:${PORT}/raw/nonexistentkey || echo "Error occurred"` ); // If we get here, check if the response indicates a 404 const hasError = stdout.includes('404') || stdout.includes('Not Found') || stderr.includes('Error'); assert(hasError, 'Should return 404 status for non-existent document'); } catch (error) { // If curl fails, that's also a valid test result assert(true, 'Error occurred as expected'); } }); }); }); describe('Rate Limiting', function() { it('should enforce rate limits', async function() { try { // Make multiple rapid requests const requests = Array(10).fill().map(() => execAsync(`curl -s -I http://${HOST}:${PORT}/`) ); const responses = await Promise.all(requests); const hasRateLimit = responses.some(({ stdout }) => stdout.includes('X-RateLimit-Remaining') ); assert(hasRateLimit, 'Should include rate limit headers'); } catch (error) { console.error('Error in rate limit test:', error); throw error; } }); }); });