Skip to content

Commit

Permalink
fix tests and port code from the CakePHP core
Browse files Browse the repository at this point in the history
  • Loading branch information
steinkel committed Feb 25, 2022
1 parent 094e29b commit eba9ffb
Show file tree
Hide file tree
Showing 8 changed files with 370 additions and 1 deletion.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"prefer-stable": true,
"require": {
"php": ">=7.4",
"cakephp/cakephp": "^4.3"
"cakephp/cakephp": "4.next-dev"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
Expand Down
33 changes: 33 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
colors="true"
processIsolation="false"
stopOnFailure="false"
bootstrap="./tests/bootstrap.php"
>
<php>
<ini name="memory_limit" value="-1"/>
<ini name="apc.enable_cli" value="1"/>
<env name="FIXTURE_SCHEMA_METADATA" value="./tests/schema.php"/>
</php>

<!-- Add any additional test suites you want to run here -->
<testsuites>
<testsuite name="Api Test Suite">
<directory>./tests/TestCase</directory>
</testsuite>
</testsuites>

<!-- Setup a listener for fixtures -->
<extensions>
<extension class="\Cake\TestSuite\Fixture\PHPUnitExtension" />
</extensions>

<!-- Prevent coverage reports from looking in tests and vendors -->
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
</whitelist>
</filter>

</phpunit>
81 changes: 81 additions & 0 deletions src/Routing/Middleware/CachedRoutingMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php
declare(strict_types=1);

/**
* Copyright 2013 - 2022, Cake Development Corporation (https://www.cakedc.com)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2013 - 2022, Cake Development Corporation (https://www.cakedc.com)
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
namespace CakeDC\CachedRouting\Routing\Middleware;

use Cake\Cache\Cache;
use Cake\Routing\Exception\FailedRouteCacheException;
use Cake\Routing\Middleware\RoutingMiddleware;
use Cake\Routing\RouteCollection;
use Cake\Routing\RoutingApplicationInterface;

/**
* Cache the route collection contents to speed up route loading.
* IMPORTANT: It will only work correctly for serializable route collections
*/
class CachedRoutingMiddleware extends RoutingMiddleware
{
/**
* Key used to store the route collection in the cache engine
*
* @var string
*/
public const ROUTE_COLLECTION_CACHE_KEY = 'routeCollection';

/**
* The cache configuration name to use for route collection caching,
* null to disable caching
*
* @var string|null
*/
protected $cacheConfig;

/**
* Constructor
*
* @param \Cake\Routing\RoutingApplicationInterface $app The application instance that routes are defined on.
* @param string|null $cacheConfig The cache config name to use or null to disable routes cache
*/
public function __construct(RoutingApplicationInterface $app, ?string $cacheConfig = null)
{
parent::__construct($app);
$this->cacheConfig = $cacheConfig;
}

/**
* Check if route cache is enabled and use the configured Cache to 'remember' the route collection
*
* @return \Cake\Routing\RouteCollection
*/
protected function buildRouteCollection(): RouteCollection
{
if (Cache::enabled() && $this->cacheConfig !== null) {
try {
return Cache::remember(static::ROUTE_COLLECTION_CACHE_KEY, function () {
return $this->prepareRouteCollection();
}, $this->cacheConfig);
} catch (\InvalidArgumentException $e) {
throw $e;
} catch (\Exception $e) {
throw new FailedRouteCacheException(
'Unable to cache route collection. Cached routes must be serializable. Check for route-specific
middleware or other unserializable settings in your routes. The original exception message can
show what type of object failed to serialize.',
null,
$e
);
}
}

return $this->prepareRouteCollection();
}
}
51 changes: 51 additions & 0 deletions tests/App/Application.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);

/**
* Copyright 2013 - 2022, Cake Development Corporation (https://www.cakedc.com)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2013 - 2022, Cake Development Corporation (https://www.cakedc.com)
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
namespace CakeDC\CachedRouting\Test\App;

use Cake\Core\HttpApplicationInterface;
use Cake\Http\MiddlewareQueue;
use Cake\Http\Response;
use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class Application implements \Cake\Routing\RoutingApplicationInterface, HttpApplicationInterface
{
public function __construct()
{
Router::reload();
}

/**
* @inheritDoc
*/
public function routes(RouteBuilder $routes): void
{
$routes->connect('/articles', ['controller' => 'Articles', 'action' => 'index']);
}

public function bootstrap(): void
{
}

public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
return $middlewareQueue;
}

public function handle(ServerRequestInterface $request): ResponseInterface
{
return new Response();
}
}
28 changes: 28 additions & 0 deletions tests/App/TestRequestHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);

/**
* Copyright 2013 - 2022, Cake Development Corporation (https://www.cakedc.com)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2013 - 2022, Cake Development Corporation (https://www.cakedc.com)
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
namespace CakeDC\CachedRouting\Test\App;

use Cake\Http\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class TestRequestHandler implements \Psr\Http\Server\RequestHandlerInterface
{
/**
* @inheritDoc
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
return new Response();
}
}
34 changes: 34 additions & 0 deletions tests/App/UnserializableMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);

/**
* Copyright 2013 - 2022, Cake Development Corporation (https://www.cakedc.com)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2013 - 2022, Cake Development Corporation (https://www.cakedc.com)
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
namespace CakeDC\CachedRouting\Test\App;

use Cake\Core\HttpApplicationInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class UnserializableMiddleware implements MiddlewareInterface
{
protected HttpApplicationInterface $app;

public function __construct(HttpApplicationInterface $app)
{
$this->app = $app;
}

public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
return $request;
}
}
82 changes: 82 additions & 0 deletions tests/TestCase/Routing/Middleware/CachedRoutingMiddlewareTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);

/**
* Copyright 2013 - 2022, Cake Development Corporation (https://www.cakedc.com)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2013 - 2022, Cake Development Corporation (https://www.cakedc.com)
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/

namespace CakeDC\CachedRouting\Test\TestCase\Routing\Middleware;

use Cake\Cache\Cache;
use Cake\Core\Configure;
use Cake\Http\Response;
use Cake\Http\ServerRequestFactory;
use Cake\Routing\Exception\FailedRouteCacheException;
use Cake\Routing\RouteBuilder;
use Cake\Routing\RouteCollection;
use Cake\Routing\Router;
use Cake\TestSuite\TestCase;
use CakeDC\CachedRouting\Routing\Middleware\CachedRoutingMiddleware;
use CakeDC\CachedRouting\Test\App\Application;
use CakeDC\CachedRouting\Test\App\TestRequestHandler;
use CakeDC\CachedRouting\Test\App\UnserializableMiddleware;

class CachedRoutingMiddlewareTest extends TestCase
{
public function tearDown(): void
{
parent::tearDown();

Cache::enable();
if (in_array('_cake_router_', Cache::configured(), true)) {
Cache::clear('_cake_router_');
}
Cache::drop('_cake_router_');
}

/**
* Test we store route collection in cache.
*/
public function testCacheRoutes(): void
{
$cacheConfigName = '_cake_router_';
Cache::setConfig($cacheConfigName, [
'engine' => 'File',
'path' => CACHE,
]);
$request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/articles']);
$middleware = new CachedRoutingMiddleware(new Application(), $cacheConfigName);
$middleware->process($request, new TestRequestHandler());

$routeCollection = Cache::read('routeCollection', $cacheConfigName);
$this->assertInstanceOf(RouteCollection::class, $routeCollection);
}

public function testFailedRouteCache(): void
{
Cache::setConfig('_cake_router_', [
'engine' => 'File',
'path' => CACHE,
]);

$app = $this->createMock(Application::class);
$app
->method('routes')
->will($this->returnCallback(function (RouteBuilder $routes) use ($app) {
return $routes->registerMiddleware('should fail', new UnserializableMiddleware($app));
}));

$middleware = new CachedRoutingMiddleware($app, '_cake_router_');
$request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/articles']);

$this->expectException(FailedRouteCacheException::class);
$this->expectExceptionMessage('Unable to cache route collection.');
$middleware->process($request, new TestRequestHandler());
}
}
60 changes: 60 additions & 0 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);

/**
* Copyright 2013 - 2022, Cake Development Corporation (https://www.cakedc.com)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2013 - 2022, Cake Development Corporation (https://www.cakedc.com)
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/

use Cake\Core\Configure;
use Cake\Mailer\Email;
use Cake\Utility\Security;

$findRoot = function () {
$root = dirname(__DIR__);
if (is_dir($root . '/vendor/cakephp/cakephp')) {
return $root;
}

$root = dirname(__DIR__, 2);
if (is_dir($root . '/vendor/cakephp/cakephp')) {
return $root;
}

$root = dirname(__DIR__, 3);
if (is_dir($root . '/vendor/cakephp/cakephp')) {
return $root;
}

return null;
};

function def($name, $value)
{
if (!defined($name)) {
define($name, $value);
}
}

def('DS', DIRECTORY_SEPARATOR);
def('ROOT', $findRoot());
def('APP_DIR', 'App');
def('WEBROOT_DIR', 'webroot');
def('APP', ROOT . '/tests/App/');
def('CONFIG', ROOT . '/tests/Config/');
def('WWW_ROOT', ROOT . '/webroot/');
def('TESTS', ROOT . DS . 'tests' . DS);
def('TMP', ROOT . DS . 'tmp' . DS);
def('LOGS', TMP . 'logs' . DS);
def('CACHE', TMP . 'cache' . DS);
def('CAKE_CORE_INCLUDE_PATH', ROOT . '/vendor/cakephp/cakephp');
def('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS);
def('CAKE', CORE_PATH . 'src' . DS);

require ROOT . '/vendor/cakephp/cakephp/src/basics.php';
require ROOT . '/vendor/autoload.php';

0 comments on commit eba9ffb

Please sign in to comment.