- 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.
167 lines
4.8 KiB
PHP
167 lines
4.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Framework\Database\QueryOptimization\ValueObjects\QueryLog;
|
|
|
|
describe('QueryLog Value Object', function () {
|
|
it('creates query log with all properties', function () {
|
|
$log = new QueryLog(
|
|
sql: 'SELECT * FROM users WHERE id = ?',
|
|
bindings: [123],
|
|
executionTimeMs: 5.5,
|
|
stackTrace: 'UserController::index',
|
|
rowCount: 1,
|
|
callerClass: 'UserController',
|
|
callerMethod: 'index',
|
|
callerLine: 42
|
|
);
|
|
|
|
expect($log->sql)->toBe('SELECT * FROM users WHERE id = ?');
|
|
expect($log->bindings)->toBe([123]);
|
|
expect($log->executionTimeMs)->toBe(5.5);
|
|
expect($log->rowCount)->toBe(1);
|
|
expect($log->callerClass)->toBe('UserController');
|
|
expect($log->callerMethod)->toBe('index');
|
|
expect($log->callerLine)->toBe(42);
|
|
});
|
|
|
|
it('normalizes SQL pattern correctly', function () {
|
|
$log = new QueryLog(
|
|
sql: "SELECT * FROM users WHERE id = 123 AND email = 'test@example.com'",
|
|
bindings: [],
|
|
executionTimeMs: 1.0,
|
|
stackTrace: ''
|
|
);
|
|
|
|
$pattern = $log->getPattern();
|
|
|
|
expect($pattern)->toBe('SELECT * FROM users WHERE id = ? AND email = ?');
|
|
});
|
|
|
|
it('normalizes IN clauses', function () {
|
|
$log = new QueryLog(
|
|
sql: 'SELECT * FROM users WHERE id IN (1, 2, 3, 4, 5)',
|
|
bindings: [],
|
|
executionTimeMs: 1.0,
|
|
stackTrace: ''
|
|
);
|
|
|
|
$pattern = $log->getPattern();
|
|
|
|
expect($pattern)->toBe('SELECT * FROM users WHERE id IN (?)');
|
|
});
|
|
|
|
it('detects SELECT queries', function () {
|
|
$log = new QueryLog(
|
|
sql: 'SELECT * FROM users',
|
|
bindings: [],
|
|
executionTimeMs: 1.0,
|
|
stackTrace: ''
|
|
);
|
|
|
|
expect($log->isSelect())->toBeTrue();
|
|
expect($log->isInsert())->toBeFalse();
|
|
expect($log->isUpdate())->toBeFalse();
|
|
expect($log->isDelete())->toBeFalse();
|
|
});
|
|
|
|
it('detects INSERT queries', function () {
|
|
$log = new QueryLog(
|
|
sql: 'INSERT INTO users (name, email) VALUES (?, ?)',
|
|
bindings: ['John', 'john@example.com'],
|
|
executionTimeMs: 2.0,
|
|
stackTrace: ''
|
|
);
|
|
|
|
expect($log->isInsert())->toBeTrue();
|
|
expect($log->isSelect())->toBeFalse();
|
|
});
|
|
|
|
it('extracts table name from SELECT', function () {
|
|
$log = new QueryLog(
|
|
sql: 'SELECT * FROM users WHERE id = ?',
|
|
bindings: [1],
|
|
executionTimeMs: 1.0,
|
|
stackTrace: ''
|
|
);
|
|
|
|
expect($log->getTableName())->toBe('users');
|
|
});
|
|
|
|
it('extracts table name from INSERT', function () {
|
|
$log = new QueryLog(
|
|
sql: 'INSERT INTO orders (user_id, total) VALUES (?, ?)',
|
|
bindings: [1, 100],
|
|
executionTimeMs: 1.0,
|
|
stackTrace: ''
|
|
);
|
|
|
|
expect($log->getTableName())->toBe('orders');
|
|
});
|
|
|
|
it('detects WHERE clause', function () {
|
|
$log = new QueryLog(
|
|
sql: 'SELECT * FROM users WHERE id = ?',
|
|
bindings: [1],
|
|
executionTimeMs: 1.0,
|
|
stackTrace: ''
|
|
);
|
|
|
|
expect($log->hasWhereClause())->toBeTrue();
|
|
});
|
|
|
|
it('detects missing WHERE clause', function () {
|
|
$log = new QueryLog(
|
|
sql: 'SELECT * FROM users',
|
|
bindings: [],
|
|
executionTimeMs: 1.0,
|
|
stackTrace: ''
|
|
);
|
|
|
|
expect($log->hasWhereClause())->toBeFalse();
|
|
});
|
|
|
|
it('detects JOIN queries', function () {
|
|
$log = new QueryLog(
|
|
sql: 'SELECT * FROM users LEFT JOIN profiles ON users.id = profiles.user_id',
|
|
bindings: [],
|
|
executionTimeMs: 1.0,
|
|
stackTrace: ''
|
|
);
|
|
|
|
expect($log->hasJoin())->toBeTrue();
|
|
});
|
|
|
|
it('detects slow queries', function () {
|
|
$log = new QueryLog(
|
|
sql: 'SELECT * FROM users',
|
|
bindings: [],
|
|
executionTimeMs: 150.0,
|
|
stackTrace: ''
|
|
);
|
|
|
|
expect($log->isSlow(100.0))->toBeTrue();
|
|
expect($log->isSlow(200.0))->toBeFalse();
|
|
});
|
|
|
|
it('throws on negative execution time', function () {
|
|
new QueryLog(
|
|
sql: 'SELECT * FROM users',
|
|
bindings: [],
|
|
executionTimeMs: -5.0,
|
|
stackTrace: ''
|
|
);
|
|
})->throws(InvalidArgumentException::class, 'Execution time cannot be negative');
|
|
|
|
it('throws on negative row count', function () {
|
|
new QueryLog(
|
|
sql: 'SELECT * FROM users',
|
|
bindings: [],
|
|
executionTimeMs: 1.0,
|
|
stackTrace: '',
|
|
rowCount: -1
|
|
);
|
|
})->throws(InvalidArgumentException::class, 'Row count cannot be negative');
|
|
});
|