ciyidogan commited on
Commit
b823b0d
·
verified ·
1 Parent(s): fcd282f

Update flare-ui/src/app/components/test/test.component.ts

Browse files
flare-ui/src/app/components/test/test.component.ts CHANGED
@@ -10,11 +10,12 @@ import { MatListModule } from '@angular/material/list';
10
  import { MatChipsModule } from '@angular/material/chips';
11
  import { MatCardModule } from '@angular/material/card';
12
  import { ApiService } from '../../services/api.service';
 
13
  import { HttpClient } from '@angular/common/http';
14
 
15
  interface TestResult {
16
  name: string;
17
- status: 'PASS' | 'FAIL' | 'RUNNING' | 'SKIPPED';
18
  duration_ms?: number;
19
  error?: string;
20
  details?: string;
@@ -48,13 +49,14 @@ interface TestCase {
48
  MatExpansionModule,
49
  MatListModule,
50
  MatChipsModule,
51
- MatCardModule // ADD THIS
52
  ],
53
  templateUrl: './test.component.html',
54
  styleUrls: ['./test.component.scss']
55
  })
56
  export class TestComponent implements OnInit {
57
  private apiService = inject(ApiService);
 
58
  private http = inject(HttpClient);
59
 
60
  running = false;
@@ -66,28 +68,28 @@ export class TestComponent implements OnInit {
66
  name: 'auth',
67
  displayName: 'Authentication Tests',
68
  tests: [],
69
- selected: false,
70
  expanded: false
71
  },
72
  {
73
  name: 'api',
74
  displayName: 'API Endpoint Tests',
75
  tests: [],
76
- selected: false,
77
  expanded: false
78
  },
79
  {
80
  name: 'validation',
81
  displayName: 'Validation Tests',
82
  tests: [],
83
- selected: false,
84
  expanded: false
85
  },
86
  {
87
  name: 'integration',
88
  displayName: 'Integration Tests',
89
  tests: [],
90
- selected: false,
91
  expanded: false
92
  }
93
  ];
@@ -119,7 +121,6 @@ export class TestComponent implements OnInit {
119
 
120
  ngOnInit() {
121
  this.initializeTests();
122
- // Başlangıçta tüm kategoriler seçili mi kontrol et
123
  this.updateAllSelected();
124
  }
125
 
@@ -131,9 +132,35 @@ export class TestComponent implements OnInit {
131
  this.updateAllSelected();
132
  }
133
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  initializeTests() {
135
  // Authentication Tests
136
  this.addTest('auth', 'Login with valid credentials', async () => {
 
137
  try {
138
  const response = await this.http.post('/api/login', {
139
  username: 'admin',
@@ -143,37 +170,39 @@ export class TestComponent implements OnInit {
143
  return {
144
  name: 'Login with valid credentials',
145
  status: response?.token ? 'PASS' : 'FAIL',
146
- duration_ms: 120
 
147
  };
148
  } catch (error) {
149
  return {
150
  name: 'Login with valid credentials',
151
  status: 'FAIL',
152
  error: 'Login failed',
153
- duration_ms: 120
154
  };
155
  }
156
  });
157
 
158
  this.addTest('auth', 'Login with invalid credentials', async () => {
 
159
  try {
160
  await this.http.post('/api/login', {
161
  username: 'admin',
162
- password: 'wrong'
163
  }).toPromise();
164
 
165
  return {
166
  name: 'Login with invalid credentials',
167
  status: 'FAIL',
168
  error: 'Expected 401 but got success',
169
- duration_ms: 80
170
  };
171
  } catch (error: any) {
172
  return {
173
  name: 'Login with invalid credentials',
174
  status: error.status === 401 ? 'PASS' : 'FAIL',
175
- duration_ms: 80,
176
- details: 'Correctly rejected invalid credentials'
177
  };
178
  }
179
  });
@@ -182,11 +211,21 @@ export class TestComponent implements OnInit {
182
  this.addTest('api', 'GET /api/environment', async () => {
183
  const start = Date.now();
184
  try {
 
 
 
 
 
 
 
 
 
185
  const response = await this.apiService.getEnvironment().toPromise();
186
  return {
187
  name: 'GET /api/environment',
188
  status: response?.work_mode ? 'PASS' : 'FAIL',
189
- duration_ms: Date.now() - start
 
190
  };
191
  } catch (error) {
192
  return {
@@ -201,12 +240,21 @@ export class TestComponent implements OnInit {
201
  this.addTest('api', 'GET /api/projects', async () => {
202
  const start = Date.now();
203
  try {
 
 
 
 
 
 
 
 
 
204
  const response = await this.apiService.getProjects().toPromise();
205
  return {
206
  name: 'GET /api/projects',
207
  status: Array.isArray(response) ? 'PASS' : 'FAIL',
208
  duration_ms: Date.now() - start,
209
- details: `Retrieved ${response?.length || 0} projects`
210
  };
211
  } catch (error) {
212
  return {
@@ -221,12 +269,21 @@ export class TestComponent implements OnInit {
221
  this.addTest('api', 'GET /api/apis', async () => {
222
  const start = Date.now();
223
  try {
 
 
 
 
 
 
 
 
 
224
  const response = await this.apiService.getAPIs().toPromise();
225
  return {
226
  name: 'GET /api/apis',
227
  status: Array.isArray(response) ? 'PASS' : 'FAIL',
228
  duration_ms: Date.now() - start,
229
- details: `Retrieved ${response?.length || 0} APIs`
230
  };
231
  } catch (error) {
232
  return {
@@ -244,26 +301,54 @@ export class TestComponent implements OnInit {
244
  let projectId: number | undefined = undefined;
245
 
246
  try {
247
- // Create project
 
 
 
 
 
 
 
 
 
 
248
  const createResponse = await this.apiService.createProject({
249
- name: `test_project_${Date.now()}`,
250
- caption: 'Test Project'
 
 
251
  }).toPromise() as any;
252
 
253
  if (!createResponse?.id) {
254
- throw new Error('Project creation failed');
255
  }
256
 
257
  projectId = createResponse.id;
258
 
 
 
 
 
 
 
 
 
259
  // Delete project
260
- await this.apiService.deleteProject(projectId!).toPromise();
 
 
 
 
 
 
 
 
261
 
262
  return {
263
  name: 'Create and delete project',
264
  status: 'PASS',
265
  duration_ms: Date.now() - start,
266
- details: 'Project lifecycle test passed'
267
  };
268
  } catch (error: any) {
269
  // Try to clean up if project was created
@@ -284,23 +369,102 @@ export class TestComponent implements OnInit {
284
 
285
  this.addTest('integration', 'API used in intent cannot be deleted', async () => {
286
  const start = Date.now();
 
 
 
287
  try {
288
- // Try to delete an API that's used in intents
289
- await this.apiService.deleteAPI('book_flight_api').toPromise();
290
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291
  return {
292
  name: 'API used in intent cannot be deleted',
293
  status: 'FAIL',
294
- error: 'Expected error but API was deleted',
295
  duration_ms: Date.now() - start
296
  };
297
- } catch (error: any) {
298
- return {
299
- name: 'API used in intent cannot be deleted',
300
- status: error.status === 400 ? 'PASS' : 'FAIL',
301
- duration_ms: Date.now() - start,
302
- details: 'Correctly prevented deletion of API in use'
303
- };
 
 
 
 
304
  }
305
  });
306
 
@@ -308,17 +472,29 @@ export class TestComponent implements OnInit {
308
  this.addTest('validation', 'Regex validation - valid pattern', async () => {
309
  const start = Date.now();
310
  try {
311
- const response = await this.apiService.validateRegex('^[A-Z]{3}$', 'ABC').toPromise();
 
 
 
 
 
 
 
 
 
312
  return {
313
  name: 'Regex validation - valid pattern',
314
- status: response.valid && response.matches ? 'PASS' : 'FAIL',
315
- duration_ms: Date.now() - start
 
 
 
316
  };
317
  } catch (error) {
318
  return {
319
  name: 'Regex validation - valid pattern',
320
  status: 'FAIL',
321
- error: 'Validation failed',
322
  duration_ms: Date.now() - start
323
  };
324
  }
@@ -327,14 +503,26 @@ export class TestComponent implements OnInit {
327
  this.addTest('validation', 'Regex validation - invalid pattern', async () => {
328
  const start = Date.now();
329
  try {
330
- const response = await this.apiService.validateRegex('[invalid', 'test').toPromise();
 
 
 
 
 
 
 
 
 
331
  return {
332
  name: 'Regex validation - invalid pattern',
333
- status: !response.valid ? 'PASS' : 'FAIL',
334
  duration_ms: Date.now() - start,
335
- details: 'Correctly identified invalid regex'
 
 
336
  };
337
- } catch (error) {
 
338
  return {
339
  name: 'Regex validation - invalid pattern',
340
  status: 'PASS',
@@ -346,7 +534,8 @@ export class TestComponent implements OnInit {
346
 
347
  // Update test counts
348
  this.categories.forEach(cat => {
349
- cat.displayName = `${cat.displayName} (${cat.tests.length} tests)`;
 
350
  });
351
  }
352
 
 
10
  import { MatChipsModule } from '@angular/material/chips';
11
  import { MatCardModule } from '@angular/material/card';
12
  import { ApiService } from '../../services/api.service';
13
+ import { AuthService } from '../../services/auth.service';
14
  import { HttpClient } from '@angular/common/http';
15
 
16
  interface TestResult {
17
  name: string;
18
+ status: 'PASS' | 'FAIL' | 'RUNNING' | 'SKIP';
19
  duration_ms?: number;
20
  error?: string;
21
  details?: string;
 
49
  MatExpansionModule,
50
  MatListModule,
51
  MatChipsModule,
52
+ MatCardModule
53
  ],
54
  templateUrl: './test.component.html',
55
  styleUrls: ['./test.component.scss']
56
  })
57
  export class TestComponent implements OnInit {
58
  private apiService = inject(ApiService);
59
+ private authService = inject(AuthService);
60
  private http = inject(HttpClient);
61
 
62
  running = false;
 
68
  name: 'auth',
69
  displayName: 'Authentication Tests',
70
  tests: [],
71
+ selected: true,
72
  expanded: false
73
  },
74
  {
75
  name: 'api',
76
  displayName: 'API Endpoint Tests',
77
  tests: [],
78
+ selected: true,
79
  expanded: false
80
  },
81
  {
82
  name: 'validation',
83
  displayName: 'Validation Tests',
84
  tests: [],
85
+ selected: true,
86
  expanded: false
87
  },
88
  {
89
  name: 'integration',
90
  displayName: 'Integration Tests',
91
  tests: [],
92
+ selected: true,
93
  expanded: false
94
  }
95
  ];
 
121
 
122
  ngOnInit() {
123
  this.initializeTests();
 
124
  this.updateAllSelected();
125
  }
126
 
 
132
  this.updateAllSelected();
133
  }
134
 
135
+ // Helper method to ensure authentication
136
+ private async ensureAuth(): Promise<boolean> {
137
+ try {
138
+ // Check if we already have a token
139
+ if (this.authService.getToken()) {
140
+ return true;
141
+ }
142
+
143
+ // Otherwise login
144
+ const response = await this.http.post('/api/login', {
145
+ username: 'admin',
146
+ password: 'admin'
147
+ }).toPromise() as any;
148
+
149
+ if (response?.token) {
150
+ this.authService.setToken(response.token);
151
+ this.authService.setUsername(response.username);
152
+ return true;
153
+ }
154
+ return false;
155
+ } catch {
156
+ return false;
157
+ }
158
+ }
159
+
160
  initializeTests() {
161
  // Authentication Tests
162
  this.addTest('auth', 'Login with valid credentials', async () => {
163
+ const start = Date.now();
164
  try {
165
  const response = await this.http.post('/api/login', {
166
  username: 'admin',
 
170
  return {
171
  name: 'Login with valid credentials',
172
  status: response?.token ? 'PASS' : 'FAIL',
173
+ duration_ms: Date.now() - start,
174
+ details: response?.token ? 'Successfully authenticated' : 'No token received'
175
  };
176
  } catch (error) {
177
  return {
178
  name: 'Login with valid credentials',
179
  status: 'FAIL',
180
  error: 'Login failed',
181
+ duration_ms: Date.now() - start
182
  };
183
  }
184
  });
185
 
186
  this.addTest('auth', 'Login with invalid credentials', async () => {
187
+ const start = Date.now();
188
  try {
189
  await this.http.post('/api/login', {
190
  username: 'admin',
191
+ password: 'wrong_password_12345'
192
  }).toPromise();
193
 
194
  return {
195
  name: 'Login with invalid credentials',
196
  status: 'FAIL',
197
  error: 'Expected 401 but got success',
198
+ duration_ms: Date.now() - start
199
  };
200
  } catch (error: any) {
201
  return {
202
  name: 'Login with invalid credentials',
203
  status: error.status === 401 ? 'PASS' : 'FAIL',
204
+ duration_ms: Date.now() - start,
205
+ details: error.status === 401 ? 'Correctly rejected invalid credentials' : `Unexpected status: ${error.status}`
206
  };
207
  }
208
  });
 
211
  this.addTest('api', 'GET /api/environment', async () => {
212
  const start = Date.now();
213
  try {
214
+ if (!await this.ensureAuth()) {
215
+ return {
216
+ name: 'GET /api/environment',
217
+ status: 'SKIP',
218
+ error: 'Authentication failed',
219
+ duration_ms: Date.now() - start
220
+ };
221
+ }
222
+
223
  const response = await this.apiService.getEnvironment().toPromise();
224
  return {
225
  name: 'GET /api/environment',
226
  status: response?.work_mode ? 'PASS' : 'FAIL',
227
+ duration_ms: Date.now() - start,
228
+ details: response?.work_mode ? `Work mode: ${response.work_mode}` : 'No work mode returned'
229
  };
230
  } catch (error) {
231
  return {
 
240
  this.addTest('api', 'GET /api/projects', async () => {
241
  const start = Date.now();
242
  try {
243
+ if (!await this.ensureAuth()) {
244
+ return {
245
+ name: 'GET /api/projects',
246
+ status: 'SKIP',
247
+ error: 'Authentication failed',
248
+ duration_ms: Date.now() - start
249
+ };
250
+ }
251
+
252
  const response = await this.apiService.getProjects().toPromise();
253
  return {
254
  name: 'GET /api/projects',
255
  status: Array.isArray(response) ? 'PASS' : 'FAIL',
256
  duration_ms: Date.now() - start,
257
+ details: Array.isArray(response) ? `Retrieved ${response.length} projects` : 'Invalid response format'
258
  };
259
  } catch (error) {
260
  return {
 
269
  this.addTest('api', 'GET /api/apis', async () => {
270
  const start = Date.now();
271
  try {
272
+ if (!await this.ensureAuth()) {
273
+ return {
274
+ name: 'GET /api/apis',
275
+ status: 'SKIP',
276
+ error: 'Authentication failed',
277
+ duration_ms: Date.now() - start
278
+ };
279
+ }
280
+
281
  const response = await this.apiService.getAPIs().toPromise();
282
  return {
283
  name: 'GET /api/apis',
284
  status: Array.isArray(response) ? 'PASS' : 'FAIL',
285
  duration_ms: Date.now() - start,
286
+ details: Array.isArray(response) ? `Retrieved ${response.length} APIs` : 'Invalid response format'
287
  };
288
  } catch (error) {
289
  return {
 
301
  let projectId: number | undefined = undefined;
302
 
303
  try {
304
+ if (!await this.ensureAuth()) {
305
+ return {
306
+ name: 'Create and delete project',
307
+ status: 'SKIP',
308
+ error: 'Authentication failed',
309
+ duration_ms: Date.now() - start
310
+ };
311
+ }
312
+
313
+ // Create test project
314
+ const testProjectName = `test_project_${Date.now()}`;
315
  const createResponse = await this.apiService.createProject({
316
+ name: testProjectName,
317
+ caption: 'Test Project for Integration Test',
318
+ icon: 'folder',
319
+ description: 'This is a test project'
320
  }).toPromise() as any;
321
 
322
  if (!createResponse?.id) {
323
+ throw new Error('Project creation failed - no ID returned');
324
  }
325
 
326
  projectId = createResponse.id;
327
 
328
+ // Verify project was created
329
+ const projects = await this.apiService.getProjects().toPromise() as any[];
330
+ const createdProject = projects.find(p => p.id === projectId);
331
+
332
+ if (!createdProject) {
333
+ throw new Error('Created project not found in project list');
334
+ }
335
+
336
  // Delete project
337
+ await this.apiService.deleteProject(projectId).toPromise();
338
+
339
+ // Verify project was soft deleted
340
+ const projectsAfterDelete = await this.apiService.getProjects().toPromise() as any[];
341
+ const deletedProject = projectsAfterDelete.find(p => p.id === projectId);
342
+
343
+ if (deletedProject) {
344
+ throw new Error('Project still visible after deletion');
345
+ }
346
 
347
  return {
348
  name: 'Create and delete project',
349
  status: 'PASS',
350
  duration_ms: Date.now() - start,
351
+ details: `Successfully created and deleted project: ${testProjectName}`
352
  };
353
  } catch (error: any) {
354
  // Try to clean up if project was created
 
369
 
370
  this.addTest('integration', 'API used in intent cannot be deleted', async () => {
371
  const start = Date.now();
372
+ let testApiName: string | undefined;
373
+ let testProjectId: number | undefined;
374
+
375
  try {
376
+ if (!await this.ensureAuth()) {
377
+ return {
378
+ name: 'API used in intent cannot be deleted',
379
+ status: 'SKIP',
380
+ error: 'Authentication failed',
381
+ duration_ms: Date.now() - start
382
+ };
383
+ }
384
+
385
+ // 1. Create test API
386
+ testApiName = `test_api_${Date.now()}`;
387
+ await this.apiService.createAPI({
388
+ name: testApiName,
389
+ url: 'https://test.example.com/api',
390
+ method: 'POST',
391
+ timeout_seconds: 10,
392
+ headers: { 'Content-Type': 'application/json' },
393
+ body_template: {}
394
+ }).toPromise();
395
+
396
+ // 2. Create test project with version that uses the API
397
+ const testProjectName = `test_project_${Date.now()}`;
398
+ const createProjectResponse = await this.apiService.createProject({
399
+ name: testProjectName,
400
+ caption: 'Test Project'
401
+ }).toPromise() as any;
402
+
403
+ testProjectId = createProjectResponse.id;
404
+
405
+ // 3. Update the version to add an intent that uses our API
406
+ const version = createProjectResponse.versions[0];
407
+ await this.apiService.updateVersion(testProjectId, version.id, {
408
+ caption: version.caption,
409
+ general_prompt: 'Test prompt',
410
+ llm: version.llm,
411
+ intents: [{
412
+ name: 'test-intent',
413
+ caption: 'Test Intent',
414
+ locale: 'tr-TR',
415
+ detection_prompt: 'Test detection',
416
+ examples: ['test example'],
417
+ parameters: [],
418
+ action: testApiName, // This is where we use the API
419
+ fallback_timeout_prompt: 'Timeout',
420
+ fallback_error_prompt: 'Error'
421
+ }],
422
+ last_update_date: version.last_update_date
423
+ }).toPromise();
424
+
425
+ // 4. Try to delete the API - this should fail
426
+ try {
427
+ await this.apiService.deleteAPI(testApiName).toPromise();
428
+
429
+ // If we reach here, deletion succeeded when it shouldn't have
430
+ return {
431
+ name: 'API used in intent cannot be deleted',
432
+ status: 'FAIL',
433
+ error: 'API was deleted even though it was in use',
434
+ duration_ms: Date.now() - start
435
+ };
436
+ } catch (deleteError: any) {
437
+ // Check if we got the expected error
438
+ const isExpectedError = deleteError.status === 400 &&
439
+ deleteError.error?.detail?.includes('API is used');
440
+
441
+ return {
442
+ name: 'API used in intent cannot be deleted',
443
+ status: isExpectedError ? 'PASS' : 'FAIL',
444
+ duration_ms: Date.now() - start,
445
+ details: isExpectedError
446
+ ? 'Correctly prevented deletion of API in use'
447
+ : `Unexpected error: Status ${deleteError.status}, Detail: ${deleteError.error?.detail || deleteError.message}`
448
+ };
449
+ }
450
+ } catch (error: any) {
451
  return {
452
  name: 'API used in intent cannot be deleted',
453
  status: 'FAIL',
454
+ error: `Test setup failed: ${error.message}`,
455
  duration_ms: Date.now() - start
456
  };
457
+ } finally {
458
+ // Cleanup
459
+ try {
460
+ if (testProjectId) {
461
+ await this.apiService.deleteProject(testProjectId).toPromise();
462
+ }
463
+ if (testApiName) {
464
+ // Now we can delete the API since the project is gone
465
+ await this.apiService.deleteAPI(testApiName).toPromise();
466
+ }
467
+ } catch {}
468
  }
469
  });
470
 
 
472
  this.addTest('validation', 'Regex validation - valid pattern', async () => {
473
  const start = Date.now();
474
  try {
475
+ if (!await this.ensureAuth()) {
476
+ return {
477
+ name: 'Regex validation - valid pattern',
478
+ status: 'SKIP',
479
+ error: 'Authentication failed',
480
+ duration_ms: Date.now() - start
481
+ };
482
+ }
483
+
484
+ const response = await this.apiService.validateRegex('^[A-Z]{3}$', 'ABC').toPromise() as any;
485
  return {
486
  name: 'Regex validation - valid pattern',
487
+ status: response?.valid && response?.matches ? 'PASS' : 'FAIL',
488
+ duration_ms: Date.now() - start,
489
+ details: response?.valid && response?.matches
490
+ ? 'Pattern matched successfully'
491
+ : 'Pattern did not match or validation failed'
492
  };
493
  } catch (error) {
494
  return {
495
  name: 'Regex validation - valid pattern',
496
  status: 'FAIL',
497
+ error: 'Validation endpoint failed',
498
  duration_ms: Date.now() - start
499
  };
500
  }
 
503
  this.addTest('validation', 'Regex validation - invalid pattern', async () => {
504
  const start = Date.now();
505
  try {
506
+ if (!await this.ensureAuth()) {
507
+ return {
508
+ name: 'Regex validation - invalid pattern',
509
+ status: 'SKIP',
510
+ error: 'Authentication failed',
511
+ duration_ms: Date.now() - start
512
+ };
513
+ }
514
+
515
+ const response = await this.apiService.validateRegex('[invalid', 'test').toPromise() as any;
516
  return {
517
  name: 'Regex validation - invalid pattern',
518
+ status: !response?.valid ? 'PASS' : 'FAIL',
519
  duration_ms: Date.now() - start,
520
+ details: !response?.valid
521
+ ? 'Correctly identified invalid regex'
522
+ : 'Failed to identify invalid regex'
523
  };
524
+ } catch (error: any) {
525
+ // Some errors are expected for invalid regex
526
  return {
527
  name: 'Regex validation - invalid pattern',
528
  status: 'PASS',
 
534
 
535
  // Update test counts
536
  this.categories.forEach(cat => {
537
+ const originalName = cat.displayName.split(' (')[0];
538
+ cat.displayName = `${originalName} (${cat.tests.length} tests)`;
539
  });
540
  }
541