- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
220 lines
8.1 KiB
PHP
220 lines
8.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Framework\Database\ValueObjects\SqlState;
|
|
|
|
describe('SqlState Value Object', function () {
|
|
it('validates SQLSTATE format', function () {
|
|
// Valid 5-character alphanumeric codes
|
|
expect(fn() => new SqlState('23505'))->not->toThrow(\InvalidArgumentException::class);
|
|
expect(fn() => new SqlState('08001'))->not->toThrow(\InvalidArgumentException::class);
|
|
expect(fn() => new SqlState('42S02'))->not->toThrow(\InvalidArgumentException::class);
|
|
expect(fn() => new SqlState('HY000'))->not->toThrow(\InvalidArgumentException::class);
|
|
});
|
|
|
|
it('rejects invalid SQLSTATE formats', function () {
|
|
// Too short
|
|
expect(fn() => new SqlState('2350'))->toThrow(\InvalidArgumentException::class);
|
|
|
|
// Too long
|
|
expect(fn() => new SqlState('235050'))->toThrow(\InvalidArgumentException::class);
|
|
|
|
// Invalid characters
|
|
expect(fn() => new SqlState('23-05'))->toThrow(\InvalidArgumentException::class);
|
|
expect(fn() => new SqlState('23@05'))->toThrow(\InvalidArgumentException::class);
|
|
expect(fn() => new SqlState('abcde'))->toThrow(\InvalidArgumentException::class);
|
|
});
|
|
|
|
it('extracts SQLSTATE class correctly', function () {
|
|
$sqlState = new SqlState('23505');
|
|
expect($sqlState->getClass())->toBe('23');
|
|
|
|
$sqlState = new SqlState('08001');
|
|
expect($sqlState->getClass())->toBe('08');
|
|
|
|
$sqlState = new SqlState('42S02');
|
|
expect($sqlState->getClass())->toBe('42');
|
|
});
|
|
|
|
it('extracts SQLSTATE subclass correctly', function () {
|
|
$sqlState = new SqlState('23505');
|
|
expect($sqlState->getSubclass())->toBe('505');
|
|
|
|
$sqlState = new SqlState('08001');
|
|
expect($sqlState->getSubclass())->toBe('001');
|
|
|
|
$sqlState = new SqlState('42S02');
|
|
expect($sqlState->getSubclass())->toBe('S02');
|
|
});
|
|
|
|
it('identifies connection errors', function () {
|
|
$connectionError = new SqlState('08001');
|
|
expect($connectionError->isConnectionError())->toBeTrue();
|
|
|
|
$otherError = new SqlState('23505');
|
|
expect($otherError->isConnectionError())->toBeFalse();
|
|
});
|
|
|
|
it('identifies constraint violations', function () {
|
|
$constraintViolation = new SqlState('23505');
|
|
expect($constraintViolation->isConstraintViolation())->toBeTrue();
|
|
|
|
$otherError = new SqlState('08001');
|
|
expect($otherError->isConstraintViolation())->toBeFalse();
|
|
});
|
|
|
|
it('identifies transaction rollbacks', function () {
|
|
$transactionRollback = new SqlState('40001');
|
|
expect($transactionRollback->isTransactionRollback())->toBeTrue();
|
|
|
|
$otherError = new SqlState('23505');
|
|
expect($otherError->isTransactionRollback())->toBeFalse();
|
|
});
|
|
|
|
it('identifies syntax errors', function () {
|
|
$syntaxError = new SqlState('42000');
|
|
expect($syntaxError->isSyntaxError())->toBeTrue();
|
|
|
|
$otherError = new SqlState('23505');
|
|
expect($otherError->isSyntaxError())->toBeFalse();
|
|
});
|
|
|
|
it('identifies driver errors', function () {
|
|
$driverError = new SqlState('HY000');
|
|
expect($driverError->isDriverError())->toBeTrue();
|
|
|
|
$otherError = new SqlState('23505');
|
|
expect($otherError->isDriverError())->toBeFalse();
|
|
});
|
|
|
|
it('identifies unique violations', function () {
|
|
$uniqueViolation = new SqlState('23505');
|
|
expect($uniqueViolation->isUniqueViolation())->toBeTrue();
|
|
|
|
$otherConstraint = new SqlState('23503');
|
|
expect($otherConstraint->isUniqueViolation())->toBeFalse();
|
|
});
|
|
|
|
it('identifies foreign key violations', function () {
|
|
$foreignKeyViolation = new SqlState('23503');
|
|
expect($foreignKeyViolation->isForeignKeyViolation())->toBeTrue();
|
|
|
|
$otherConstraint = new SqlState('23505');
|
|
expect($otherConstraint->isForeignKeyViolation())->toBeFalse();
|
|
});
|
|
|
|
it('identifies not null violations', function () {
|
|
$notNullViolation = new SqlState('23502');
|
|
expect($notNullViolation->isNotNullViolation())->toBeTrue();
|
|
|
|
$otherConstraint = new SqlState('23505');
|
|
expect($otherConstraint->isNotNullViolation())->toBeFalse();
|
|
});
|
|
|
|
it('identifies check constraint violations', function () {
|
|
$checkViolation = new SqlState('23514');
|
|
expect($checkViolation->isCheckViolation())->toBeTrue();
|
|
|
|
$otherConstraint = new SqlState('23505');
|
|
expect($otherConstraint->isCheckViolation())->toBeFalse();
|
|
});
|
|
|
|
it('identifies table not found errors', function () {
|
|
$tableNotFound = new SqlState('42S02');
|
|
expect($tableNotFound->isTableNotFound())->toBeTrue();
|
|
|
|
$otherError = new SqlState('42S22');
|
|
expect($otherError->isTableNotFound())->toBeFalse();
|
|
});
|
|
|
|
it('identifies column not found errors', function () {
|
|
$columnNotFound = new SqlState('42S22');
|
|
expect($columnNotFound->isColumnNotFound())->toBeTrue();
|
|
|
|
$otherError = new SqlState('42S02');
|
|
expect($otherError->isColumnNotFound())->toBeFalse();
|
|
});
|
|
|
|
it('identifies deadlocks', function () {
|
|
$deadlock = new SqlState('40001');
|
|
expect($deadlock->isDeadlock())->toBeTrue();
|
|
|
|
$otherError = new SqlState('40002');
|
|
expect($otherError->isDeadlock())->toBeFalse();
|
|
});
|
|
|
|
it('identifies serialization failures', function () {
|
|
$serializationFailure = new SqlState('40001');
|
|
expect($serializationFailure->isSerializationFailure())->toBeTrue();
|
|
|
|
$otherError = new SqlState('40002');
|
|
expect($otherError->isSerializationFailure())->toBeFalse();
|
|
});
|
|
|
|
it('identifies connection failures', function () {
|
|
$connectionFailure = new SqlState('08001');
|
|
expect($connectionFailure->isConnectionFailure())->toBeTrue();
|
|
|
|
$otherConnectionError = new SqlState('08003');
|
|
expect($otherConnectionError->isConnectionFailure())->toBeFalse();
|
|
});
|
|
|
|
it('identifies connection does not exist', function () {
|
|
$connectionDoesNotExist = new SqlState('08003');
|
|
expect($connectionDoesNotExist->isConnectionDoesNotExist())->toBeTrue();
|
|
|
|
$otherConnectionError = new SqlState('08001');
|
|
expect($otherConnectionError->isConnectionDoesNotExist())->toBeFalse();
|
|
});
|
|
|
|
it('identifies connection rejected', function () {
|
|
$connectionRejected = new SqlState('08004');
|
|
expect($connectionRejected->isConnectionRejected())->toBeTrue();
|
|
|
|
$otherConnectionError = new SqlState('08001');
|
|
expect($otherConnectionError->isConnectionRejected())->toBeFalse();
|
|
});
|
|
|
|
it('compares SQLSTATE codes for equality', function () {
|
|
$sqlState1 = new SqlState('23505');
|
|
$sqlState2 = new SqlState('23505');
|
|
$sqlState3 = new SqlState('23503');
|
|
|
|
expect($sqlState1->equals($sqlState2))->toBeTrue();
|
|
expect($sqlState1->equals($sqlState3))->toBeFalse();
|
|
});
|
|
|
|
it('converts to string representation', function () {
|
|
$sqlState = new SqlState('23505');
|
|
|
|
expect($sqlState->toString())->toBe('23505');
|
|
expect((string) $sqlState)->toBe('23505');
|
|
expect($sqlState->__toString())->toBe('23505');
|
|
});
|
|
|
|
it('handles PostgreSQL-specific codes', function () {
|
|
$pgUniqueViolation = new SqlState('23505');
|
|
expect($pgUniqueViolation->isUniqueViolation())->toBeTrue();
|
|
expect($pgUniqueViolation->isConstraintViolation())->toBeTrue();
|
|
|
|
$pgTableNotFound = new SqlState('42P01');
|
|
expect($pgTableNotFound->isSyntaxError())->toBeTrue();
|
|
});
|
|
|
|
it('handles MySQL-specific codes', function () {
|
|
$mysqlTableNotFound = new SqlState('42S02');
|
|
expect($mysqlTableNotFound->isTableNotFound())->toBeTrue();
|
|
expect($mysqlTableNotFound->isSyntaxError())->toBeTrue();
|
|
|
|
$mysqlColumnNotFound = new SqlState('42S22');
|
|
expect($mysqlColumnNotFound->isColumnNotFound())->toBeTrue();
|
|
});
|
|
|
|
it('handles driver-specific codes', function () {
|
|
$driverError = new SqlState('HY000');
|
|
expect($driverError->isDriverError())->toBeTrue();
|
|
expect($driverError->getClass())->toBe('HY');
|
|
});
|
|
});
|