-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest-database-api.js
More file actions
302 lines (252 loc) · 9.19 KB
/
test-database-api.js
File metadata and controls
302 lines (252 loc) · 9.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
/**
* Test Script for Database Integration
* Tests API key management and submission persistence
*/
const axios = require('axios');
const colors = require('colors/safe');
const API_URL = process.env.API_URL || 'http://localhost:4000';
// Test data
let testApiKey = null;
let testApiKeyId = null;
let testSubmissionId = null;
// Helper function to make API calls
async function apiCall(method, endpoint, data = null, apiKey = null) {
try {
const config = {
method,
url: `${API_URL}${endpoint}`,
headers: {}
};
if (apiKey) {
config.headers['X-API-Key'] = apiKey;
}
if (data) {
config.data = data;
}
const response = await axios(config);
return response.data;
} catch (error) {
if (error.response) {
throw new Error(`API Error: ${error.response.data.error || error.response.statusText}`);
}
throw error;
}
}
// Test functions
async function testHealth() {
console.log(colors.blue('\n📋 Testing Health Endpoint...'));
const health = await apiCall('GET', '/health');
console.log(colors.green('✅ Health check passed:'), health);
return true;
}
async function testCreateApiKey() {
console.log(colors.blue('\n🔑 Testing API Key Creation...'));
// Use a demo key for initial authentication
const demoKey = 'sk_demo_test_key';
const result = await apiCall('POST', '/api/v1/api-keys', {
name: 'Test API Key',
permissions: ['*']
}, demoKey);
if (result.success && result.data.key) {
testApiKey = result.data.key;
testApiKeyId = result.data.id;
console.log(colors.green('✅ API Key created:'));
console.log(' Key ID:', result.data.id);
console.log(' Key Prefix:', result.data.key_prefix);
console.log(' Full Key:', colors.yellow(testApiKey));
console.log(colors.yellow(' ⚠️ Store this key securely - it won\'t be shown again!'));
return true;
} else {
throw new Error('Failed to create API key');
}
}
async function testListApiKeys() {
console.log(colors.blue('\n📋 Testing List API Keys...'));
const result = await apiCall('GET', '/api/v1/api-keys', null, testApiKey || 'sk_demo_test');
if (result.success) {
console.log(colors.green('✅ API Keys listed:'));
result.data.forEach(key => {
console.log(` - ${key.name} (${key.key_prefix}...) - Active: ${key.is_active}`);
});
return true;
} else {
throw new Error('Failed to list API keys');
}
}
async function testCreateSubmission() {
console.log(colors.blue('\n📝 Testing Submission Creation with Database...'));
const submissionData = {
platform: 'hot100ai',
content: {
title: 'Test Product - Database Integration',
description: 'Testing database persistence for submissions',
url: 'https://example.com',
category: 'Developer Tools'
},
priority: 8
};
const result = await apiCall('POST', '/api/v1/submissions', submissionData, testApiKey || 'sk_demo_test');
if (result.success && result.data.id) {
testSubmissionId = result.data.id;
console.log(colors.green('✅ Submission created:'));
console.log(' ID:', result.data.id);
console.log(' Platform:', result.data.platform);
console.log(' Status:', result.data.status);
console.log(' Priority:', result.data.priority);
return true;
} else {
throw new Error('Failed to create submission');
}
}
async function testGetSubmission() {
console.log(colors.blue('\n🔍 Testing Get Submission...'));
if (!testSubmissionId) {
console.log(colors.yellow('⚠️ No submission ID to test with'));
return false;
}
const result = await apiCall('GET', `/api/v1/submissions/${testSubmissionId}`, null, testApiKey || 'sk_demo_test');
if (result.success && result.data) {
console.log(colors.green('✅ Submission retrieved:'));
console.log(' ID:', result.data.id);
console.log(' Status:', result.data.status);
console.log(' Progress:', result.data.progress || 0, '%');
return true;
} else {
throw new Error('Failed to get submission');
}
}
async function testListSubmissions() {
console.log(colors.blue('\n📋 Testing List Submissions...'));
const result = await apiCall('GET', '/api/v1/submissions', null, testApiKey || 'sk_demo_test');
if (result.success) {
console.log(colors.green('✅ Submissions listed:'));
console.log(' Total:', result.total);
if (result.data && result.data.length > 0) {
result.data.slice(0, 3).forEach(sub => {
console.log(` - ${sub.platform}: ${sub.content?.title || 'No title'} (${sub.status})`);
});
}
return true;
} else {
throw new Error('Failed to list submissions');
}
}
async function testRateLimit() {
console.log(colors.blue('\n⏱️ Testing Rate Limiting...'));
const testKey = testApiKey || 'sk_demo_test';
const requests = [];
// Make 5 rapid requests
for (let i = 0; i < 5; i++) {
requests.push(apiCall('GET', '/api/v1/submissions', null, testKey));
}
try {
const results = await Promise.all(requests);
console.log(colors.green('✅ Rate limit headers present'));
// Check last response headers (would need to modify apiCall to return headers)
console.log(' Note: Rate limit headers are set but not visible in this test');
return true;
} catch (error) {
if (error.message.includes('Rate limit')) {
console.log(colors.yellow('⚠️ Rate limit hit (expected behavior)'));
return true;
}
throw error;
}
}
async function testApiKeyUsage() {
console.log(colors.blue('\n📊 Testing API Key Usage Stats...'));
if (!testApiKeyId) {
console.log(colors.yellow('⚠️ No API key ID to test with'));
return false;
}
const result = await apiCall('GET', `/api/v1/api-keys/${testApiKeyId}/usage`, null, testApiKey || 'sk_demo_test');
if (result.success) {
console.log(colors.green('✅ Usage stats retrieved'));
if (result.data.total_requests) {
console.log(' Total Requests:', result.data.total_requests);
console.log(' Success Rate:', result.data.successful_requests / result.data.total_requests * 100, '%');
}
return true;
} else {
throw new Error('Failed to get usage stats');
}
}
async function testRevokeApiKey() {
console.log(colors.blue('\n🔒 Testing API Key Revocation...'));
if (!testApiKeyId || testApiKeyId === 'demo-key-id') {
console.log(colors.yellow('⚠️ No real API key to revoke (demo mode)'));
return true;
}
const result = await apiCall('DELETE', `/api/v1/api-keys/${testApiKeyId}`, null, testApiKey || 'sk_demo_test');
if (result.success) {
console.log(colors.green('✅ API key revoked successfully'));
// Try to use the revoked key
try {
await apiCall('GET', '/api/v1/submissions', null, testApiKey);
console.log(colors.red('❌ Revoked key still works (should not happen)'));
return false;
} catch (error) {
if (error.message.includes('Invalid')) {
console.log(colors.green('✅ Revoked key properly rejected'));
return true;
}
throw error;
}
} else {
throw new Error('Failed to revoke API key');
}
}
// Main test runner
async function runTests() {
console.log(colors.bold.cyan('\n🚀 Starting Database Integration Tests\n'));
console.log(colors.gray(`API URL: ${API_URL}`));
console.log(colors.gray(`Database: ${process.env.SUPABASE_URL ? 'Supabase' : 'Demo/In-Memory'}\n`));
const tests = [
{ name: 'Health Check', fn: testHealth },
{ name: 'Create API Key', fn: testCreateApiKey },
{ name: 'List API Keys', fn: testListApiKeys },
{ name: 'Create Submission', fn: testCreateSubmission },
{ name: 'Get Submission', fn: testGetSubmission },
{ name: 'List Submissions', fn: testListSubmissions },
{ name: 'Rate Limiting', fn: testRateLimit },
{ name: 'API Key Usage', fn: testApiKeyUsage },
{ name: 'Revoke API Key', fn: testRevokeApiKey }
];
let passed = 0;
let failed = 0;
for (const test of tests) {
try {
const result = await test.fn();
if (result !== false) {
passed++;
}
} catch (error) {
console.log(colors.red(`❌ ${test.name} failed:`, error.message));
failed++;
}
// Small delay between tests
await new Promise(resolve => setTimeout(resolve, 500));
}
console.log(colors.bold.cyan('\n📊 Test Results Summary\n'));
console.log(colors.green(`✅ Passed: ${passed}`));
console.log(colors.red(`❌ Failed: ${failed}`));
if (failed === 0) {
console.log(colors.bold.green('\n🎉 All tests passed! Database integration is working.\n'));
} else {
console.log(colors.bold.yellow(`\n⚠️ Some tests failed. Please check the configuration.\n`));
}
console.log(colors.gray('Next steps:'));
console.log(colors.gray('1. Run migrations if not already done: npm run migrate'));
console.log(colors.gray('2. Check Supabase dashboard for created data'));
console.log(colors.gray('3. Test with real browser profiles for actual submissions'));
}
// Check if colors module is available
if (!colors) {
console.log('Installing colors module...');
require('child_process').execSync('npm install colors', { stdio: 'inherit' });
}
// Run the tests
runTests().catch(error => {
console.error(colors.red('Fatal error:'), error);
process.exit(1);
});