Skip to content

Improve test suite #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: CI

on: [push]

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
php: [8.3, 8.2, 8.1]
laravel: [11.*, 10.*]
stability: [prefer-lowest, prefer-stable]
include:
- laravel: 11.*
testbench: 9.*
- laravel: 10.*
testbench: 8.*
exclude:
- laravel: 11.*
php: 8.1

name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo
coverage: xdebug

- name: Install dependencies
run: |
composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update
composer update --${{ matrix.stability }} --prefer-dist --no-interaction

- name: Execute tests
run: |
vendor/bin/pest
10 changes: 5 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@
],
"require": {
"php": "^8.1",
"guzzlehttp/guzzle": "^7.6",
"illuminate/http": "^10.0|^11.0",
"illuminate/http": "^10.32|^11.0",
"illuminate/support": "^10.0|^11.0",
"monolog/monolog": "^3.0"
},
Expand All @@ -39,8 +38,9 @@
"pestphp/pest": "^2.33",
"pestphp/pest-plugin-arch": "^2.0",
"pestphp/pest-plugin-laravel": "^2.0",
"saloonphp/laravel-http-sender": "^2.0",
"saloonphp/laravel-plugin": "^3.0"
"saloonphp/laravel-http-sender": "^2.0|^3.0",
"saloonphp/laravel-plugin": "^3.0",
"spatie/invade": "^2.0"
},
"suggest": {
"saloonphp/laravel-plugin": "To support logging of Saloon events (^3.0)"
Expand Down Expand Up @@ -75,4 +75,4 @@
},
"minimum-stability": "stable",
"prefer-stable": true
}
}
5 changes: 3 additions & 2 deletions src/Mixins/PendingRequestMixin.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ public function log()
if (! is_null($name)) {
$logger = $logger->withName($name);
}
foreach ($messageFormats as $format) {
foreach ($messageFormats as $key => $format) {
// We'll use unshift instead of push, to add the middleware to the bottom of the stack, not the top
$stack->unshift(
Middleware::log($logger, new MessageFormatter($format))
Middleware::log($logger, new MessageFormatter($format)),
'http-client-global-logger-'.$key
);
}

Expand Down
47 changes: 0 additions & 47 deletions src/Providers/EventServiceProvider.php

This file was deleted.

22 changes: 20 additions & 2 deletions src/Providers/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@

namespace Onlime\LaravelHttpClientGlobalLogger\Providers;

use Illuminate\Http\Client\Events\RequestSending;
use Illuminate\Http\Client\Events\ResponseReceived;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\ServiceProvider as BaseServiceProvider;
use Monolog\Handler\StreamHandler;
use Onlime\LaravelHttpClientGlobalLogger\Listeners\LogRequestSending;
use Onlime\LaravelHttpClientGlobalLogger\Listeners\LogResponseReceived;
use Onlime\LaravelHttpClientGlobalLogger\Mixins\PendingRequestMixin;
use Saloon\Laravel\Events\SendingSaloonRequest;
use Saloon\Laravel\Events\SentSaloonRequest;

class ServiceProvider extends BaseServiceProvider
{
Expand All @@ -18,15 +25,26 @@ public function register()

if (config('http-client-global-logger.enabled') &&
! config('http-client-global-logger.mixin')) {
$this->app->register(EventServiceProvider::class);
$this->registerEventListeners();
}
}

private function registerEventListeners(): void
{
// Laravel HTTP Client
Event::listen(RequestSending::class, LogRequestSending::class);
Event::listen(ResponseReceived::class, LogResponseReceived::class);

// Saloon
Event::listen(SendingSaloonRequest::class, LogRequestSending::class);
Event::listen(SentSaloonRequest::class, LogResponseReceived::class);
}

public function boot()
{
$this->publishes([
$this->configFileLocation() => config_path('http-client-global-logger.php'),
], 'config');
], 'http-client-global-logger');

$channel = config('http-client-global-logger.channel');
if (! array_key_exists($channel, config('logging.channels'))) {
Expand Down
113 changes: 113 additions & 0 deletions tests/EventHelperTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php

use GuzzleHttp\Psr7\Request as Psr7Request;
use GuzzleHttp\Psr7\Response as Psr7Response;
use Illuminate\Http\Client\Events\RequestSending;
use Illuminate\Http\Client\Events\ResponseReceived;
use Illuminate\Http\Client\Request as ClientRequest;
use Illuminate\Http\Client\Response as ClientResponse;
use Onlime\LaravelHttpClientGlobalLogger\EventHelper;
use Saloon\Enums\Method;
use Saloon\Http\Connector;
use Saloon\Http\PendingRequest;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Laravel\Events\SendingSaloonRequest;
use Saloon\Laravel\Events\SentSaloonRequest;

function psr7Request(): Psr7Request
{
return new Psr7Request('GET', 'http://localhost/test');
}

function psr7Response(): Psr7Response
{
return new Psr7Response(200, ['X-Foo' => 'Bar']);
}

function laravelHttpRequest(): ClientRequest
{
return new ClientRequest(psr7Request());
}

function laravelHttpResponse(): ClientResponse
{
return new ClientResponse(psr7Response());
}

it('resolves the psr request from Laravel\'s RequestSending event', function () {
$psrRequest = EventHelper::getPsrRequest(new RequestSending(laravelHttpRequest()));

expect($psrRequest)->toBeInstanceOf(Psr7Request::class)
->and($psrRequest->getMethod())->toBe('GET')
->and($psrRequest->getUri()->__toString())->toBe('http://localhost/test');
});

it('resolves the psr request from Laravel\'s ResponseReceived event', function () {
$psrRequest = EventHelper::getPsrRequest(new ResponseReceived(laravelHttpRequest(), laravelHttpResponse()));

expect($psrRequest)->toBeInstanceOf(Psr7Request::class)
->and($psrRequest->getMethod())->toBe('GET')
->and($psrRequest->getUri()->__toString())->toBe('http://localhost/test');
});

it('resolves the psr response from Laravel\'s ResponseReceived event', function () {
$psrResponse = EventHelper::getPsrResponse(new ResponseReceived(laravelHttpRequest(), laravelHttpResponse()));

expect($psrResponse)->toBeInstanceOf(Psr7Response::class)
->and($psrResponse->getStatusCode())->toBe(200)
->and($psrResponse->getHeaderLine('X-Foo'))->toBe('Bar');
});

function saloonPendingRequest(): PendingRequest
{
return new PendingRequest(
new class extends Connector
{
public function resolveBaseUrl(): string
{
return 'http://localhost';
}
},
new class extends Request
{
protected Method $method = Method::GET;

public function resolveEndpoint(): string
{
return '/test';
}
}
);
}

function saloonResponse(PendingRequest $pendingRequest): Response
{
return new Response(psr7Response(), $pendingRequest, $pendingRequest->createPsrRequest());
}

it('resolves the psr request from Saloon\'s SendingSaloonRequest event', function () {
$psrRequest = EventHelper::getPsrRequest(new SendingSaloonRequest(saloonPendingRequest()));

expect($psrRequest)->toBeInstanceOf(Psr7Request::class)
->and($psrRequest->getMethod())->toBe('GET')
->and($psrRequest->getUri()->__toString())->toBe('http://localhost/test');
});

it('resolves the psr request from Saloon\'s SentSaloonRequest event', function () {
$pendingRequest = saloonPendingRequest();
$psrRequest = EventHelper::getPsrRequest(new SentSaloonRequest($pendingRequest, saloonResponse($pendingRequest)));

expect($psrRequest)->toBeInstanceOf(Psr7Request::class)
->and($psrRequest->getMethod())->toBe('GET')
->and($psrRequest->getUri()->__toString())->toBe('http://localhost/test');
});

it('resolves the psr response from Saloon\'s SentSaloonRequest event', function () {
$pendingRequest = saloonPendingRequest();
$psrResponse = EventHelper::getPsrResponse(new SentSaloonRequest($pendingRequest, saloonResponse($pendingRequest)));

expect($psrResponse)->toBeInstanceOf(Psr7Response::class)
->and($psrResponse->getStatusCode())->toBe(200)
->and($psrResponse->getHeaderLine('X-Foo'))->toBe('Bar');
});
23 changes: 23 additions & 0 deletions tests/PendingRequestMixinTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

use GuzzleHttp\HandlerStack;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Http;
use Onlime\LaravelHttpClientGlobalLogger\Mixins\PendingRequestMixin;

it('rebuilds the guzzle handler stack to include the logger middleware at the bottom of the stack', function () {
PendingRequest::mixin(new PendingRequestMixin);

$pendingRequest = Http::withHeaders(['X-Test' => 'true'])->log();

/** @var HandlerStack $handler */
$handler = $pendingRequest->getOptions()['handler'];

// We need to invade the HandlerStack to access the stack property or findByName method
expect($handler)->toBeInstanceOf(HandlerStack::class)
->and(invade($handler)->findByName('http-client-global-logger-0'))->toBeInt()
->and(invade($handler)->findByName('http-client-global-logger-1'))->toBeInt()
->and(fn () => invade($handler)->findByName('http-client-global-logger-2'))
->toThrow(\InvalidArgumentException::class);
});
79 changes: 79 additions & 0 deletions tests/ServiceProviderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

use Illuminate\Http\Client\Events\RequestSending;
use Illuminate\Http\Client\Events\ResponseReceived;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Facades\Event;
use Onlime\LaravelHttpClientGlobalLogger\Listeners\LogRequestSending;
use Onlime\LaravelHttpClientGlobalLogger\Listeners\LogResponseReceived;
use Onlime\LaravelHttpClientGlobalLogger\Providers\ServiceProvider;
use Saloon\Laravel\Events\SendingSaloonRequest;
use Saloon\Laravel\Events\SentSaloonRequest;

it('registers event listeners', function (string $eventName, string $listenerName) {
config([
'http-client-global-logger.enabled' => true,
'http-client-global-logger.mixin' => false,
]);

(new ServiceProvider(app()))->register();

$listeners = Event::getRawListeners()[$eventName] ?? [];

expect($listeners)->not->toBeEmpty()
->and($listeners)->toContain($listenerName);
})->with([
[RequestSending::class, LogRequestSending::class],
[ResponseReceived::class, LogResponseReceived::class],
[SendingSaloonRequest::class, LogRequestSending::class],
[SentSaloonRequest::class, LogResponseReceived::class],
]);

it('merges the default config', function () {
$config = config('http-client-global-logger');

expect($config)->toBeArray();

foreach ([
'enabled',
'mixin',
'channel',
'logfile',
'format',
'obfuscate',
'trim_response_body',
] as $key) {
expect($config)->toHaveKey($key);
}
});

it('can publish the config file', function () {
@unlink(config_path('http-client-global-logger.php'));

$this->artisan('vendor:publish', ['--tag' => 'http-client-global-logger']);

$this->assertFileExists(config_path('http-client-global-logger.php'));
});

it('configures the log channel', function () {
$defaultChannel = config('http-client-global-logger.channel');

$config = config('logging.channels.'.$defaultChannel);

expect($config)->toBeArray();
});

it('can register the mixin on the PendingRequest class', function (bool $mixin) {
PendingRequest::flushMacros();

config([
'http-client-global-logger.mixin' => $mixin,
]);

(new ServiceProvider(app()))->boot();

expect(PendingRequest::hasMacro('log'))->toBe($mixin);
})->with([
true,
false,
]);