You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
294 lines
7.3 KiB
294 lines
7.3 KiB
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Test API Demo Script
|
|
*
|
|
* Demonstrates the Test API Server functionality
|
|
* and validates all endpoints work correctly.
|
|
*
|
|
* @author Matthew Raymer
|
|
* @version 1.0.0
|
|
*/
|
|
|
|
const fetch = require('node-fetch');
|
|
|
|
const API_BASE_URL = 'http://localhost:3001';
|
|
|
|
/**
|
|
* Make HTTP request with timeout
|
|
* @param {string} url - Request URL
|
|
* @param {Object} options - Fetch options
|
|
* @returns {Promise<Object>} Response data
|
|
*/
|
|
async function makeRequest(url, options = {}) {
|
|
try {
|
|
const response = await fetch(url, {
|
|
timeout: 10000,
|
|
...options
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
return {
|
|
status: response.status,
|
|
data,
|
|
headers: Object.fromEntries(response.headers.entries())
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
status: 0,
|
|
error: error.message
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test health endpoint
|
|
*/
|
|
async function testHealth() {
|
|
console.log('🔍 Testing health endpoint...');
|
|
|
|
const result = await makeRequest(`${API_BASE_URL}/health`);
|
|
|
|
if (result.error) {
|
|
console.error('❌ Health check failed:', result.error);
|
|
return false;
|
|
}
|
|
|
|
console.log('✅ Health check passed');
|
|
console.log(' Status:', result.status);
|
|
console.log(' Version:', result.data.version);
|
|
console.log(' Endpoints:', Object.keys(result.data.endpoints).length);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Test content fetching
|
|
*/
|
|
async function testContentFetching() {
|
|
console.log('\n📱 Testing content fetching...');
|
|
|
|
const slotId = 'slot-08:00';
|
|
const result = await makeRequest(`${API_BASE_URL}/api/content/${slotId}`);
|
|
|
|
if (result.error) {
|
|
console.error('❌ Content fetch failed:', result.error);
|
|
return false;
|
|
}
|
|
|
|
console.log('✅ Content fetch passed');
|
|
console.log(' Status:', result.status);
|
|
console.log(' Slot ID:', result.data.slotId);
|
|
console.log(' Title:', result.data.title);
|
|
console.log(' ETag:', result.headers.etag);
|
|
|
|
return result.headers.etag;
|
|
}
|
|
|
|
/**
|
|
* Test ETag caching
|
|
*/
|
|
async function testETagCaching(etag) {
|
|
console.log('\n🔄 Testing ETag caching...');
|
|
|
|
const slotId = 'slot-08:00';
|
|
const result = await makeRequest(`${API_BASE_URL}/api/content/${slotId}`, {
|
|
headers: {
|
|
'If-None-Match': etag
|
|
}
|
|
});
|
|
|
|
if (result.error) {
|
|
console.error('❌ ETag test failed:', result.error);
|
|
return false;
|
|
}
|
|
|
|
if (result.status === 304) {
|
|
console.log('✅ ETag caching works (304 Not Modified)');
|
|
return true;
|
|
} else {
|
|
console.log('⚠️ ETag caching unexpected response:', result.status);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test error scenarios
|
|
*/
|
|
async function testErrorScenarios() {
|
|
console.log('\n🚨 Testing error scenarios...');
|
|
|
|
const errorTypes = ['server-error', 'not-found', 'rate-limit', 'unauthorized'];
|
|
let passed = 0;
|
|
|
|
for (const errorType of errorTypes) {
|
|
const result = await makeRequest(`${API_BASE_URL}/api/error/${errorType}`);
|
|
|
|
if (result.error) {
|
|
console.log(`❌ ${errorType}: ${result.error}`);
|
|
} else {
|
|
console.log(`✅ ${errorType}: ${result.status}`);
|
|
passed++;
|
|
}
|
|
}
|
|
|
|
console.log(` Passed: ${passed}/${errorTypes.length}`);
|
|
return passed === errorTypes.length;
|
|
}
|
|
|
|
/**
|
|
* Test metrics endpoint
|
|
*/
|
|
async function testMetrics() {
|
|
console.log('\n📊 Testing metrics endpoint...');
|
|
|
|
const result = await makeRequest(`${API_BASE_URL}/api/metrics`);
|
|
|
|
if (result.error) {
|
|
console.error('❌ Metrics test failed:', result.error);
|
|
return false;
|
|
}
|
|
|
|
console.log('✅ Metrics endpoint works');
|
|
console.log(' Content store size:', result.data.contentStore.size);
|
|
console.log(' ETag store size:', result.data.etagStore.size);
|
|
console.log(' Uptime:', Math.round(result.data.uptime), 'seconds');
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Test content update
|
|
*/
|
|
async function testContentUpdate() {
|
|
console.log('\n✏️ Testing content update...');
|
|
|
|
const slotId = 'slot-08:00';
|
|
const newContent = {
|
|
content: {
|
|
title: 'Updated Test Title',
|
|
body: 'This is updated test content',
|
|
timestamp: Date.now()
|
|
}
|
|
};
|
|
|
|
const result = await makeRequest(`${API_BASE_URL}/api/content/${slotId}`, {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(newContent)
|
|
});
|
|
|
|
if (result.error) {
|
|
console.error('❌ Content update failed:', result.error);
|
|
return false;
|
|
}
|
|
|
|
console.log('✅ Content update works');
|
|
console.log(' Status:', result.status);
|
|
console.log(' New ETag:', result.data.etag);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Test content clearing
|
|
*/
|
|
async function testContentClearing() {
|
|
console.log('\n🗑️ Testing content clearing...');
|
|
|
|
const result = await makeRequest(`${API_BASE_URL}/api/content`, {
|
|
method: 'DELETE'
|
|
});
|
|
|
|
if (result.error) {
|
|
console.error('❌ Content clearing failed:', result.error);
|
|
return false;
|
|
}
|
|
|
|
console.log('✅ Content clearing works');
|
|
console.log(' Status:', result.status);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Main test runner
|
|
*/
|
|
async function runTests() {
|
|
console.log('🚀 Starting Test API validation...\n');
|
|
|
|
const tests = [
|
|
{ name: 'Health Check', fn: testHealth },
|
|
{ name: 'Content Fetching', fn: testContentFetching },
|
|
{ name: 'ETag Caching', fn: testETagCaching },
|
|
{ name: 'Error Scenarios', fn: testErrorScenarios },
|
|
{ name: 'Metrics', fn: testMetrics },
|
|
{ name: 'Content Update', fn: testContentUpdate },
|
|
{ name: 'Content Clearing', fn: testContentClearing }
|
|
];
|
|
|
|
let passed = 0;
|
|
let etag = null;
|
|
|
|
for (const test of tests) {
|
|
try {
|
|
if (test.name === 'ETag Caching' && etag) {
|
|
const result = await test.fn(etag);
|
|
if (result) passed++;
|
|
} else {
|
|
const result = await test.fn();
|
|
if (result) {
|
|
passed++;
|
|
if (test.name === 'Content Fetching' && typeof result === 'string') {
|
|
etag = result;
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error(`❌ ${test.name} failed with error:`, error.message);
|
|
}
|
|
}
|
|
|
|
console.log(`\n📋 Test Results: ${passed}/${tests.length} passed`);
|
|
|
|
if (passed === tests.length) {
|
|
console.log('🎉 All tests passed! Test API is working correctly.');
|
|
} else {
|
|
console.log('⚠️ Some tests failed. Check the output above for details.');
|
|
}
|
|
|
|
console.log('\n💡 Next steps:');
|
|
console.log(' 1. Start your test app');
|
|
console.log(' 2. Configure it to use this API');
|
|
console.log(' 3. Test plugin functionality');
|
|
console.log(' 4. Monitor API metrics at /api/metrics');
|
|
}
|
|
|
|
// Check if API server is running
|
|
async function checkServer() {
|
|
try {
|
|
const result = await makeRequest(`${API_BASE_URL}/health`);
|
|
if (result.error) {
|
|
console.error('❌ Cannot connect to Test API Server');
|
|
console.error(' Make sure the server is running: npm start');
|
|
console.error(' Server should be available at:', API_BASE_URL);
|
|
process.exit(1);
|
|
}
|
|
} catch (error) {
|
|
console.error('❌ Cannot connect to Test API Server');
|
|
console.error(' Make sure the server is running: npm start');
|
|
console.error(' Server should be available at:', API_BASE_URL);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
// Run tests
|
|
checkServer().then(() => {
|
|
runTests().catch(error => {
|
|
console.error('❌ Test runner failed:', error.message);
|
|
process.exit(1);
|
|
});
|
|
});
|
|
|