234 lines
7.2 KiB
TypeScript
234 lines
7.2 KiB
TypeScript
// tests/api/04-live.ts
|
|
|
|
import { api, log, runTest, saveImage, wait } from './utils';
|
|
import { endpoints } from './config';
|
|
|
|
import { fileURLToPath } from 'url';
|
|
import { dirname } from 'path';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
|
|
async function main() {
|
|
log.section('LIVE ENDPOINT TESTS');
|
|
|
|
// Test 1: First call (cache MISS)
|
|
await runTest('Live generation - cache MISS', async () => {
|
|
const params = new URLSearchParams({
|
|
prompt: 'A serene zen garden with rocks and sand',
|
|
aspectRatio: '16:9',
|
|
});
|
|
|
|
const startTime = Date.now();
|
|
const result = await api(`${endpoints.live}?${params}`, {
|
|
timeout: 60000, // Longer timeout for generation
|
|
});
|
|
const duration = Date.now() - startTime;
|
|
|
|
// Should return image buffer
|
|
if (!(result.data instanceof ArrayBuffer)) {
|
|
throw new Error('Expected image buffer');
|
|
}
|
|
|
|
// Check cache status header
|
|
const cacheStatus = result.headers.get('X-Cache-Status');
|
|
if (cacheStatus !== 'MISS') {
|
|
throw new Error(`Expected cache MISS, got: ${cacheStatus}`);
|
|
}
|
|
|
|
log.detail('Cache status', cacheStatus);
|
|
log.detail('Duration', `${duration}ms`);
|
|
log.detail('Content-Type', result.headers.get('Content-Type'));
|
|
log.detail('Image size', `${result.data.byteLength} bytes`);
|
|
|
|
await saveImage(result.data, 'live-cache-miss.png');
|
|
});
|
|
|
|
// Test 2: Second call with same params (cache HIT)
|
|
await runTest('Live generation - cache HIT', async () => {
|
|
const params = new URLSearchParams({
|
|
prompt: 'A serene zen garden with rocks and sand',
|
|
aspectRatio: '16:9',
|
|
});
|
|
|
|
const startTime = Date.now();
|
|
const result = await api(`${endpoints.live}?${params}`);
|
|
const duration = Date.now() - startTime;
|
|
|
|
// Check cache status header
|
|
const cacheStatus = result.headers.get('X-Cache-Status');
|
|
if (cacheStatus !== 'HIT') {
|
|
throw new Error(`Expected cache HIT, got: ${cacheStatus}`);
|
|
}
|
|
|
|
log.detail('Cache status', cacheStatus);
|
|
log.detail('Duration', `${duration}ms (should be faster)`);
|
|
log.detail('Image size', `${result.data.byteLength} bytes`);
|
|
|
|
await saveImage(result.data, 'live-cache-hit.png');
|
|
});
|
|
|
|
// Test 3: Different aspect ratio (new cache entry)
|
|
await runTest('Live generation - different params', async () => {
|
|
const params = new URLSearchParams({
|
|
prompt: 'A serene zen garden with rocks and sand',
|
|
aspectRatio: '1:1', // Different aspect ratio
|
|
});
|
|
|
|
const result = await api(`${endpoints.live}?${params}`, {
|
|
timeout: 60000,
|
|
});
|
|
|
|
const cacheStatus = result.headers.get('X-Cache-Status');
|
|
if (cacheStatus !== 'MISS') {
|
|
throw new Error(`Expected cache MISS for different params, got: ${cacheStatus}`);
|
|
}
|
|
|
|
log.detail('Cache status', cacheStatus);
|
|
log.detail('Aspect ratio', '1:1');
|
|
|
|
await saveImage(result.data, 'live-different-aspect.png');
|
|
});
|
|
|
|
// Test 4: With reference image
|
|
await runTest('Live generation - with reference', async () => {
|
|
const params = new URLSearchParams({
|
|
prompt: 'Product photo featuring @brand-logo',
|
|
aspectRatio: '16:9',
|
|
reference: '@brand-logo',
|
|
});
|
|
|
|
const result = await api(`${endpoints.live}?${params}`, {
|
|
timeout: 60000,
|
|
});
|
|
|
|
const cacheStatus = result.headers.get('X-Cache-Status');
|
|
log.detail('Cache status', cacheStatus);
|
|
log.detail('With reference', '@brand-logo');
|
|
|
|
await saveImage(result.data, 'live-with-reference.png');
|
|
});
|
|
|
|
// Test 5: Multiple references
|
|
await runTest('Live generation - multiple references', async () => {
|
|
const params = new URLSearchParams({
|
|
prompt: 'Combine @brand-logo and @generated-logo',
|
|
aspectRatio: '1:1',
|
|
});
|
|
params.append('reference', '@brand-logo');
|
|
params.append('reference', '@generated-logo');
|
|
|
|
const result = await api(`${endpoints.live}?${params}`, {
|
|
timeout: 60000,
|
|
});
|
|
|
|
const cacheStatus = result.headers.get('X-Cache-Status');
|
|
log.detail('Cache status', cacheStatus);
|
|
log.detail('References', '[@brand-logo, @generated-logo]');
|
|
|
|
await saveImage(result.data, 'live-multiple-refs.png');
|
|
});
|
|
|
|
// Test 6: Custom dimensions
|
|
await runTest('Live generation - custom dimensions', async () => {
|
|
const params = new URLSearchParams({
|
|
prompt: 'A landscape painting',
|
|
width: '1024',
|
|
height: '768',
|
|
});
|
|
|
|
const result = await api(`${endpoints.live}?${params}`, {
|
|
timeout: 60000,
|
|
});
|
|
|
|
const cacheStatus = result.headers.get('X-Cache-Status');
|
|
log.detail('Cache status', cacheStatus);
|
|
log.detail('Dimensions', '1024x768');
|
|
|
|
await saveImage(result.data, 'live-custom-dims.png');
|
|
});
|
|
|
|
// Test 7: Verify cache works as URL
|
|
await runTest('Live as direct URL (browser-like)', async () => {
|
|
const url = `${endpoints.live}?prompt=${encodeURIComponent('A beautiful sunset')}&aspectRatio=16:9`;
|
|
|
|
log.info('Testing URL format:');
|
|
log.detail('URL', url);
|
|
|
|
const result = await api(url, { timeout: 60000 });
|
|
|
|
if (!(result.data instanceof ArrayBuffer)) {
|
|
throw new Error('Should return image directly');
|
|
}
|
|
|
|
const cacheStatus = result.headers.get('X-Cache-Status');
|
|
log.detail('Cache status', cacheStatus);
|
|
log.detail('Works as direct URL', '✓');
|
|
|
|
await saveImage(result.data, 'live-direct-url.png');
|
|
});
|
|
|
|
// Test 8: Verify Cache-Control header for CDN
|
|
await runTest('Check Cache-Control headers', async () => {
|
|
const params = new URLSearchParams({
|
|
prompt: 'Test cache control',
|
|
aspectRatio: '1:1',
|
|
});
|
|
|
|
const result = await api(`${endpoints.live}?${params}`, {
|
|
timeout: 60000,
|
|
});
|
|
|
|
const cacheControl = result.headers.get('Cache-Control');
|
|
const contentType = result.headers.get('Content-Type');
|
|
|
|
log.detail('Cache-Control', cacheControl || 'NOT SET');
|
|
log.detail('Content-Type', contentType || 'NOT SET');
|
|
|
|
if (!cacheControl || !cacheControl.includes('public')) {
|
|
log.warning('Cache-Control should be set for CDN optimization');
|
|
}
|
|
});
|
|
|
|
// Test 9: Rapid repeated calls (verify cache performance)
|
|
await runTest('Cache performance test', async () => {
|
|
const params = new URLSearchParams({
|
|
prompt: 'Performance test image',
|
|
aspectRatio: '1:1',
|
|
});
|
|
|
|
// First call (MISS)
|
|
log.info('Making first call (MISS)...');
|
|
const firstCall = await api(`${endpoints.live}?${params}`, {
|
|
timeout: 60000,
|
|
});
|
|
const firstDuration = firstCall.duration;
|
|
|
|
await wait(1000);
|
|
|
|
// Rapid subsequent calls (all HITs)
|
|
log.info('Making 5 rapid cache HIT calls...');
|
|
const durations: number[] = [];
|
|
|
|
for (let i = 0; i < 5; i++) {
|
|
const result = await api(`${endpoints.live}?${params}`);
|
|
durations.push(result.duration);
|
|
|
|
const cacheStatus = result.headers.get('X-Cache-Status');
|
|
if (cacheStatus !== 'HIT') {
|
|
throw new Error(`Call ${i + 1} expected HIT, got ${cacheStatus}`);
|
|
}
|
|
}
|
|
|
|
const avgHitDuration = durations.reduce((a, b) => a + b, 0) / durations.length;
|
|
|
|
log.detail('First call (MISS)', `${firstDuration}ms`);
|
|
log.detail('Avg HIT calls', `${avgHitDuration.toFixed(0)}ms`);
|
|
log.detail('Speedup', `${(firstDuration / avgHitDuration).toFixed(1)}x faster`);
|
|
});
|
|
|
|
log.section('LIVE ENDPOINT TESTS COMPLETED');
|
|
}
|
|
|
|
main().catch(console.error);
|