- 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.
142 lines
4.4 KiB
PHP
142 lines
4.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Unit\Framework\Logging;
|
|
|
|
use App\Framework\Logging\ValueObjects\ExceptionContext;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class ExceptionContextTest extends TestCase
|
|
{
|
|
public function test_creates_from_throwable(): void
|
|
{
|
|
$exception = new \RuntimeException('Test error', 123);
|
|
$context = ExceptionContext::fromThrowable($exception);
|
|
|
|
$this->assertEquals(\RuntimeException::class, $context->class);
|
|
$this->assertEquals('RuntimeException', $context->getShortClass());
|
|
$this->assertEquals('Test error', $context->message);
|
|
$this->assertEquals(123, $context->code);
|
|
$this->assertNotEmpty($context->file);
|
|
$this->assertGreaterThan(0, $context->line);
|
|
}
|
|
|
|
public function test_captures_stack_trace(): void
|
|
{
|
|
$exception = $this->createException();
|
|
$context = ExceptionContext::fromThrowable($exception);
|
|
|
|
$this->assertNotEmpty($context->stackTrace);
|
|
$this->assertContainsOnlyInstancesOf(
|
|
\App\Framework\Logging\ValueObjects\StackFrame::class,
|
|
$context->stackTrace
|
|
);
|
|
}
|
|
|
|
public function test_captures_previous_exception(): void
|
|
{
|
|
$previous = new \RuntimeException('Previous error');
|
|
$exception = new \RuntimeException('Current error', 0, $previous);
|
|
|
|
$context = ExceptionContext::fromThrowable($exception);
|
|
|
|
$this->assertNotNull($context->previous);
|
|
$this->assertEquals('Previous error', $context->previous->message);
|
|
$this->assertEquals(1, $context->getChainLength());
|
|
}
|
|
|
|
public function test_captures_exception_chain(): void
|
|
{
|
|
$first = new \RuntimeException('First');
|
|
$second = new \RuntimeException('Second', 0, $first);
|
|
$third = new \RuntimeException('Third', 0, $second);
|
|
|
|
$context = ExceptionContext::fromThrowable($third);
|
|
|
|
$this->assertEquals(2, $context->getChainLength());
|
|
|
|
$chain = $context->getChain();
|
|
$this->assertCount(3, $chain);
|
|
$this->assertEquals('Third', $chain[0]->message);
|
|
$this->assertEquals('Second', $chain[1]->message);
|
|
$this->assertEquals('First', $chain[2]->message);
|
|
}
|
|
|
|
public function test_get_top_frames(): void
|
|
{
|
|
$exception = $this->createException();
|
|
$context = ExceptionContext::fromThrowable($exception);
|
|
|
|
$topFrames = $context->getTopFrames(3);
|
|
|
|
$this->assertCount(min(3, count($context->stackTrace)), $topFrames);
|
|
}
|
|
|
|
public function test_to_array(): void
|
|
{
|
|
$exception = new \RuntimeException('Test');
|
|
$context = ExceptionContext::fromThrowable($exception);
|
|
|
|
$array = $context->toArray();
|
|
|
|
$this->assertArrayHasKey('class', $array);
|
|
$this->assertArrayHasKey('message', $array);
|
|
$this->assertArrayHasKey('file', $array);
|
|
$this->assertArrayHasKey('line', $array);
|
|
$this->assertArrayHasKey('stack_trace', $array);
|
|
}
|
|
|
|
public function test_to_compact_array(): void
|
|
{
|
|
$exception = new \RuntimeException('Test');
|
|
$context = ExceptionContext::fromThrowable($exception);
|
|
|
|
$array = $context->toCompactArray();
|
|
|
|
$this->assertArrayHasKey('class', $array);
|
|
$this->assertArrayHasKey('message', $array);
|
|
$this->assertArrayHasKey('location', $array);
|
|
$this->assertArrayNotHasKey('stack_trace', $array);
|
|
}
|
|
|
|
public function test_get_summary(): void
|
|
{
|
|
$exception = new \RuntimeException('Test error');
|
|
$context = ExceptionContext::fromThrowable($exception);
|
|
|
|
$summary = $context->getSummary();
|
|
|
|
$this->assertStringContainsString('RuntimeException', $summary);
|
|
$this->assertStringContainsString('Test error', $summary);
|
|
}
|
|
|
|
public function test_json_serializable(): void
|
|
{
|
|
$exception = new \RuntimeException('Test');
|
|
$context = ExceptionContext::fromThrowable($exception);
|
|
|
|
$json = json_encode($context);
|
|
|
|
$this->assertNotFalse($json);
|
|
|
|
$decoded = json_decode($json, true);
|
|
$this->assertArrayHasKey('class', $decoded);
|
|
$this->assertArrayHasKey('message', $decoded);
|
|
}
|
|
|
|
private function createException(): \Exception
|
|
{
|
|
try {
|
|
$this->throwException();
|
|
} catch (\Exception $e) {
|
|
return $e;
|
|
}
|
|
}
|
|
|
|
private function throwException(): void
|
|
{
|
|
throw new \RuntimeException('Test exception');
|
|
}
|
|
}
|