First init
This commit is contained in:
83
tests/Fakes/FakeLoghandlerClient.php
Normal file
83
tests/Fakes/FakeLoghandlerClient.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace HerrleinIT\LogHandler\Tests\Fakes;
|
||||
|
||||
use BadMethodCallException;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Promise\FulfilledPromise;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Throwable;
|
||||
|
||||
class FakeLoghandlerClient implements ClientInterface
|
||||
{
|
||||
/** @var array<int, array{method:string,uri:string,options:array}> */
|
||||
public array $requests = [];
|
||||
|
||||
/**
|
||||
* @param array<int, ResponseInterface|Throwable|callable> $queue
|
||||
*/
|
||||
public function __construct(private array $queue = []) {}
|
||||
|
||||
public function request(string $method, $uri, array $options = []): ResponseInterface
|
||||
{
|
||||
$this->requests[] = [
|
||||
'method' => strtoupper($method),
|
||||
'uri' => (string) $uri,
|
||||
'options' => $options,
|
||||
];
|
||||
|
||||
if ($this->queue !== []) {
|
||||
$next = array_shift($this->queue);
|
||||
|
||||
if ($next instanceof Throwable) {
|
||||
throw $next;
|
||||
}
|
||||
|
||||
if (is_callable($next)) {
|
||||
$result = $next($this, $method, $uri, $options);
|
||||
|
||||
if ($result instanceof ResponseInterface) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if ($next instanceof ResponseInterface) {
|
||||
return $next;
|
||||
}
|
||||
}
|
||||
|
||||
return new Response(200);
|
||||
}
|
||||
|
||||
public function requestAsync($method, $uri, array $options = []): PromiseInterface
|
||||
{
|
||||
return new FulfilledPromise($this->request($method, $uri, $options));
|
||||
}
|
||||
|
||||
public function send(RequestInterface $request, array $options = []): ResponseInterface
|
||||
{
|
||||
return $this->request($request->getMethod(), $request->getUri(), $options + ['request' => $request]);
|
||||
}
|
||||
|
||||
public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface
|
||||
{
|
||||
return $this->requestAsync($request->getMethod(), $request->getUri(), $options + ['request' => $request]);
|
||||
}
|
||||
|
||||
public function getConfig(?string $option = null): mixed
|
||||
{
|
||||
if ($option !== null) {
|
||||
throw new BadMethodCallException('Fake client does not expose configurable options.');
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function append(ResponseInterface|Throwable|callable $next): void
|
||||
{
|
||||
$this->queue[] = $next;
|
||||
}
|
||||
}
|
||||
104
tests/Feature/LogForwardingTest.php
Normal file
104
tests/Feature/LogForwardingTest.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace HerrleinIT\LogHandler\Tests\Feature;
|
||||
|
||||
use ErrorException;
|
||||
use HerrleinIT\LogHandler\Handlers\LogForwardingHandler;
|
||||
use HerrleinIT\LogHandler\LogForwarder;
|
||||
use HerrleinIT\LogHandler\Tests\Fakes\FakeLoghandlerClient;
|
||||
use HerrleinIT\LogHandler\Tests\TestCase;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Testing\Fluent\AssertableJson;
|
||||
|
||||
class LogForwardingTest extends TestCase
|
||||
{
|
||||
public function test_exception_payload_is_forwarded(): void
|
||||
{
|
||||
$client = new FakeLoghandlerClient();
|
||||
$this->app->instance(LogForwarder::class, new LogForwarder($this->app['config'], $client));
|
||||
|
||||
$exception = new ErrorException('Testerror', 0, E_WARNING, '/var/test/testfile.php', 1337);
|
||||
|
||||
$channel = Log::channel('loghandler');
|
||||
|
||||
$this->assertContains(
|
||||
LogForwardingHandler::class,
|
||||
array_map(fn ($handler) => $handler::class, $channel->getLogger()->getHandlers())
|
||||
);
|
||||
|
||||
$channel->warning('Ignored message', ['exception' => $exception]);
|
||||
|
||||
$this->assertCount(1, $client->requests);
|
||||
|
||||
$request = $client->requests[0];
|
||||
$this->assertSame('POST', $request['method']);
|
||||
$this->assertSame('http://test.example/api/error/create', $request['uri']);
|
||||
$this->assertSame('Bearer test-token', $request['options']['headers']['Authorization']);
|
||||
|
||||
AssertableJson::fromArray($request['options']['json'])
|
||||
->where('source', config('loghandler.source'))
|
||||
->where('error', 'Testerror')
|
||||
->where('type', 'E_WARNING')
|
||||
->where('file', '/var/test/testfile.php')
|
||||
->where('line', '1337')
|
||||
->where('trace', fn ($trace) => is_string($trace) && $trace !== '')
|
||||
->etc();
|
||||
}
|
||||
|
||||
public function test_disabled_handler_skips_forwarding(): void
|
||||
{
|
||||
$client = new FakeLoghandlerClient();
|
||||
config()->set('loghandler.enabled', false);
|
||||
|
||||
$this->app->instance(LogForwarder::class, new LogForwarder($this->app['config'], $client));
|
||||
|
||||
Log::channel('loghandler')->error('Testerror');
|
||||
|
||||
$this->assertCount(0, $client->requests);
|
||||
}
|
||||
|
||||
public function test_missing_token_skips_forwarding(): void
|
||||
{
|
||||
$client = new FakeLoghandlerClient();
|
||||
config()->set('loghandler.token', '');
|
||||
|
||||
$this->app->instance(LogForwarder::class, new LogForwarder($this->app['config'], $client));
|
||||
|
||||
Log::channel('loghandler')->error('Testerror');
|
||||
|
||||
$this->assertCount(0, $client->requests);
|
||||
}
|
||||
|
||||
public function test_stack_channel_includes_handler(): void
|
||||
{
|
||||
$client = new FakeLoghandlerClient();
|
||||
$this->app->instance(LogForwarder::class, new LogForwarder($this->app['config'], $client));
|
||||
|
||||
$stack = Log::channel('stack');
|
||||
|
||||
$this->assertContains(
|
||||
LogForwardingHandler::class,
|
||||
array_map(fn ($handler) => $handler::class, $stack->getHandlers())
|
||||
);
|
||||
|
||||
$stack->error('Stack error', [
|
||||
'file' => '/var/test/testfile.php',
|
||||
'line' => 99,
|
||||
]);
|
||||
|
||||
$this->assertCount(1, $client->requests);
|
||||
|
||||
$request = $client->requests[0];
|
||||
$this->assertSame('POST', $request['method']);
|
||||
$this->assertSame('http://test.example/api/error/create', $request['uri']);
|
||||
|
||||
AssertableJson::fromArray($request['options']['json'])
|
||||
->where('source', config('loghandler.source'))
|
||||
->where('error', 'Stack error')
|
||||
->where('type', 'E_ERROR')
|
||||
->where('file', '/var/test/testfile.php')
|
||||
->where('line', '99')
|
||||
->where('trace', '')
|
||||
->etc();
|
||||
}
|
||||
}
|
||||
53
tests/TestCase.php
Normal file
53
tests/TestCase.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace HerrleinIT\LogHandler\Tests;
|
||||
|
||||
use HerrleinIT\LogHandler\LogHandlerServiceProvider;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Orchestra\Testbench\TestCase as Orchestra;
|
||||
|
||||
abstract class TestCase extends Orchestra
|
||||
{
|
||||
protected function getPackageProviders($app): array
|
||||
{
|
||||
return [LogHandlerServiceProvider::class];
|
||||
}
|
||||
|
||||
protected function defineEnvironment($app): void
|
||||
{
|
||||
$app['config']->set('logging.default', 'stack');
|
||||
$app['config']->set('logging.channels.loghandler', [
|
||||
'driver' => 'loghandler',
|
||||
'level' => 'debug',
|
||||
'bubble' => true,
|
||||
]);
|
||||
$app['config']->set('logging.channels.single', [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => 'debug',
|
||||
'replace_placeholders' => true,
|
||||
]);
|
||||
$app['config']->set('logging.channels.stack', [
|
||||
'driver' => 'stack',
|
||||
'channels' => ['single', 'loghandler'],
|
||||
'ignore_exceptions' => false,
|
||||
]);
|
||||
|
||||
$app['config']->set('loghandler', [
|
||||
'endpoint' => 'http://test.example/api/error/create',
|
||||
'token' => 'test-token',
|
||||
'source' => 'Project Name',
|
||||
'enabled' => true,
|
||||
'timeout_ms' => 3000,
|
||||
'retry_times' => 0,
|
||||
'include_trace' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
Log::forgetChannel('loghandler');
|
||||
Log::forgetChannel('stack');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user