chore: add deployment configurations and tests for logger and dispatcher
All checks were successful
🧪✨ Tests Workflow / 🛡️ 🔒 License Check (push) Successful in 2m56s
🧪✨ Tests Workflow / 🛡️ 🔒 Library Audit (push) Successful in 3m6s
🧪✨ Tests Workflow / 🧪 ✨ Database Migrations (push) Successful in 3m15s
🧪✨ Tests Workflow / 📝 ✨ Code Lint (push) Successful in 2m58s
🧪✨ Tests Workflow / 🐙 🔍 Code Sniffer (push) Successful in 2m59s
🧪✨ Tests Workflow / 🧪 ✅ Unit Tests (push) Successful in 1m49s

This commit is contained in:
2025-11-13 14:09:27 -05:00
parent 5542ad1e75
commit 1e446b8b36
12 changed files with 477 additions and 11 deletions

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace Siteworxpro\Tests\Facades;
use Siteworxpro\App\Services\Facades\Dispatcher;
class DispatcherTest extends AbstractFacade
{
protected function getFacadeClass(): string
{
return Dispatcher::class;
}
protected function getConcrete(): string
{
return \Siteworxpro\App\Events\Dispatcher::class;
}
}

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace Siteworxpro\Tests\Facades;
use Siteworxpro\App\Services\Facades\Logger;
class LoggerTest extends AbstractFacade
{
protected function getFacadeClass(): string
{
return Logger::class;
}
protected function getConcrete(): string
{
return \Siteworxpro\App\Log\Logger::class;
}
}

View File

@@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace Siteworxpro\Tests\Helpers;
use Siteworxpro\App\Helpers\Env;
use Siteworxpro\App\Helpers\Ulid;
use Siteworxpro\Tests\Unit;
class UlidTest extends Unit
{
public function testGetString(): void
{
$ulid = Ulid::generate();
$this->assertIsString($ulid);
$this->assertEquals(16, strlen($ulid));
}
}

167
tests/Log/LoggerRpcTest.php Normal file
View File

@@ -0,0 +1,167 @@
<?php
declare(strict_types=1);
namespace Siteworxpro\Tests\Log;
use Mockery;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Siteworxpro\App\Log\Logger;
use Siteworxpro\Tests\Unit;
class LoggerRpcTest extends Unit
{
protected function tearDown(): void
{
parent::tearDown();
unset($_SERVER['RR_RPC']);
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws \Throwable
*/
public function testLogsDebugMessageWhenLevelIsDebug(): void
{
$this->expectNotToPerformAssertions();
$_SERVER['RR_RPC'] = 'tcp://127.0.0.1:6001';
$mock = Mockery::mock(LoggerInterface::class);
$mock->expects('debug')
->with('message', ['key' => 'value'])
->once();
\Siteworxpro\App\Services\Facades\Logger::getFacadeContainer()
->bind(\RoadRunner\Logger\Logger::class, function () use ($mock) {
return $mock;
});
$inputBuffer = fopen('php://memory', 'r+');
$logger = new Logger(LogLevel::DEBUG, $inputBuffer);
$logger->debug('message', ['key' => 'value']);
$mock->shouldHaveReceived('debug');
Mockery::close();
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function testLogsDebugMessageWhenLevelIsInfoNotice(): void
{
$this->expectNotToPerformAssertions();
$_SERVER['RR_RPC'] = 'tcp://127.0.0.1:6001';
$mock = Mockery::mock(LoggerInterface::class);
$mock->expects('info')
->with('message', ['key' => 'value'])
->times(2);
\Siteworxpro\App\Services\Facades\Logger::getFacadeContainer()
->bind(\RoadRunner\Logger\Logger::class, function () use ($mock) {
return $mock;
});
$inputBuffer = fopen('php://memory', 'r+');
$logger = new Logger(LogLevel::DEBUG, $inputBuffer);
$logger->info('message', ['key' => 'value']);
$logger->notice('message', ['key' => 'value']);
$mock->shouldHaveReceived('info')->times(2);
Mockery::close();
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function testLogsDebugMessageWhenLevelIsInfoWarning(): void
{
$this->expectNotToPerformAssertions();
$_SERVER['RR_RPC'] = 'tcp://127.0.0.1:6001';
$mock = Mockery::mock(LoggerInterface::class);
$mock->expects('warning')
->with('message', ['key' => 'value'])
->times(1);
\Siteworxpro\App\Services\Facades\Logger::getFacadeContainer()
->bind(\RoadRunner\Logger\Logger::class, function () use ($mock) {
return $mock;
});
$inputBuffer = fopen('php://memory', 'r+');
$logger = new Logger(LogLevel::DEBUG, $inputBuffer);
$logger->warning('message', ['key' => 'value']);
$mock->shouldHaveReceived('warning');
Mockery::close();
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function testLogsDebugMessageWhenLevelIsInfoError(): void
{
$this->expectNotToPerformAssertions();
$_SERVER['RR_RPC'] = 'tcp://127.0.0.1:6001';
$mock = Mockery::mock(LoggerInterface::class);
$mock->expects('error')
->with('message', ['key' => 'value'])
->times(4);
\Siteworxpro\App\Services\Facades\Logger::getFacadeContainer()
->bind(\RoadRunner\Logger\Logger::class, function () use ($mock) {
return $mock;
});
$inputBuffer = fopen('php://memory', 'r+');
$logger = new Logger(LogLevel::DEBUG, $inputBuffer);
$logger->error('message', ['key' => 'value']);
$logger->critical('message', ['key' => 'value']);
$logger->alert('message', ['key' => 'value']);
$logger->emergency('message', ['key' => 'value']);
$mock->shouldHaveReceived('error')->times(4);
Mockery::close();
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function testLogsLog(): void
{
$this->expectNotToPerformAssertions();
$_SERVER['RR_RPC'] = 'tcp://127.0.0.1:6001';
$mock = Mockery::mock(LoggerInterface::class);
$mock->expects('log')
->with('notaloglevel', 'message', ['key' => 'value']);
\Siteworxpro\App\Services\Facades\Logger::getFacadeContainer()
->bind(\RoadRunner\Logger\Logger::class, function () use ($mock) {
return $mock;
});
$inputBuffer = fopen('php://memory', 'r+');
$logger = new Logger(LogLevel::DEBUG, $inputBuffer);
$logger->log('notaloglevel', 'message', ['key' => 'value']);
$mock->shouldHaveReceived('log')->times(1);
Mockery::close();
}
}

155
tests/Log/LoggerTest.php Normal file
View File

@@ -0,0 +1,155 @@
<?php
declare(strict_types=1);
namespace Siteworxpro\Tests\Log;
use Psr\Log\LogLevel;
use Siteworxpro\App\Log\Logger;
use Siteworxpro\Tests\Unit;
class LoggerTest extends Unit
{
private function getLoggerWithBuffer(string $logLevel): array
{
$inputBuffer = fopen('php://memory', 'r+');
return [new Logger($logLevel, $inputBuffer), $inputBuffer];
}
private function getContents($inputBuffer): string
{
return stream_get_contents($inputBuffer, -1, 0);
}
private function testLogLevel(string $level): void
{
[$logger, $inputBuffer] = $this->getLoggerWithBuffer($level);
$logger->$level('message', ['key' => 'value']);
$output = $this->getContents($inputBuffer);
$this->assertNotEmpty($output);
$decoded = json_decode($output, true);
$this->assertEquals('message', $decoded['message']);
$this->assertEquals('value', $decoded['context']['key']);
}
private function testLogLevelEmpty(string $configLevel, string $logLevel): void
{
[$logger, $inputBuffer] = $this->getLoggerWithBuffer($configLevel);
$logger->$logLevel('message', ['key' => 'value']);
$output = $this->getContents($inputBuffer);
$this->assertEmpty($output);
}
public function testLogsDebugMessageWhenLevelIsDebug(): void
{
$this->testLogLevel(LogLevel::DEBUG);
}
public function testLogsInfoMessageWhenLevelIsInfo(): void
{
$this->testLogLevel(LogLevel::INFO);
}
public function testLogsWarningMessageWhenLevelIsWarning(): void
{
$this->testLogLevel(LogLevel::WARNING);
}
public function testLogsErrorMessageWhenLevelIsError(): void
{
$this->testLogLevel(LogLevel::ERROR);
}
public function testLogsCriticalMessageWhenLevelIsCritical(): void
{
$this->testLogLevel(LogLevel::CRITICAL);
}
public function testLogsAlertMessageWhenLevelIsAlert(): void
{
$this->testLogLevel(LogLevel::ALERT);
}
public function testLogsEmergencyMessageWhenLevelIsEmergency(): void
{
$this->testLogLevel(LogLevel::EMERGENCY);
}
public function testLogsNoticeMessageWhenLevelIsNotice(): void
{
$this->testLogLevel(LogLevel::NOTICE);
}
public function testDoesNotLogWhenMinimumLevelIsInfo(): void
{
$this->testLogLevelEmpty(LogLevel::INFO, LogLevel::DEBUG);
}
public function testDoesNotLogWhenMinimumLevelIsWarning(): void
{
$this->testLogLevelEmpty(LogLevel::WARNING, LogLevel::INFO);
$this->testLogLevelEmpty(LogLevel::WARNING, LogLevel::DEBUG);
}
public function testDoesNotLogWhenMinimumLevelIsError(): void
{
$this->testLogLevelEmpty(LogLevel::ERROR, LogLevel::DEBUG);
$this->testLogLevelEmpty(LogLevel::ERROR, LogLevel::INFO);
$this->testLogLevelEmpty(LogLevel::ERROR, LogLevel::WARNING);
}
public function testDoesNotLogWhenMinimumLevelIsNotice(): void
{
$this->testLogLevelEmpty(LogLevel::NOTICE, LogLevel::DEBUG);
$this->testLogLevelEmpty(LogLevel::NOTICE, LogLevel::INFO);
}
public function testLogsMessageWithEmptyContext(): void
{
[$logger, $buffer] = $this->getLoggerWithBuffer(LogLevel::INFO);
$logger->info('Message without context');
$output = $this->getContents($buffer);
$this->assertNotEmpty($output);
$decoded = json_decode($output, true);
$this->assertEquals('Message without context', $decoded['message']);
}
public function testLogsMessageWithComplexContext(): void
{
[$logger, $buffer] = $this->getLoggerWithBuffer(LogLevel::INFO);
$logger->info('Complex context', [
'user_id' => 123,
'nested' => ['key' => 'value'],
'array' => [1, 2, 3]
]);
$output = $this->getContents($buffer);
$this->assertNotEmpty($output);
$decoded = json_decode($output, true);
$this->assertEquals(123, $decoded['context']['user_id']);
$this->assertEquals('value', $decoded['context']['nested']['key']);
}
public function testLogsStringableMessage(): void
{
[$logger, $buffer] = $this->getLoggerWithBuffer(LogLevel::INFO);
$stringable = new class implements \Stringable {
public function __toString(): string
{
return 'Stringable message';
}
};
$logger->info($stringable);
$output = $this->getContents($buffer);
$this->assertNotEmpty($output);
$decoded = json_decode($output, true);
$this->assertEquals('Stringable message', $decoded['message']);
}
}