This commit is contained in:
Marcel Pociot
2020-04-29 16:49:33 +02:00
parent c2084e6be6
commit 6cf206e0a2
35 changed files with 566 additions and 215 deletions

View File

@@ -2,14 +2,16 @@
namespace App\Client;
use App\Client\Http\Controllers\PushLogsToDashboardController;
use App\Client\Http\HttpClient;
use App\HttpServer\App;
use App\HttpServer\Controllers\AttachDataToLogController;
use App\HttpServer\Controllers\ClearLogsController;
use App\HttpServer\Controllers\DashboardController;
use App\HttpServer\Controllers\LogController;
use App\HttpServer\Controllers\ReplayLogController;
use App\HttpServer\Controllers\StoreLogController;
use App\Http\App;
use App\Client\Http\Controllers\AttachDataToLogController;
use App\Client\Http\Controllers\ClearLogsController;
use App\Client\Http\Controllers\DashboardController;
use App\Client\Http\Controllers\LogController;
use App\Client\Http\Controllers\ReplayLogController;
use App\Http\Controllers\StoreLogController;
use App\Http\RouteGenerator;
use App\WebSockets\Socket;
use Ratchet\WebSocket\WsServer;
use React\EventLoop\LoopInterface;
@@ -33,9 +35,13 @@ class Factory
/** @var App */
protected $app;
/** @var RouteGenerator */
protected $router;
public function __construct()
{
$this->loop = LoopFactory::create();
$this->router = new RouteGenerator();
}
public function setHost(string $host)
@@ -93,21 +99,18 @@ class Factory
protected function addRoutes()
{
$dashboardRoute = new Route('/', ['_controller' => app(DashboardController::class)], [], [], null, [], ['GET']);
$logRoute = new Route('/logs', ['_controller' => app(LogController::class)], [], [], null, [], ['GET']);
$storeLogRoute = new Route('/logs', ['_controller' => app(StoreLogController::class)], [], [], null, [], ['POST']);
$replayLogRoute = new Route('/replay/{log}', ['_controller' => app(ReplayLogController::class)], [], [], null, [], ['GET']);
$attachLogDataRoute = new Route('/logs/{request_id}/data', ['_controller' => app(AttachDataToLogController::class)], [], [], null, [], ['POST']);
$clearLogsRoute = new Route('/logs/clear', ['_controller' => app(ClearLogsController::class)], [], [], null, [], ['GET']);
$this->router->get('/', DashboardController::class);
$this->router->get('/logs', LogController::class);
$this->router->post('/logs', PushLogsToDashboardController::class);
$this->router->get('/replay/{log}', ReplayLogController::class);
$this->router->post('/logs/{request_id}/data', AttachDataToLogController::class);
$this->router->post('/logs/clear', ClearLogsController::class);
$this->app->route('/socket', new WsServer(new Socket()), ['*']);
$this->app->routes->add('dashboard', $dashboardRoute);
$this->app->routes->add('logs', $logRoute);
$this->app->routes->add('storeLogs', $storeLogRoute);
$this->app->routes->add('replayLog', $replayLogRoute);
$this->app->routes->add('attachLogData', $attachLogDataRoute);
$this->app->routes->add('clearLogs', $clearLogsRoute);
foreach ($this->router->getRoutes()->all() as $name => $route) {
$this->app->routes->add($name, $route);
}
}
protected function detectNextFreeDashboardPort($port = 4040): int
@@ -138,6 +141,11 @@ class Factory
return $this;
}
public function getApp(): App
{
return $this->app;
}
public function run()
{
$this->loop->run();

View File

@@ -1,10 +1,13 @@
<?php
namespace App\HttpServer\Controllers;
namespace App\Client\Http\Controllers;
use App\Http\Controllers\PostController;
use GuzzleHttp\Psr7\Response;
use Illuminate\Http\Request;
use App\Logger\RequestLogger;
use Ratchet\ConnectionInterface;
use function GuzzleHttp\Psr7\str;
class AttachDataToLogController extends PostController
{
@@ -24,6 +27,11 @@ class AttachDataToLogController extends PostController
$loggedRequest->setAdditionalData((array)$request->get('data', []));
$this->requestLogger->pushLogs();
$httpConnection->send(str(new Response(200)));
return;
}
$httpConnection->send(str(new Response(404)));
}
}

View File

@@ -1,9 +1,10 @@
<?php
namespace App\HttpServer\Controllers;
namespace App\Client\Http\Controllers;
use App\Client\Http\HttpClient;
use App\HttpServer\QueryParameters;
use App\Http\Controllers\Controller;
use App\Http\QueryParameters;
use App\Logger\RequestLogger;
use GuzzleHttp\Psr7\Response;
use Ratchet\ConnectionInterface;

View File

@@ -1,8 +1,9 @@
<?php
namespace App\HttpServer\Controllers;
namespace App\Client\Http\Controllers;
use App\Client\Client;
use App\Http\Controllers\Controller;
use GuzzleHttp\Psr7\Response;
use function GuzzleHttp\Psr7\str;
use Psr\Http\Message\RequestInterface;

View File

@@ -1,7 +1,8 @@
<?php
namespace App\HttpServer\Controllers;
namespace App\Client\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Logger\RequestLogger;
use GuzzleHttp\Psr7\Response;
use Ratchet\ConnectionInterface;

View File

@@ -1,7 +1,8 @@
<?php
namespace App\HttpServer\Controllers;
namespace App\Client\Http\Controllers;
use App\Http\Controllers\Controller;
use Exception;
use App\WebSockets\Socket;
use GuzzleHttp\Psr7\Response;
@@ -10,7 +11,7 @@ use Ratchet\ConnectionInterface;
use function GuzzleHttp\Psr7\str;
use Psr\Http\Message\RequestInterface;
class StoreLogController extends Controller
class PushLogsToDashboardController extends Controller
{
public function onOpen(ConnectionInterface $connection, RequestInterface $request = null)

View File

@@ -1,9 +1,10 @@
<?php
namespace App\HttpServer\Controllers;
namespace App\Client\Http\Controllers;
use App\Client\Http\HttpClient;
use App\HttpServer\QueryParameters;
use App\Http\Controllers\Controller;
use App\Http\QueryParameters;
use App\Logger\RequestLogger;
use GuzzleHttp\Psr7\Response;
use Ratchet\ConnectionInterface;
@@ -26,8 +27,21 @@ class ReplayLogController extends Controller
public function onOpen(ConnectionInterface $connection, RequestInterface $request = null)
{
/** @var RequestLogger $logger */
$requestData = $this->requestLogger->findLoggedRequest(QueryParameters::create($request)->get('log'))->getRequestData();
$loggedRequest = $this->requestLogger->findLoggedRequest(QueryParameters::create($request)->get('log'));
if (is_null($loggedRequest)) {
$connection->send(
str(new Response(
404,
['Content-Type' => 'application/json'],
))
);
$connection->close();
return;
}
$requestData = $loggedRequest->getRequestData();
/** @var HttpClient $tunnel */
$this->httpClient->performRequest($requestData);

View File

@@ -1,6 +1,6 @@
<?php
namespace App\HttpServer;
namespace App\Http;
use Ratchet\Http\Router;
use Ratchet\Server\IoServer;
@@ -12,12 +12,15 @@ use Symfony\Component\Routing\RouteCollection;
class App extends \Ratchet\App
{
/** @var Server */
protected $socket;
public function __construct($httpHost, $port, $address, LoopInterface $loop)
{
$this->httpHost = $httpHost;
$this->port = $port;
$socket = new Reactor($address.':'.$port, $loop);
$this->socket = new Reactor($address.':'.$port, $loop);
$this->routes = new RouteCollection;
@@ -25,8 +28,13 @@ class App extends \Ratchet\App
$router = new Router($urlMatcher);
$httpServer = new HttpServer($router);
$httpServer = new Server($router);
$this->_server = new IoServer($httpServer, $socket, $loop);
$this->_server = new IoServer($httpServer, $this->socket, $loop);
}
public function close()
{
$this->socket->close();
}
}

View File

@@ -1,6 +1,6 @@
<?php
namespace App\HttpServer\Controllers;
namespace App\Http\Controllers;
use Exception;
use Ratchet\ConnectionInterface;

View File

@@ -1,8 +1,8 @@
<?php
namespace App\HttpServer\Controllers;
namespace App\Http\Controllers;
use App\HttpServer\QueryParameters;
use App\Http\QueryParameters;
use GuzzleHttp\Psr7\ServerRequest;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;

View File

@@ -1,6 +1,6 @@
<?php
namespace App\HttpServer;
namespace App\Http;
use Psr\Http\Message\RequestInterface;

View File

@@ -1,6 +1,6 @@
<?php
namespace App\Server\Http;
namespace App\Http;
use Ratchet\WebSocket\MessageComponentInterface;
use Ratchet\WebSocket\WsServer;

View File

@@ -1,10 +1,10 @@
<?php
namespace App\HttpServer;
namespace App\Http;
use Ratchet\Http\HttpServerInterface;
class HttpServer extends \Ratchet\Http\HttpServer
class Server extends \Ratchet\Http\HttpServer
{
public function __construct(HttpServerInterface $component)
{

View File

@@ -32,7 +32,6 @@ class CliRequestLogger extends Logger
public function logRequest(LoggedRequest $loggedRequest)
{
return;
if ($this->requests->has($loggedRequest->id())) {
$this->requests[$loggedRequest->id()] = $loggedRequest;
} else {

View File

@@ -94,6 +94,11 @@ class LoggedRequest implements \JsonSerializable
$this->additionalData = array_merge($this->additionalData, $data);
}
public function getAdditionalData(): array
{
return $this->additionalData;
}
protected function isBinary(string $string): bool
{
return preg_match('~[^\x20-\x7E\t\r\n]~', $string) > 0;
@@ -122,26 +127,21 @@ class LoggedRequest implements \JsonSerializable
}
}
public function id()
public function id(): string
{
return $this->id;
}
public function getRequestData()
public function getRequestData(): ?string
{
return $this->rawRequest;
}
public function getResponse()
public function getResponse(): ?Response
{
return $this->parsedResponse;
}
protected function getResponseBody()
{
return \Laminas\Http\Response::fromString($this->rawResponse)->getBody();
}
protected function getPost()
{
$postData = [];

View File

@@ -19,6 +19,8 @@ class RequestLogger
/** @var CliRequestLogger */
protected $cliRequestLogger;
const MAX_LOGGED_REQUESTS = 10;
public function __construct(Browser $browser, CliRequestLogger $cliRequestLogger)
{
$this->client = $browser;
@@ -32,17 +34,19 @@ class RequestLogger
});
}
public function logRequest(string $rawRequest, Request $request)
public function logRequest(string $rawRequest, Request $request): LoggedRequest
{
$loggedRequest = new LoggedRequest($rawRequest, $request);
array_unshift($this->requests, $loggedRequest);
$this->requests = array_slice($this->requests, 0, 10);
$this->requests = array_slice($this->requests, 0, static::MAX_LOGGED_REQUESTS);
$this->cliRequestLogger->logRequest($loggedRequest);
$this->pushLogs();
return $loggedRequest;
}
public function logResponse(Request $request, string $rawResponse)
@@ -59,7 +63,7 @@ class RequestLogger
}
}
public function getData()
public function getData(): array
{
return $this->requests;
}
@@ -73,6 +77,7 @@ class RequestLogger
public function pushLogs()
{
// TODO: Make dashboard part configurable
$this
->client
->post(

View File

@@ -36,7 +36,7 @@ class AppServiceProvider extends ServiceProvider
$localConfigFile = getcwd() . DIRECTORY_SEPARATOR . '.expose.php';
if (file_exists($localConfigFile)) {
$localConfig = require_once $localConfigFile;
$localConfig = require $localConfigFile;
config()->set('expose', array_merge($builtInConfig, $localConfig));
return;
}
@@ -49,7 +49,7 @@ class AppServiceProvider extends ServiceProvider
]);
if (file_exists($configFile)) {
$globalConfig = require_once $configFile;
$globalConfig = require $configFile;
config()->set('expose', array_merge($builtInConfig, $globalConfig));
}
}

View File

@@ -4,7 +4,7 @@ namespace App\Server;
use App\Contracts\ConnectionManager as ConnectionManagerContract;
use App\Contracts\SubdomainGenerator;
use App\HttpServer\HttpServer;
use App\Http\Server as HttpServer;
use App\Server\Connections\ConnectionManager;
use App\Server\Http\Controllers\Admin\DeleteUsersController;
use App\Server\Http\Controllers\Admin\ListSitesController;
@@ -14,7 +14,7 @@ use App\Server\Http\Controllers\Admin\StoreUsersController;
use App\Server\Http\Controllers\Admin\VerifyLoginController;
use App\Server\Http\Controllers\ControlMessageController;
use App\Server\Http\Controllers\TunnelMessageController;
use App\Server\Http\RouteGenerator;
use App\Http\RouteGenerator;
use App\Server\Http\Router;
use App\Server\SubdomainGenerator\RandomSubdomainGenerator;
use Clue\React\SQLite\DatabaseInterface;

View File

@@ -2,7 +2,7 @@
namespace App\Server\Http\Controllers\Admin;
use App\HttpServer\Controllers\PostController;
use App\Http\Controllers\PostController;
use Clue\React\SQLite\DatabaseInterface;
use Clue\React\SQLite\Result;
use GuzzleHttp\Psr7\Response;

View File

@@ -3,7 +3,7 @@
namespace App\Server\Http\Controllers\Admin;
use App\Contracts\ConnectionManager;
use App\HttpServer\Controllers\PostController;
use App\Http\Controllers\PostController;
use App\Server\Configuration;
use Clue\React\SQLite\DatabaseInterface;
use Clue\React\SQLite\Result;

View File

@@ -2,7 +2,7 @@
namespace App\Server\Http\Controllers\Admin;
use App\HttpServer\Controllers\PostController;
use App\Http\Controllers\PostController;
use Clue\React\SQLite\DatabaseInterface;
use Clue\React\SQLite\Result;
use GuzzleHttp\Psr7\Response;

View File

@@ -3,7 +3,7 @@
namespace App\Server\Http\Controllers\Admin;
use App\Contracts\ConnectionManager;
use App\HttpServer\Controllers\PostController;
use App\Http\Controllers\PostController;
use Clue\React\SQLite\DatabaseInterface;
use Clue\React\SQLite\Result;
use GuzzleHttp\Psr7\Response;

View File

@@ -2,7 +2,7 @@
namespace App\Server\Http\Controllers\Admin;
use App\HttpServer\Controllers\PostController;
use App\Http\Controllers\PostController;
use Clue\React\SQLite\DatabaseInterface;
use Clue\React\SQLite\Result;
use GuzzleHttp\Psr7\Response;

View File

@@ -3,7 +3,7 @@
namespace App\Server\Http\Controllers\Admin;
use App\Contracts\ConnectionManager;
use App\HttpServer\Controllers\PostController;
use App\Http\Controllers\PostController;
use Clue\React\SQLite\DatabaseInterface;
use Clue\React\SQLite\Result;
use GuzzleHttp\Psr7\Response;

View File

@@ -3,7 +3,7 @@
namespace App\Server\Http\Controllers;
use App\Contracts\ConnectionManager;
use App\HttpServer\QueryParameters;
use App\Http\QueryParameters;
use Clue\React\SQLite\DatabaseInterface;
use Clue\React\SQLite\Result;
use Ratchet\WebSocket\MessageComponentInterface;

View File

@@ -3,7 +3,7 @@
namespace App\Server\Http\Controllers;
use App\Contracts\ConnectionManager;
use App\HttpServer\Controllers\PostController;
use App\Http\Controllers\PostController;
use App\Server\Configuration;
use App\Server\Connections\ControlConnection;
use GuzzleHttp\Psr7\Response;

View File

@@ -2,7 +2,7 @@
namespace App\Server\Http;
use App\HttpServer\QueryParameters;
use App\Http\QueryParameters;
use GuzzleHttp\Psr7\ServerRequest;
use Psr\Http\Message\RequestInterface;
use Ratchet\ConnectionInterface;

View File

@@ -31,7 +31,7 @@
"illuminate/validation": "^7.7",
"laminas/laminas-http": "^2.11",
"laravel-zero/framework": "^7.0",
"mockery/mockery": "^1.3.1",
"mockery/mockery": "^1.3",
"namshi/cuzzle": "^2.0",
"nyholm/psr7": "^1.2",
"phpunit/phpunit": "^8.5",

218
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "3199f5982eed399c719f72239be99a83",
"content-hash": "17ed4fb1b80fc6efe2594c3bfbbf3c7f",
"packages": [],
"packages-dev": [
{
@@ -1047,7 +1047,7 @@
},
{
"name": "illuminate/cache",
"version": "v7.7.1",
"version": "v7.9.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/cache.git",
@@ -1098,7 +1098,7 @@
},
{
"name": "illuminate/config",
"version": "v7.7.1",
"version": "v7.9.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/config.git",
@@ -1142,16 +1142,16 @@
},
{
"name": "illuminate/console",
"version": "v7.7.1",
"version": "v7.9.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/console.git",
"reference": "364648fc102ca0b3a7834934ed5885c11e285f29"
"reference": "3056c8d5069115c0bc86a5dc70b22710d427e259"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/console/zipball/364648fc102ca0b3a7834934ed5885c11e285f29",
"reference": "364648fc102ca0b3a7834934ed5885c11e285f29",
"url": "https://api.github.com/repos/illuminate/console/zipball/3056c8d5069115c0bc86a5dc70b22710d427e259",
"reference": "3056c8d5069115c0bc86a5dc70b22710d427e259",
"shasum": ""
},
"require": {
@@ -1192,20 +1192,20 @@
],
"description": "The Illuminate Console package.",
"homepage": "https://laravel.com",
"time": "2020-04-20T09:32:33+00:00"
"time": "2020-04-24T09:01:47+00:00"
},
{
"name": "illuminate/container",
"version": "v7.7.1",
"version": "v7.9.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/container.git",
"reference": "aa8dfe90a3eb31dc760adc911647be5d2e129c8a"
"reference": "78a134ab5bcf6e6e50321dfb0d602b698898698d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/container/zipball/aa8dfe90a3eb31dc760adc911647be5d2e129c8a",
"reference": "aa8dfe90a3eb31dc760adc911647be5d2e129c8a",
"url": "https://api.github.com/repos/illuminate/container/zipball/78a134ab5bcf6e6e50321dfb0d602b698898698d",
"reference": "78a134ab5bcf6e6e50321dfb0d602b698898698d",
"shasum": ""
},
"require": {
@@ -1236,20 +1236,20 @@
],
"description": "The Illuminate Container package.",
"homepage": "https://laravel.com",
"time": "2020-04-20T14:17:11+00:00"
"time": "2020-04-23T13:57:26+00:00"
},
{
"name": "illuminate/contracts",
"version": "v7.7.1",
"version": "v7.9.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/contracts.git",
"reference": "69a40779d8fc43e3f43da973b9c0c20bdbd81203"
"reference": "4f9cad4bd982e9f100b1f0a42677fdd3bbfa48fd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/contracts/zipball/69a40779d8fc43e3f43da973b9c0c20bdbd81203",
"reference": "69a40779d8fc43e3f43da973b9c0c20bdbd81203",
"url": "https://api.github.com/repos/illuminate/contracts/zipball/4f9cad4bd982e9f100b1f0a42677fdd3bbfa48fd",
"reference": "4f9cad4bd982e9f100b1f0a42677fdd3bbfa48fd",
"shasum": ""
},
"require": {
@@ -1280,11 +1280,11 @@
],
"description": "The Illuminate Contracts package.",
"homepage": "https://laravel.com",
"time": "2020-04-09T15:01:22+00:00"
"time": "2020-04-28T07:21:27+00:00"
},
{
"name": "illuminate/events",
"version": "v7.7.1",
"version": "v7.9.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/events.git",
@@ -1329,7 +1329,7 @@
},
{
"name": "illuminate/filesystem",
"version": "v7.7.1",
"version": "v7.9.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/filesystem.git",
@@ -1382,16 +1382,16 @@
},
{
"name": "illuminate/http",
"version": "v7.7.1",
"version": "v7.9.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/http.git",
"reference": "05444c7ecfad9e12c42d75f6b9a3dd0adb8b0a57"
"reference": "d9f6088b0296fa41c0a4afa6a2ec27a156d4917e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/http/zipball/05444c7ecfad9e12c42d75f6b9a3dd0adb8b0a57",
"reference": "05444c7ecfad9e12c42d75f6b9a3dd0adb8b0a57",
"url": "https://api.github.com/repos/illuminate/http/zipball/d9f6088b0296fa41c0a4afa6a2ec27a156d4917e",
"reference": "d9f6088b0296fa41c0a4afa6a2ec27a156d4917e",
"shasum": ""
},
"require": {
@@ -1430,11 +1430,11 @@
],
"description": "The Illuminate Http package.",
"homepage": "https://laravel.com",
"time": "2020-04-20T08:03:18+00:00"
"time": "2020-04-24T17:19:43+00:00"
},
{
"name": "illuminate/pipeline",
"version": "v7.7.1",
"version": "v7.9.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/pipeline.git",
@@ -1478,7 +1478,7 @@
},
{
"name": "illuminate/session",
"version": "v7.7.1",
"version": "v7.9.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/session.git",
@@ -1529,16 +1529,16 @@
},
{
"name": "illuminate/support",
"version": "v7.7.1",
"version": "v7.9.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/support.git",
"reference": "7143690b5b718a4a89f8a1ecda79833e75dd138c"
"reference": "677a3ad776db92b339a2926927929d0b070642ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/support/zipball/7143690b5b718a4a89f8a1ecda79833e75dd138c",
"reference": "7143690b5b718a4a89f8a1ecda79833e75dd138c",
"url": "https://api.github.com/repos/illuminate/support/zipball/677a3ad776db92b339a2926927929d0b070642ea",
"reference": "677a3ad776db92b339a2926927929d0b070642ea",
"shasum": ""
},
"require": {
@@ -1587,20 +1587,20 @@
],
"description": "The Illuminate Support package.",
"homepage": "https://laravel.com",
"time": "2020-04-21T15:58:25+00:00"
"time": "2020-04-28T07:20:41+00:00"
},
{
"name": "illuminate/testing",
"version": "v7.7.1",
"version": "v7.9.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/testing.git",
"reference": "5ec43e2778a5454b31b886f2ed4f4b2d291419fd"
"reference": "8594d186a6a6b9a584043b06d00099b2481f2018"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/testing/zipball/5ec43e2778a5454b31b886f2ed4f4b2d291419fd",
"reference": "5ec43e2778a5454b31b886f2ed4f4b2d291419fd",
"url": "https://api.github.com/repos/illuminate/testing/zipball/8594d186a6a6b9a584043b06d00099b2481f2018",
"reference": "8594d186a6a6b9a584043b06d00099b2481f2018",
"shasum": ""
},
"require": {
@@ -1638,11 +1638,11 @@
],
"description": "The Illuminate Testing package.",
"homepage": "https://laravel.com",
"time": "2020-04-16T17:12:54+00:00"
"time": "2020-04-27T14:32:07+00:00"
},
{
"name": "illuminate/translation",
"version": "v7.7.1",
"version": "v7.9.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/translation.git",
@@ -1688,16 +1688,16 @@
},
{
"name": "illuminate/validation",
"version": "v7.7.1",
"version": "v7.9.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/validation.git",
"reference": "99377aec3b5a2c2184d99de3dd7c8fb675e5a4ef"
"reference": "24cf7ff8e4a274a42eb86c94796dc01dec9e5760"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/validation/zipball/99377aec3b5a2c2184d99de3dd7c8fb675e5a4ef",
"reference": "99377aec3b5a2c2184d99de3dd7c8fb675e5a4ef",
"url": "https://api.github.com/repos/illuminate/validation/zipball/24cf7ff8e4a274a42eb86c94796dc01dec9e5760",
"reference": "24cf7ff8e4a274a42eb86c94796dc01dec9e5760",
"shasum": ""
},
"require": {
@@ -1737,7 +1737,7 @@
],
"description": "The Illuminate Validation package.",
"homepage": "https://laravel.com",
"time": "2020-04-19T19:55:49+00:00"
"time": "2020-04-23T19:11:28+00:00"
},
{
"name": "jolicode/jolinotif",
@@ -2186,16 +2186,16 @@
},
{
"name": "laravel-zero/foundation",
"version": "v7.6.1",
"version": "v7.8.1",
"source": {
"type": "git",
"url": "https://github.com/laravel-zero/foundation.git",
"reference": "61438f6d9220d2e20f8610ccbe894507d89f8f1a"
"reference": "eb9fc2275706bdc150fdcc2ff9ec155fc74f7c65"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel-zero/foundation/zipball/61438f6d9220d2e20f8610ccbe894507d89f8f1a",
"reference": "61438f6d9220d2e20f8610ccbe894507d89f8f1a",
"url": "https://api.github.com/repos/laravel-zero/foundation/zipball/eb9fc2275706bdc150fdcc2ff9ec155fc74f7c65",
"reference": "eb9fc2275706bdc150fdcc2ff9ec155fc74f7c65",
"shasum": ""
},
"require": {
@@ -2224,7 +2224,7 @@
"framework",
"laravel"
],
"time": "2020-04-14T16:39:20+00:00"
"time": "2020-04-27T08:21:33+00:00"
},
{
"name": "laravel-zero/framework",
@@ -3140,24 +3140,21 @@
},
{
"name": "phpdocumentor/reflection-common",
"version": "2.0.0",
"version": "2.1.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
"reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a"
"reference": "6568f4687e5b41b054365f9ae03fcb1ed5f2069b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a",
"reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/6568f4687e5b41b054365f9ae03fcb1ed5f2069b",
"reference": "6568f4687e5b41b054365f9ae03fcb1ed5f2069b",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"require-dev": {
"phpunit/phpunit": "~6"
},
"type": "library",
"extra": {
"branch-alias": {
@@ -3188,7 +3185,7 @@
"reflection",
"static analysis"
],
"time": "2018-08-07T13:53:10+00:00"
"time": "2020-04-27T09:25:28+00:00"
},
{
"name": "phpdocumentor/reflection-docblock",
@@ -5542,16 +5539,16 @@
},
{
"name": "symfony/cache",
"version": "v5.0.7",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
"reference": "7c229da093cb0c630e5d16b99fd253e20f979ac2"
"reference": "0c5f5b1882dc82b255a4bdead4ed3c7738cddc04"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/7c229da093cb0c630e5d16b99fd253e20f979ac2",
"reference": "7c229da093cb0c630e5d16b99fd253e20f979ac2",
"url": "https://api.github.com/repos/symfony/cache/zipball/0c5f5b1882dc82b255a4bdead4ed3c7738cddc04",
"reference": "0c5f5b1882dc82b255a4bdead4ed3c7738cddc04",
"shasum": ""
},
"require": {
@@ -5617,7 +5614,7 @@
"caching",
"psr6"
],
"time": "2020-03-27T16:56:45+00:00"
"time": "2020-04-28T17:58:55+00:00"
},
{
"name": "symfony/cache-contracts",
@@ -5679,7 +5676,7 @@
},
{
"name": "symfony/console",
"version": "v5.0.7",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
@@ -5755,7 +5752,7 @@
},
{
"name": "symfony/error-handler",
"version": "v5.0.7",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/error-handler.git",
@@ -5810,7 +5807,7 @@
},
{
"name": "symfony/event-dispatcher",
"version": "v5.0.7",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
@@ -5938,16 +5935,16 @@
},
{
"name": "symfony/expression-language",
"version": "v5.0.7",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/expression-language.git",
"reference": "00e044885469d193c3b8dfa62030cd4525576d4e"
"reference": "b93755750b9e2a8d240bdf014de5b545105c5178"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/expression-language/zipball/00e044885469d193c3b8dfa62030cd4525576d4e",
"reference": "00e044885469d193c3b8dfa62030cd4525576d4e",
"url": "https://api.github.com/repos/symfony/expression-language/zipball/b93755750b9e2a8d240bdf014de5b545105c5178",
"reference": "b93755750b9e2a8d240bdf014de5b545105c5178",
"shasum": ""
},
"require": {
@@ -5985,11 +5982,11 @@
],
"description": "Symfony ExpressionLanguage Component",
"homepage": "https://symfony.com",
"time": "2020-03-27T16:56:45+00:00"
"time": "2020-04-15T15:59:10+00:00"
},
{
"name": "symfony/finder",
"version": "v5.0.7",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
@@ -6038,16 +6035,16 @@
},
{
"name": "symfony/http-foundation",
"version": "v5.0.7",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "26fb006a2c7b6cdd23d52157b05f8414ffa417b6"
"reference": "e47fdf8b24edc12022ba52923150ec6484d7f57d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/26fb006a2c7b6cdd23d52157b05f8414ffa417b6",
"reference": "26fb006a2c7b6cdd23d52157b05f8414ffa417b6",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/e47fdf8b24edc12022ba52923150ec6484d7f57d",
"reference": "e47fdf8b24edc12022ba52923150ec6484d7f57d",
"shasum": ""
},
"require": {
@@ -6089,20 +6086,20 @@
],
"description": "Symfony HttpFoundation Component",
"homepage": "https://symfony.com",
"time": "2020-03-30T14:14:32+00:00"
"time": "2020-04-18T20:50:06+00:00"
},
{
"name": "symfony/http-kernel",
"version": "v5.0.7",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
"reference": "ad574c55d451127cab1c45b4ac51bf283e340cf0"
"reference": "3565e51eecd06106304baba5ccb7ba89db2d7d2b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/ad574c55d451127cab1c45b4ac51bf283e340cf0",
"reference": "ad574c55d451127cab1c45b4ac51bf283e340cf0",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/3565e51eecd06106304baba5ccb7ba89db2d7d2b",
"reference": "3565e51eecd06106304baba5ccb7ba89db2d7d2b",
"shasum": ""
},
"require": {
@@ -6118,6 +6115,7 @@
"symfony/browser-kit": "<4.4",
"symfony/cache": "<5.0",
"symfony/config": "<5.0",
"symfony/console": "<4.4",
"symfony/dependency-injection": "<4.4",
"symfony/doctrine-bridge": "<5.0",
"symfony/form": "<5.0",
@@ -6185,20 +6183,20 @@
],
"description": "Symfony HttpKernel Component",
"homepage": "https://symfony.com",
"time": "2020-03-30T15:04:59+00:00"
"time": "2020-04-28T18:53:25+00:00"
},
{
"name": "symfony/mime",
"version": "v5.0.7",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
"reference": "481b7d6da88922fb1e0d86a943987722b08f3955"
"reference": "5d6c81c39225a750f3f43bee15f03093fb9aaa0b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/481b7d6da88922fb1e0d86a943987722b08f3955",
"reference": "481b7d6da88922fb1e0d86a943987722b08f3955",
"url": "https://api.github.com/repos/symfony/mime/zipball/5d6c81c39225a750f3f43bee15f03093fb9aaa0b",
"reference": "5d6c81c39225a750f3f43bee15f03093fb9aaa0b",
"shasum": ""
},
"require": {
@@ -6247,7 +6245,7 @@
"mime",
"mime-type"
],
"time": "2020-03-27T16:56:45+00:00"
"time": "2020-04-17T03:29:44+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -6543,16 +6541,16 @@
},
{
"name": "symfony/process",
"version": "v5.0.7",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "c5ca4a0fc16a0c888067d43fbcfe1f8a53d8e70e"
"reference": "3179f68dff5bad14d38c4114a1dab98030801fd7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/c5ca4a0fc16a0c888067d43fbcfe1f8a53d8e70e",
"reference": "c5ca4a0fc16a0c888067d43fbcfe1f8a53d8e70e",
"url": "https://api.github.com/repos/symfony/process/zipball/3179f68dff5bad14d38c4114a1dab98030801fd7",
"reference": "3179f68dff5bad14d38c4114a1dab98030801fd7",
"shasum": ""
},
"require": {
@@ -6588,7 +6586,7 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"time": "2020-03-27T16:56:45+00:00"
"time": "2020-04-15T15:59:10+00:00"
},
{
"name": "symfony/psr-http-message-bridge",
@@ -6656,16 +6654,16 @@
},
{
"name": "symfony/routing",
"version": "v5.0.7",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
"reference": "d98a95d0a684caba47a47c1c50c602a669dc973b"
"reference": "9b18480a6e101f8d9ab7c483ace7c19441be5111"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/routing/zipball/d98a95d0a684caba47a47c1c50c602a669dc973b",
"reference": "d98a95d0a684caba47a47c1c50c602a669dc973b",
"url": "https://api.github.com/repos/symfony/routing/zipball/9b18480a6e101f8d9ab7c483ace7c19441be5111",
"reference": "9b18480a6e101f8d9ab7c483ace7c19441be5111",
"shasum": ""
},
"require": {
@@ -6728,7 +6726,7 @@
"uri",
"url"
],
"time": "2020-03-30T11:42:42+00:00"
"time": "2020-04-21T21:02:50+00:00"
},
{
"name": "symfony/service-contracts",
@@ -6790,16 +6788,16 @@
},
{
"name": "symfony/translation",
"version": "v5.0.7",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
"reference": "99b831770e10807dca0979518e2c89edffef5978"
"reference": "c3879db7a68fe3e12b41263b05879412c87b27fd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/99b831770e10807dca0979518e2c89edffef5978",
"reference": "99b831770e10807dca0979518e2c89edffef5978",
"url": "https://api.github.com/repos/symfony/translation/zipball/c3879db7a68fe3e12b41263b05879412c87b27fd",
"reference": "c3879db7a68fe3e12b41263b05879412c87b27fd",
"shasum": ""
},
"require": {
@@ -6863,7 +6861,7 @@
],
"description": "Symfony Translation Component",
"homepage": "https://symfony.com",
"time": "2020-03-27T16:56:45+00:00"
"time": "2020-04-12T16:45:47+00:00"
},
{
"name": "symfony/translation-contracts",
@@ -6924,16 +6922,16 @@
},
{
"name": "symfony/var-dumper",
"version": "v5.0.7",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "f74a126acd701392eef2492a17228d42552c86b5"
"reference": "09de28632f16f81058a85fcf318397218272a07b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/f74a126acd701392eef2492a17228d42552c86b5",
"reference": "f74a126acd701392eef2492a17228d42552c86b5",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/09de28632f16f81058a85fcf318397218272a07b",
"reference": "09de28632f16f81058a85fcf318397218272a07b",
"shasum": ""
},
"require": {
@@ -6995,20 +6993,20 @@
"debug",
"dump"
],
"time": "2020-03-27T16:56:45+00:00"
"time": "2020-04-12T16:45:47+00:00"
},
{
"name": "symfony/var-exporter",
"version": "v5.0.7",
"version": "v5.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-exporter.git",
"reference": "ffd29a70370e466343e33154b5df197a07a13afa"
"reference": "5d18811da9e1ae2bb86b0a97fb2d784e27ffd59f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/ffd29a70370e466343e33154b5df197a07a13afa",
"reference": "ffd29a70370e466343e33154b5df197a07a13afa",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/5d18811da9e1ae2bb86b0a97fb2d784e27ffd59f",
"reference": "5d18811da9e1ae2bb86b0a97fb2d784e27ffd59f",
"shasum": ""
},
"require": {
@@ -7055,7 +7053,7 @@
"instantiate",
"serialize"
],
"time": "2020-03-27T16:56:45+00:00"
"time": "2020-04-15T15:59:10+00:00"
},
{
"name": "theseer/tokenizer",

View File

@@ -0,0 +1,139 @@
<?php
namespace Tests\Feature\Client;
use App\Client\Factory;
use App\Client\Http\HttpClient;
use App\Logger\LoggedRequest;
use App\Logger\RequestLogger;
use Clue\React\Buzz\Browser;
use Clue\React\Buzz\Message\ResponseException;
use GuzzleHttp\Psr7\Request;
use Mockery as m;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use React\EventLoop\LoopInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use function GuzzleHttp\Psr7\str;
class DashboardTest extends TestCase
{
/** @var Browser */
protected $browser;
/** @var Factory */
protected $dashboardFactory;
/** @var RequestLogger */
protected $requestLogger;
public function setUp(): void
{
parent::setUp();
$this->browser = new Browser($this->loop);
$this->requestLogger = $this->app->make(RequestLogger::class);
}
public function tearDown(): void
{
parent::tearDown();
$this->dashboardFactory->getApp()->close();
}
/** @test */
public function accessing_the_dashboard_works()
{
$this->startDashboard();
/** @var ResponseInterface $response */
$response = $this->await($this->browser->get('http://127.0.0.1:4040'));
$this->assertSame(200, $response->getStatusCode());
}
/** @test */
public function it_can_replay_requests()
{
$request = new Request('GET', '/example', [
'X-Expose-Request-ID' => 'request-one'
]);
$httpClient = m::mock(HttpClient::class);
$httpClient->shouldReceive('performRequest')
->once()
->with(str($request));
app()->instance(HttpClient::class, $httpClient);
$this->startDashboard();
$this->logRequest($request);
$this->assertSame(200,
$this->await($this->browser->get("http://127.0.0.1:4040/replay/request-one"))
->getStatusCode()
);
}
/** @test */
public function it_returns_404_for_non_existing_replay_logs()
{
$this->startDashboard();
$this->expectException(ResponseException::class);
$this->expectExceptionMessage(404);
$this->await($this->browser->get("http://127.0.0.1:4040/replay/invalid-request"));
}
/** @test */
public function it_can_clear_logs()
{
$this->startDashboard();
$this->logRequest(new Request('GET', '/foo'));
$this->logRequest(new Request('POST', '/bar'));
$this->logRequest(new Request('DELETE', '/baz'));
$this->assertCount(3, $this->requestLogger->getData());
$this->await($this->browser->get("http://127.0.0.1:4040/logs/clear"));
$this->assertCount(0, $this->requestLogger->getData());
}
/** @test */
public function it_can_attach_additional_data_to_requests()
{
$this->startDashboard();
$loggedRequest = $this->logRequest(new Request('GET', '/foo'));
$this->await($this->browser->post("http://127.0.0.1:4040/logs/{$loggedRequest->id()}/data", [
'Content-Type' => 'application/json'
], json_encode([
'data' => [
'foo' => 'bar',
]
])));
$this->assertSame([
'foo' => 'bar'
], $this->requestLogger->findLoggedRequest($loggedRequest->id())->getAdditionalData());
}
protected function logRequest(RequestInterface $request): LoggedRequest
{
return $this->requestLogger->logRequest(str($request), \Laminas\Http\Request::fromString(str($request)));
}
protected function startDashboard()
{
$this->dashboardFactory = (new Factory())
->setLoop($this->loop)
->createHttpServer();
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Tests\Feature\Client;
use React\EventLoop\Factory;
use React\EventLoop\LoopInterface;
use React\EventLoop\StreamSelectLoop;
use React\Promise\PromiseInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use function Clue\React\Block\await;
abstract class TestCase extends \Tests\TestCase
{
const AWAIT_TIMEOUT = 1.0;
/** @var LoopInterface */
protected $loop;
public function setUp(): void
{
parent::setUp();
$this->app->bind(ConsoleOutputInterface::class, function() {
return new ConsoleOutput();
});
/** @var LoopInterface $loop */
$this->loop = $this->app->make(LoopInterface::class);
}
protected function await(PromiseInterface $promise, LoopInterface $loop = null, $timeout = null)
{
return await($promise, $loop ?? $this->loop, $timeout ?? static::AWAIT_TIMEOUT);
}
}

View File

@@ -1,20 +0,0 @@
<?php
namespace Tests\Feature;
use Tests\TestCase;
class InspiringCommandTest extends TestCase
{
/**
* A basic test example.
*
* @return void
*/
public function testInspiringCommand()
{
$this->artisan('inspiring')
->expectsOutput('Simplicity is the ultimate sophistication.')
->assertExitCode(0);
}
}

View File

@@ -1,18 +0,0 @@
<?php
namespace Tests\Unit;
use seregazhuk\React\PromiseTesting\TestCase;
class ExampleTest extends TestCase
{
/**
* A basic test example.
*
* @return void
*/
public function testBasicTest()
{
$this->assertTrue(true);
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Tests\Unit;
use App\Logger\LoggedRequest;
use GuzzleHttp\Psr7\Request;
use Laminas\Http\Request as LaminasRequest;
use Tests\TestCase;
use function GuzzleHttp\Psr7\str;
class LoggedRequestTest extends TestCase
{
/** @test */
public function it_retrieves_the_request_id()
{
$rawRequest = str(new Request(200, '/expose', [
'X-Expose-Request-ID' => 'example-request'
]));
$parsedRequest = LaminasRequest::fromString($rawRequest);
$loggedRequest = new LoggedRequest($rawRequest, $parsedRequest);
$this->assertSame('example-request', $loggedRequest->id());
}
/** @test */
public function it_returns_the_raw_request()
{
$rawRequest = str(new Request(200, '/expose', [
'X-Expose-Request-ID' => 'example-request'
]));
$parsedRequest = LaminasRequest::fromString($rawRequest);
$loggedRequest = new LoggedRequest($rawRequest, $parsedRequest);
$this->assertSame($rawRequest, $loggedRequest->getRequestData());
}
/** @test */
public function it_returns_the_parsed_request()
{
$rawRequest = str(new Request(200, '/expose', [
'X-Expose-Request-ID' => 'example-request'
]));
$parsedRequest = LaminasRequest::fromString($rawRequest);
$loggedRequest = new LoggedRequest($rawRequest, $parsedRequest);
$this->assertSame($parsedRequest, $loggedRequest->getRequest());
}
}

View File

@@ -0,0 +1,122 @@
<?php
namespace Tests\Unit;
use App\Logger\CliRequestLogger;
use App\Logger\RequestLogger;
use Clue\React\Buzz\Browser;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use Laminas\Http\Request as LaminasRequest;
use Tests\TestCase;
use function GuzzleHttp\Psr7\str;
use Mockery as m;
class RequestLoggerTest extends TestCase
{
/** @test */
public function it_can_log_requests()
{
$browser = m::mock(Browser::class);
$browser->shouldReceive('post')
->once();
$cliLogger = m::mock(CliRequestLogger::class);
$cliLogger->shouldReceive('logRequest')->once();
$requestString = str(new Request(200, '/example'));
$parsedRequest = LaminasRequest::fromString($requestString);
$logger = new RequestLogger($browser, $cliLogger);
$logger->logRequest($requestString, $parsedRequest);
$this->assertCount(1, $logger->getData());
}
/** @test */
public function it_can_clear_the_requests()
{
$browser = m::mock(Browser::class);
$browser->shouldReceive('post')
->twice();
$cliLogger = m::mock(CliRequestLogger::class);
$cliLogger->shouldReceive('logRequest')->once();
$requestString = str(new Request(200, '/example'));
$parsedRequest = LaminasRequest::fromString($requestString);
$logger = new RequestLogger($browser, $cliLogger);
$logger->logRequest($requestString, $parsedRequest);
$logger->clear();
$this->assertCount(0, $logger->getData());
}
/** @test */
public function it_can_associate_a_response_with_a_request()
{
$browser = m::mock(Browser::class);
$browser->shouldReceive('post')
->twice();
$cliLogger = m::mock(CliRequestLogger::class);
$cliLogger->shouldReceive('logRequest')
->twice();
$requestString = str(new Request(200, '/example'));
$parsedRequest = LaminasRequest::fromString($requestString);
$logger = new RequestLogger($browser, $cliLogger);
$loggedRequest = $logger->logRequest($requestString, $parsedRequest);
$this->assertNull($logger->findLoggedRequest($loggedRequest->id())->getResponse());
$responseString = str(new Response(200, [], 'Hello World!'));
$logger->logResponse($parsedRequest, $responseString);
$this->assertNotNull($logger->findLoggedRequest($loggedRequest->id())->getResponse());
}
/** @test */
public function it_can_find_a_request_by_id()
{
$browser = m::mock(Browser::class);
$browser->shouldReceive('post')
->once();
$cliLogger = m::mock(CliRequestLogger::class);
$cliLogger->shouldReceive('logRequest')->once();
$requestString = str(new Request(200, '/example'));
$parsedRequest = LaminasRequest::fromString($requestString);
$logger = new RequestLogger($browser, $cliLogger);
$loggedRequest = $logger->logRequest($requestString, $parsedRequest);
$this->assertSame($loggedRequest, $logger->findLoggedRequest($loggedRequest->id()));
}
/** @test */
public function it_only_stores_a_limited_amount_of_requests()
{
$browser = m::mock(Browser::class);
$browser->shouldReceive('post');
$cliLogger = m::mock(CliRequestLogger::class);
$cliLogger->shouldReceive('logRequest');
$requestString = str(new Request(200, '/example'));
$parsedRequest = LaminasRequest::fromString($requestString);
$logger = new RequestLogger($browser, $cliLogger);
foreach (range(1, 20) as $i) {
$logger->logRequest($requestString, $parsedRequest);
}
$this->assertCount(RequestLogger::MAX_LOGGED_REQUESTS, $logger->getData());
}
}