Testing
Testing Strategy
ReCloud implements comprehensive testing across all layers with automated CI/CD pipelines ensuring quality and reliability.
Test Types
Unit Tests
Component Testing
// ToolDispatcher unit test
import { ToolDispatcher } from '../services/ToolDispatcher';
import { expect } from 'chai';
import sinon from 'sinon';
describe('ToolDispatcher', () => {
let dispatcher: ToolDispatcher;
let mockApiClient: sinon.SinonStubbedInstance<ApiClient>;
beforeEach(() => {
mockApiClient = sinon.createStubInstance(ApiClient);
dispatcher = new ToolDispatcher(mockApiClient);
});
describe('dispatch', () => {
it('should route remote tools to API client', async () => {
const toolName = 'analyzeSentiment';
const parameters = { text: 'test' };
mockApiClient.executeTool.resolves({ success: true });
const result = await dispatcher.dispatch(toolName, parameters);
expect(mockApiClient.executeTool.calledWith(toolName, parameters)).to.be.true;
expect(result.success).to.be.true;
});
});
});
Utility Function Testing
// Configuration utility tests
describe('getModelForTool', () => {
afterEach(() => {
delete process.env.ANALYZE_SENTIMENT_MODEL;
});
it('returns default model for unmapped tool', () => {
expect(getModelForTool('unknown')).to.equal('gemini-2.5-flash');
});
it('returns mapped model from environment', () => {
process.env.ANALYZE_SENTIMENT_MODEL = 'gemini-2.5-pro';
expect(getModelForTool('analyzeSentiment')).to.equal('gemini-2.5-pro');
});
});
Integration Tests
API Integration
// API endpoint integration test
describe('Tool Execution API', () => {
let app: Express;
let server: Server;
beforeAll(async () => {
app = await createApp();
server = app.listen(3001);
});
afterAll(async () => {
await server.close();
});
it('executes tool successfully', async () => {
const response = await request(app)
.post('/tools/execute')
.set('Authorization', 'Bearer test-key')
.send({
toolName: 'analyzeSentiment',
parameters: { text: 'Great product!' }
});
expect(response.status).toBe(200);
expect(response.body.success).toBe(true);
expect(response.body.result).toHaveProperty('sentiment');
});
});
Database Integration
// Database integration test
describe('Tool Execution Repository', () => {
let repository: ToolExecutionRepository;
let db: Database;
beforeEach(async () => {
db = await createTestDatabase();
repository = new ToolExecutionRepository(db);
});
afterEach(async () => {
await db.destroy();
});
it('saves tool execution', async () => {
const execution = {
toolName: 'analyzeSentiment',
parameters: { text: 'test' },
result: { sentiment: 'positive' },
duration: 1000
};
const saved = await repository.save(execution);
expect(saved.id).toBeDefined();
const retrieved = await repository.findById(saved.id);
expect(retrieved.toolName).toEqual('analyzeSentiment');
});
});
End-to-End Tests
MCP Protocol Testing
// MCP server E2E test
describe('MCP Server E2E', () => {
let mcpClient: MCPClient;
let server: Server;
beforeAll(async () => {
// Start MCP server
server = await startTestServer();
// Connect MCP client
mcpClient = new MCPClient();
await mcpClient.connect('http://localhost:3002');
});
afterAll(async () => {
await mcpClient.disconnect();
await server.close();
});
it('executes tool via MCP protocol', async () => {
const result = await mcpClient.callTool('recloud', {
subcommand: 'analyzeSentiment',
parameters: { text: 'Amazing!' }
});
expect(result.success).toBe(true);
expect(result.data.sentiment).toBeDefined();
});
});
Full Workflow Testing
// Complete workflow E2E test
describe('Complete ReCloud Workflow', () => {
it('processes request from TrayApp through MCP to API', async () => {
// 1. Start all services
await startAllServices();
// 2. Simulate TrayApp request
const trayApp = new TrayAppSimulator();
await trayApp.sendToolRequest('analyzeSentiment', { text: 'test' });
// 3. Verify MCP server received request
const mcpLogs = await getMcpLogs();
expect(mcpLogs).toContain('analyzeSentiment');
// 4. Verify API processed request
const apiLogs = await getApiLogs();
expect(apiLogs).toContain('tool execution completed');
// 5. Verify result returned to TrayApp
const result = await trayApp.getLastResult();
expect(result.success).toBe(true);
});
});
Quality Assurance
Testing Coverage
- Unit Tests: Individual component validation
- Integration Tests: Component interaction verification
- End-to-End Tests: Complete workflow validation
- Performance Tests: Load and stress testing
Quality Standards
- Automated Testing: Comprehensive test suites for all components
- Continuous Integration: Automated testing on every code change
- Performance Validation: Load testing and performance benchmarks
- Security Testing: Automated security scans and vulnerability checks
Performance Testing
Load Testing
Tool Execution Load Test
// Load test for tool execution
import { check } from 'k6';
import http from 'k6/http';
export let options = {
vus: 50, // 50 virtual users
duration: '5m',
thresholds: {
http_req_duration: ['p(95)<2000'], // 95% of requests < 2s
http_req_failed: ['rate<0.05'], // Error rate < 5%
},
};
const tools = ['analyzeSentiment', 'generateCode', 'generateQR'];
const apiKey = __ENV.API_KEY;
export default function () {
const tool = tools[Math.floor(Math.random() * tools.length)];
const payload = generatePayload(tool);
const response = http.post(
'http://localhost:3001/tools/execute',
JSON.stringify({
toolName: tool,
parameters: payload
}),
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
}
}
);
check(response, {
'status is 200': (r) => r.status === 200,
'response time < 5000ms': (r) => r.timings.duration < 5000,
'has success field': (r) => r.json().success !== undefined
});
}
function generatePayload(tool: string) {
switch (tool) {
case 'analyzeSentiment':
return { text: 'This is a great product!' };
case 'generateCode':
return { description: 'Create a hello world function', language: 'javascript' };
case 'generateQR':
return { text: 'https://recloud.dev' };
}
}
Stress Testing
Maximum Load Testing
# Apache Bench stress test
ab -n 10000 -c 100 -T 'application/json' \
-H 'Authorization: Bearer test-key' \
-p payload.json \
http://localhost:3001/tools/execute
Memory Leak Testing
// Memory leak detection test
describe('Memory Leak Tests', () => {
it('should not leak memory during repeated tool executions', async () => {
const initialMemory = process.memoryUsage().heapUsed;
// Execute tool 1000 times
for (let i = 0; i < 1000; i++) {
await executeTool('analyzeSentiment', { text: `Test ${i}` });
}
const finalMemory = process.memoryUsage().heapUsed;
const memoryIncrease = finalMemory - initialMemory;
// Allow for some memory increase but not excessive
expect(memoryIncrease).toBeLessThan(50 * 1024 * 1024); // 50MB
});
});
Security Testing
Vulnerability Scanning
Dependency Scanning
# NPM audit
npm audit
# Snyk security scan
snyk test
# OWASP Dependency Check
dependency-check --scan . --format JSON
Code Security Analysis
// Security linting rules
const securityRules = {
// Prevent dangerous functions
'no-eval': 'error',
'no-implied-eval': 'error',
// Prevent XSS
'react/jsx-no-script-url': 'error',
// Prevent command injection
'security/detect-child-process': 'error',
'security/detect-non-literal-fs-filename': 'error'
};
Penetration Testing
API Security Testing
# OWASP ZAP automated scan
zap.sh -cmd -quickurl http://localhost:3001 -quickout report.html
# API fuzzing
ffuf -w wordlist.txt -u http://localhost:3001/api/FUZZ -mc 200
Authentication Testing
// Authentication bypass test
describe('Authentication Security', () => {
it('should reject requests without valid API key', async () => {
const response = await request(app)
.post('/tools/execute')
.send({ toolName: 'test' });
expect(response.status).toBe(401);
});
it('should reject malformed API keys', async () => {
const response = await request(app)
.post('/tools/execute')
.set('Authorization', 'Bearer invalid-key')
.send({ toolName: 'test' });
expect(response.status).toBe(401);
});
});
Test Data Management
Test Database Setup
Database Fixtures
// Test data setup
export async function setupTestData() {
await db.migrate.latest();
// Create test users
await db('users').insert([
{ id: 1, email: 'test@example.com', api_key: 'test-key' },
{ id: 2, email: 'admin@example.com', api_key: 'admin-key' }
]);
// Create test tools
await db('tools').insert([
{ name: 'analyzeSentiment', category: 'analysis' },
{ name: 'generateCode', category: 'generation' }
]);
}
export async function teardownTestData() {
await db.migrate.rollback();
}
Continuous Testing
Test Environments
Development Testing
# Run tests in watch mode during development
npm run test:watch
# Run specific test file
npm test -- src/services/ToolDispatcher.test.ts
Staging Testing
# Full test suite for staging deployments
npm run test:ci
# Performance regression tests
npm run test:performance
Production Testing
# Smoke tests for production deployments
npm run test:smoke
# Synthetic monitoring
npm run test:synthetic
Test Reporting
Coverage Reports
// Generate coverage report
import { createCoverageMap } from 'istanbul-lib-coverage';
import { createCoverageSummary } from 'istanbul-lib-report';
const coverageMap = createCoverageMap(global.__coverage__);
const summary = createCoverageSummary(coverageMap);
console.log('Coverage Summary:');
console.log(`Statements: ${summary.statements.pct}%`);
console.log(`Branches: ${summary.branches.pct}%`);
console.log(`Functions: ${summary.functions.pct}%`);
console.log(`Lines: ${summary.lines.pct}%`);
Test Results Dashboard
// Test results aggregation
interface TestResults {
total: number;
passed: number;
failed: number;
skipped: number;
duration: number;
coverage: CoverageSummary;
}
const dashboard = {
generateReport: (results: TestResults) => {
// Generate HTML dashboard
// Send notifications for failures
// Update CI status
}
};
Comprehensive testing ensures ReCloud's reliability, security, and performance across all deployment scenarios.