107 lines
3.3 KiB
TypeScript
107 lines
3.3 KiB
TypeScript
/**
|
|
* Integration Test: Database Constraints and Error Mapping
|
|
*
|
|
* Tests that the API properly handles and maps database constraint violations.
|
|
*/
|
|
|
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
import { ApiClient } from '../harness/api-client';
|
|
import { DockerManager } from '../harness/docker-manager';
|
|
|
|
describe('Database Constraints - API Integration', () => {
|
|
let api: ApiClient;
|
|
let docker: DockerManager;
|
|
|
|
beforeAll(async () => {
|
|
docker = DockerManager.getInstance();
|
|
await docker.start();
|
|
|
|
api = new ApiClient({ baseUrl: 'http://localhost:3101', timeout: 60000 });
|
|
await api.waitForReady();
|
|
}, 120000);
|
|
|
|
afterAll(async () => {
|
|
docker.stop();
|
|
}, 30000);
|
|
|
|
it('should handle unique constraint violations gracefully', async () => {
|
|
// This test verifies that duplicate operations are rejected
|
|
// The exact behavior depends on the API implementation
|
|
|
|
// Try to perform an operation that might violate uniqueness
|
|
// For example, creating the same resource twice
|
|
const createData = {
|
|
name: 'Test League',
|
|
description: 'Test',
|
|
ownerId: 'test-owner',
|
|
};
|
|
|
|
// First attempt should succeed or fail gracefully
|
|
try {
|
|
await api.post('/leagues', createData);
|
|
} catch (error) {
|
|
// Expected: endpoint might not exist or validation fails
|
|
expect(error).toBeDefined();
|
|
}
|
|
});
|
|
|
|
it('should handle foreign key constraint violations', async () => {
|
|
// Try to create a resource with invalid foreign key
|
|
const invalidData = {
|
|
leagueId: 'non-existent-league',
|
|
// Other required fields...
|
|
};
|
|
|
|
await expect(
|
|
api.post('/leagues/non-existent/seasons', invalidData)
|
|
).rejects.toThrow();
|
|
});
|
|
|
|
it('should provide meaningful error messages', async () => {
|
|
// Test various invalid operations
|
|
const operations = [
|
|
() => api.post('/races/invalid-id/results/import', { resultsFileContent: 'invalid' }),
|
|
() => api.post('/leagues/invalid/seasons/invalid/publish', {}),
|
|
];
|
|
|
|
for (const operation of operations) {
|
|
try {
|
|
await operation();
|
|
throw new Error('Expected operation to fail');
|
|
} catch (error: any) {
|
|
// Should throw an error
|
|
expect(error).toBeDefined();
|
|
}
|
|
}
|
|
});
|
|
|
|
it('should maintain data integrity after failed operations', async () => {
|
|
// Verify that failed operations don't corrupt data
|
|
const initialHealth = await api.health();
|
|
expect(initialHealth).toBe(true);
|
|
|
|
// Try some invalid operations
|
|
try {
|
|
await api.post('/races/invalid/results/import', { resultsFileContent: 'invalid' });
|
|
} catch {}
|
|
|
|
// Verify API is still healthy
|
|
const finalHealth = await api.health();
|
|
expect(finalHealth).toBe(true);
|
|
});
|
|
|
|
it('should handle concurrent operations safely', async () => {
|
|
// Test that concurrent requests don't cause issues
|
|
const concurrentRequests = Array(5).fill(null).map(() =>
|
|
api.post('/races/invalid-id/results/import', {
|
|
resultsFileContent: JSON.stringify([{ invalid: 'data' }])
|
|
})
|
|
);
|
|
|
|
const results = await Promise.allSettled(concurrentRequests);
|
|
|
|
// At least some should fail (since they're invalid)
|
|
const failures = results.filter(r => r.status === 'rejected');
|
|
expect(failures.length).toBeGreaterThan(0);
|
|
});
|
|
}); |