PRIMEIRO ENVIO

This commit is contained in:
2025-12-25 12:02:07 -03:00
parent ca49575224
commit c4d3bd9a86
92 changed files with 26976 additions and 1 deletions
@@ -0,0 +1,144 @@
import fc from 'fast-check';
// Feature: website-cloning-platform, Property 32: PostgreSQL Data Storage
describe('Database Connectivity Properties', () => {
test('Property 32: Database connection configuration should be valid', async () => {
await fc.assert(
fc.asyncProperty(
fc.record({
host: fc.domain(),
port: fc.integer({ min: 1024, max: 65535 }),
database: fc.string({ minLength: 1, maxLength: 50 }).filter(s => /^[a-zA-Z][a-zA-Z0-9_]*$/.test(s)),
username: fc.string({ minLength: 1, maxLength: 50 }).filter(s => /^[a-zA-Z][a-zA-Z0-9_]*$/.test(s)),
password: fc.string({ minLength: 8, maxLength: 100 }).filter(s => /^[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]*$/.test(s) && !s.includes(' '))
}),
async (config) => {
// Test that database URL construction is valid
const encodedPassword = encodeURIComponent(config.password);
const databaseUrl = `postgresql://${config.username}:${encodedPassword}@${config.host}:${config.port}/${config.database}`;
// Validate URL format
try {
const url = new URL(databaseUrl);
return url.protocol === 'postgresql:' &&
url.hostname === config.host &&
url.port === config.port.toString() &&
url.pathname === `/${config.database}` &&
url.username === config.username;
} catch (error) {
return false;
}
}
),
{
numRuns: 100,
timeout: 5000
}
);
});
test('Property 32: Database connection parameters should be properly validated', async () => {
await fc.assert(
fc.asyncProperty(
fc.record({
maxConnections: fc.integer({ min: 1, max: 100 }),
connectionTimeout: fc.integer({ min: 1000, max: 60000 }),
queryTimeout: fc.integer({ min: 1000, max: 300000 }),
retryAttempts: fc.integer({ min: 0, max: 10 })
}),
async (params) => {
// Validate that connection parameters are within acceptable ranges
const isValidMaxConnections = params.maxConnections >= 1 && params.maxConnections <= 100;
const isValidConnectionTimeout = params.connectionTimeout >= 1000 && params.connectionTimeout <= 60000;
const isValidQueryTimeout = params.queryTimeout >= 1000 && params.queryTimeout <= 300000;
const isValidRetryAttempts = params.retryAttempts >= 0 && params.retryAttempts <= 10;
return isValidMaxConnections &&
isValidConnectionTimeout &&
isValidQueryTimeout &&
isValidRetryAttempts;
}
),
{
numRuns: 100,
timeout: 5000
}
);
});
test('Property 32: Database schema validation should handle various data types', async () => {
await fc.assert(
fc.asyncProperty(
fc.record({
stringField: fc.string({ minLength: 0, maxLength: 1000 }),
integerField: fc.integer({ min: -2147483648, max: 2147483647 }),
booleanField: fc.boolean(),
dateField: fc.date({ min: new Date('1900-01-01'), max: new Date('2100-12-31') }),
optionalField: fc.option(fc.string({ minLength: 1, maxLength: 100 }))
}),
async (data) => {
// Validate that data types are properly handled
const isValidString = typeof data.stringField === 'string';
const isValidInteger = Number.isInteger(data.integerField) &&
data.integerField >= -2147483648 &&
data.integerField <= 2147483647;
const isValidBoolean = typeof data.booleanField === 'boolean';
const isValidDate = data.dateField instanceof Date && !isNaN(data.dateField.getTime());
const isValidOptional = data.optionalField === null || typeof data.optionalField === 'string';
return isValidString && isValidInteger && isValidBoolean && isValidDate && isValidOptional;
}
),
{
numRuns: 100,
timeout: 5000
}
);
});
test('Property 32: Database transaction properties should be maintained', async () => {
await fc.assert(
fc.asyncProperty(
fc.array(
fc.record({
operation: fc.constantFrom('INSERT', 'UPDATE', 'DELETE', 'SELECT'),
table: fc.constantFrom('users', 'projects', 'pages', 'assets'),
data: fc.record({
id: fc.string({ minLength: 1, maxLength: 50 }),
timestamp: fc.date()
})
}),
{ minLength: 1, maxLength: 10 }
),
async (operations) => {
// Test transaction properties: atomicity, consistency, isolation, durability (ACID)
// Atomicity: All operations in a transaction should succeed or fail together
const hasConsistentOperations = operations.every(op =>
['INSERT', 'UPDATE', 'DELETE', 'SELECT'].includes(op.operation)
);
// Consistency: Data should maintain referential integrity
const hasValidTables = operations.every(op =>
['users', 'projects', 'pages', 'assets'].includes(op.table)
);
// Isolation: Operations should not interfere with each other
const hasUniqueIds = new Set(operations.map(op => op.data.id)).size === operations.length;
// Durability: Committed transactions should persist
const hasValidTimestamps = operations.every(op =>
op.data.timestamp instanceof Date && !isNaN(op.data.timestamp.getTime())
);
return hasConsistentOperations && hasValidTables && hasUniqueIds && hasValidTimestamps;
}
),
{
numRuns: 100,
timeout: 5000
}
);
});
});
+53
View File
@@ -0,0 +1,53 @@
import { PrismaClient } from '@prisma/client';
// Simple logger for database operations
const logger = {
info: (message: string, ...args: any[]) => console.log(`[INFO] ${message}`, ...args),
error: (message: string, ...args: any[]) => console.error(`[ERROR] ${message}`, ...args),
warn: (message: string, ...args: any[]) => console.warn(`[WARN] ${message}`, ...args),
};
let prisma: PrismaClient;
declare global {
var __prisma: PrismaClient | undefined;
}
if (process.env.NODE_ENV === 'production') {
prisma = new PrismaClient({
log: ['error', 'warn'],
});
} else {
if (!global.__prisma) {
global.__prisma = new PrismaClient({
log: ['query', 'error', 'warn'],
});
}
prisma = global.__prisma;
}
// Test database connectivity
export async function testDatabaseConnection(): Promise<boolean> {
try {
await prisma.$connect();
await prisma.$queryRaw`SELECT 1`;
logger.info('Database connection successful');
return true;
} catch (error) {
logger.error('Database connection failed:', error);
return false;
}
}
// Graceful shutdown
export async function disconnectDatabase(): Promise<void> {
try {
await prisma.$disconnect();
logger.info('Database disconnected successfully');
} catch (error) {
logger.error('Error disconnecting from database:', error);
}
}
export { prisma };
export default prisma;
+2
View File
@@ -0,0 +1,2 @@
export * from './client';
export * from '@prisma/client';