feat: error-codes in flash messages to reference log entries
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Logger;
|
||||
|
||||
use App\Logger\ErrorCodeProcessor;
|
||||
use App\Service\ErrorCodeService;
|
||||
use Monolog\Level;
|
||||
use Monolog\LogRecord;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ErrorCodeProcessorTest extends TestCase
|
||||
{
|
||||
private ErrorCodeService $errorCodeService;
|
||||
private ErrorCodeProcessor $processor;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->errorCodeService = $this->createMock(ErrorCodeService::class);
|
||||
$this->processor = new ErrorCodeProcessor($this->errorCodeService);
|
||||
}
|
||||
|
||||
public function testIgnoresDebugLevel(): void
|
||||
{
|
||||
$record = new LogRecord(
|
||||
datetime: new \DateTimeImmutable(),
|
||||
channel: 'test',
|
||||
level: Level::Debug,
|
||||
message: 'Debug message',
|
||||
);
|
||||
|
||||
$this->errorCodeService
|
||||
->expects($this->never())
|
||||
->method('getErrorCode');
|
||||
|
||||
$this->errorCodeService
|
||||
->expects($this->never())
|
||||
->method('markErrorOccurred');
|
||||
|
||||
$result = ($this->processor)($record);
|
||||
|
||||
$this->assertArrayNotHasKey('error_code', $result->extra);
|
||||
}
|
||||
|
||||
public function testIgnoresInfoLevel(): void
|
||||
{
|
||||
$record = new LogRecord(
|
||||
datetime: new \DateTimeImmutable(),
|
||||
channel: 'test',
|
||||
level: Level::Info,
|
||||
message: 'Info message',
|
||||
);
|
||||
|
||||
$this->errorCodeService
|
||||
->expects($this->never())
|
||||
->method('getErrorCode');
|
||||
|
||||
$this->errorCodeService
|
||||
->expects($this->never())
|
||||
->method('markErrorOccurred');
|
||||
|
||||
$result = ($this->processor)($record);
|
||||
|
||||
$this->assertArrayNotHasKey('error_code', $result->extra);
|
||||
}
|
||||
|
||||
public function testIgnoresWarningLevel(): void
|
||||
{
|
||||
$record = new LogRecord(
|
||||
datetime: new \DateTimeImmutable(),
|
||||
channel: 'test',
|
||||
level: Level::Warning,
|
||||
message: 'Warning message',
|
||||
);
|
||||
|
||||
$this->errorCodeService
|
||||
->expects($this->never())
|
||||
->method('getErrorCode');
|
||||
|
||||
$this->errorCodeService
|
||||
->expects($this->never())
|
||||
->method('markErrorOccurred');
|
||||
|
||||
$result = ($this->processor)($record);
|
||||
|
||||
$this->assertArrayNotHasKey('error_code', $result->extra);
|
||||
}
|
||||
|
||||
public function testAddsErrorCodeForErrorLevel(): void
|
||||
{
|
||||
$record = new LogRecord(
|
||||
datetime: new \DateTimeImmutable(),
|
||||
channel: 'test',
|
||||
level: Level::Error,
|
||||
message: 'Error message',
|
||||
);
|
||||
|
||||
$this->errorCodeService
|
||||
->expects($this->once())
|
||||
->method('getErrorCode')
|
||||
->willReturn('E-ABC12345');
|
||||
|
||||
$this->errorCodeService
|
||||
->expects($this->once())
|
||||
->method('markErrorOccurred');
|
||||
|
||||
$result = ($this->processor)($record);
|
||||
|
||||
$this->assertArrayHasKey('error_code', $result->extra);
|
||||
$this->assertSame('E-ABC12345', $result->extra['error_code']);
|
||||
}
|
||||
|
||||
public function testAddsErrorCodeForCriticalLevel(): void
|
||||
{
|
||||
$record = new LogRecord(
|
||||
datetime: new \DateTimeImmutable(),
|
||||
channel: 'test',
|
||||
level: Level::Critical,
|
||||
message: 'Critical message',
|
||||
);
|
||||
|
||||
$this->errorCodeService
|
||||
->expects($this->once())
|
||||
->method('getErrorCode')
|
||||
->willReturn('E-XYZ78901');
|
||||
|
||||
$this->errorCodeService
|
||||
->expects($this->once())
|
||||
->method('markErrorOccurred');
|
||||
|
||||
$result = ($this->processor)($record);
|
||||
|
||||
$this->assertArrayHasKey('error_code', $result->extra);
|
||||
$this->assertSame('E-XYZ78901', $result->extra['error_code']);
|
||||
}
|
||||
|
||||
public function testAddsErrorCodeForEmergencyLevel(): void
|
||||
{
|
||||
$record = new LogRecord(
|
||||
datetime: new \DateTimeImmutable(),
|
||||
channel: 'test',
|
||||
level: Level::Emergency,
|
||||
message: 'Emergency message',
|
||||
);
|
||||
|
||||
$this->errorCodeService
|
||||
->expects($this->once())
|
||||
->method('getErrorCode')
|
||||
->willReturn('E-EMR99999');
|
||||
|
||||
$this->errorCodeService
|
||||
->expects($this->once())
|
||||
->method('markErrorOccurred');
|
||||
|
||||
$result = ($this->processor)($record);
|
||||
|
||||
$this->assertArrayHasKey('error_code', $result->extra);
|
||||
$this->assertSame('E-EMR99999', $result->extra['error_code']);
|
||||
}
|
||||
|
||||
public function testDoesNotAddCodeWhenServiceReturnsNull(): void
|
||||
{
|
||||
$record = new LogRecord(
|
||||
datetime: new \DateTimeImmutable(),
|
||||
channel: 'test',
|
||||
level: Level::Error,
|
||||
message: 'Error message',
|
||||
);
|
||||
|
||||
$this->errorCodeService
|
||||
->expects($this->once())
|
||||
->method('getErrorCode')
|
||||
->willReturn(null);
|
||||
|
||||
$this->errorCodeService
|
||||
->expects($this->never())
|
||||
->method('markErrorOccurred');
|
||||
|
||||
$result = ($this->processor)($record);
|
||||
|
||||
$this->assertArrayNotHasKey('error_code', $result->extra);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Service;
|
||||
|
||||
use App\Service\ErrorCodeService;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
class ErrorCodeServiceTest extends TestCase
|
||||
{
|
||||
private RequestStack $requestStack;
|
||||
private ErrorCodeService $service;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->requestStack = new RequestStack();
|
||||
$this->service = new ErrorCodeService($this->requestStack);
|
||||
}
|
||||
|
||||
public function testReturnsNullWithoutRequest(): void
|
||||
{
|
||||
$result = $this->service->getErrorCode();
|
||||
|
||||
$this->assertNull($result);
|
||||
}
|
||||
|
||||
public function testReturnsNullWithoutRequestId(): void
|
||||
{
|
||||
$request = new Request();
|
||||
$this->requestStack->push($request);
|
||||
|
||||
$result = $this->service->getErrorCode();
|
||||
|
||||
$this->assertNull($result);
|
||||
}
|
||||
|
||||
public function testGeneratesCodeWithRequestId(): void
|
||||
{
|
||||
$request = new Request();
|
||||
$request->attributes->set('request_id', 'abc123');
|
||||
$this->requestStack->push($request);
|
||||
|
||||
$result = $this->service->getErrorCode();
|
||||
|
||||
$this->assertNotNull($result);
|
||||
$this->assertMatchesRegularExpression('/^E-[A-Z0-9]{8}$/', $result);
|
||||
}
|
||||
|
||||
public function testGeneratesConsistentCodeForSameRequestId(): void
|
||||
{
|
||||
$request = new Request();
|
||||
$request->attributes->set('request_id', 'abc123');
|
||||
$this->requestStack->push($request);
|
||||
|
||||
$result1 = $this->service->getErrorCode();
|
||||
$result2 = $this->service->getErrorCode();
|
||||
|
||||
$this->assertSame($result1, $result2);
|
||||
}
|
||||
|
||||
public function testGeneratesDifferentCodesForDifferentRequestIds(): void
|
||||
{
|
||||
$request1 = new Request();
|
||||
$request1->attributes->set('request_id', 'abc123');
|
||||
$this->requestStack->push($request1);
|
||||
|
||||
$service1 = new ErrorCodeService($this->requestStack);
|
||||
$result1 = $service1->getErrorCode();
|
||||
|
||||
$this->requestStack->pop();
|
||||
|
||||
$request2 = new Request();
|
||||
$request2->attributes->set('request_id', 'xyz789');
|
||||
$this->requestStack->push($request2);
|
||||
|
||||
$service2 = new ErrorCodeService($this->requestStack);
|
||||
$result2 = $service2->getErrorCode();
|
||||
|
||||
$this->assertNotSame($result1, $result2);
|
||||
}
|
||||
|
||||
public function testSequenceSuffixesProduceSameCode(): void
|
||||
{
|
||||
$request1 = new Request();
|
||||
$request1->attributes->set('request_id', 'abc123_1');
|
||||
$this->requestStack->push($request1);
|
||||
|
||||
$service1 = new ErrorCodeService($this->requestStack);
|
||||
$result1 = $service1->getErrorCode();
|
||||
|
||||
$this->requestStack->pop();
|
||||
|
||||
$request2 = new Request();
|
||||
$request2->attributes->set('request_id', 'abc123_2');
|
||||
$this->requestStack->push($request2);
|
||||
|
||||
$service2 = new ErrorCodeService($this->requestStack);
|
||||
$result2 = $service2->getErrorCode();
|
||||
|
||||
$this->assertSame($result1, $result2);
|
||||
}
|
||||
|
||||
public function testSequenceSuffixMatchesBaseId(): void
|
||||
{
|
||||
$request1 = new Request();
|
||||
$request1->attributes->set('request_id', 'abc123');
|
||||
$this->requestStack->push($request1);
|
||||
|
||||
$service1 = new ErrorCodeService($this->requestStack);
|
||||
$result1 = $service1->getErrorCode();
|
||||
|
||||
$this->requestStack->pop();
|
||||
|
||||
$request2 = new Request();
|
||||
$request2->attributes->set('request_id', 'abc123_5');
|
||||
$this->requestStack->push($request2);
|
||||
|
||||
$service2 = new ErrorCodeService($this->requestStack);
|
||||
$result2 = $service2->getErrorCode();
|
||||
|
||||
$this->assertSame($result1, $result2);
|
||||
}
|
||||
|
||||
public function testHasErrorReturnsFalseByDefault(): void
|
||||
{
|
||||
$this->assertFalse($this->service->hasError());
|
||||
}
|
||||
|
||||
public function testMarkErrorOccurredSetsFlag(): void
|
||||
{
|
||||
$this->service->markErrorOccurred();
|
||||
|
||||
$this->assertTrue($this->service->hasError());
|
||||
}
|
||||
|
||||
public function testHasErrorRemainsTrueAfterMultipleCalls(): void
|
||||
{
|
||||
$this->service->markErrorOccurred();
|
||||
$this->service->markErrorOccurred();
|
||||
|
||||
$this->assertTrue($this->service->hasError());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user