Commit b15aed57 authored by catch's avatar catch

Issue #1859684 by dawehner, effulgentsia: Expand routeBuilder unit test.

parent 0d263c64
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
namespace Drupal\Core\Routing; namespace Drupal\Core\Routing;
use Symfony\Component\Routing\Matcher\Dumper\MatcherDumperInterface;
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RouteCollection;
use Drupal\Core\Database\Connection; use Drupal\Core\Database\Connection;
...@@ -59,10 +58,7 @@ public function __construct(Connection $connection, $table = 'router') { ...@@ -59,10 +58,7 @@ public function __construct(Connection $connection, $table = 'router') {
} }
/** /**
* Adds additional routes to be dumped. * {@inheritdoc}
*
* @param Symfony\Component\Routing\RouteCollection $routes
* A collection of routes to add to this dumper.
*/ */
public function addRoutes(RouteCollection $routes) { public function addRoutes(RouteCollection $routes) {
if (empty($this->routes)) { if (empty($this->routes)) {
......
<?php
/**
* @file
* Contains \Drupal\Core\Routing\MatcherDumperInterface.
*/
namespace Drupal\Core\Routing;
use Symfony\Component\Routing\Matcher\Dumper\MatcherDumperInterface as SymfonyMatcherDumperInterface;
use Symfony\Component\Routing\RouteCollection;
/**
* Extends the symfony matcher dumper interface with a addRoutes method.
*/
interface MatcherDumperInterface extends SymfonyMatcherDumperInterface {
/**
* Adds additional routes to be dumped.
*
* @param \Symfony\Component\Routing\RouteCollection $routes
* A collection of routes to add to this dumper.
*/
public function addRoutes(RouteCollection $routes);
}
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
namespace Drupal\Core\Routing; namespace Drupal\Core\Routing;
use Drupal\Component\Discovery\YamlDiscovery; use Drupal\Component\Discovery\YamlDiscovery;
use Symfony\Component\Routing\Matcher\Dumper\MatcherDumperInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Yaml\Parser; use Symfony\Component\Yaml\Parser;
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RouteCollection;
...@@ -47,7 +46,14 @@ class RouteBuilder { ...@@ -47,7 +46,14 @@ class RouteBuilder {
protected $dispatcher; protected $dispatcher;
/** /**
* The extension handler for retieving the list of enabled modules. * The yaml discovery used to find all the .routing.yml files.
*
* @var \Drupal\Component\Discovery\YamlDiscovery
*/
protected $yamlDiscovery;
/**
* The module handler.
* *
* @var \Drupal\Core\Extension\ModuleHandlerInterface * @var \Drupal\Core\Extension\ModuleHandlerInterface
*/ */
...@@ -56,12 +62,14 @@ class RouteBuilder { ...@@ -56,12 +62,14 @@ class RouteBuilder {
/** /**
* Construcs the RouteBuilder using the passed MatcherDumperInterface. * Construcs the RouteBuilder using the passed MatcherDumperInterface.
* *
* @param \Symfony\Component\Routing\Matcher\Dumper\MatcherDumperInterface $dumper * @param \Drupal\Core\Routing\MatcherDumperInterface $dumper
* The matcher dumper used to store the route information. * The matcher dumper used to store the route information.
* @param \Drupal\Core\Lock\LockBackendInterface $lock * @param \Drupal\Core\Lock\LockBackendInterface $lock
* The lock backend. * The lock backend.
* @param \Symfony\Component\EventDispatcherEventDispatcherInterface * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
* The event dispatcher to notify of routes. * The event dispatcher to notify of routes.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
*/ */
public function __construct(MatcherDumperInterface $dumper, LockBackendInterface $lock, EventDispatcherInterface $dispatcher, ModuleHandlerInterface $module_handler) { public function __construct(MatcherDumperInterface $dumper, LockBackendInterface $lock, EventDispatcherInterface $dispatcher, ModuleHandlerInterface $module_handler) {
$this->dumper = $dumper; $this->dumper = $dumper;
...@@ -72,6 +80,9 @@ public function __construct(MatcherDumperInterface $dumper, LockBackendInterface ...@@ -72,6 +80,9 @@ public function __construct(MatcherDumperInterface $dumper, LockBackendInterface
/** /**
* Rebuilds the route info and dumps to dumper. * Rebuilds the route info and dumps to dumper.
*
* @return bool
* Returns TRUE if the rebuild succeeds, FALSE otherwise.
*/ */
public function rebuild() { public function rebuild() {
if (!$this->lock->acquire('router_rebuild')) { if (!$this->lock->acquire('router_rebuild')) {
...@@ -79,10 +90,10 @@ public function rebuild() { ...@@ -79,10 +90,10 @@ public function rebuild() {
// We choose to block here since otherwise the routes might not be // We choose to block here since otherwise the routes might not be
// available, resulting in a 404. // available, resulting in a 404.
$this->lock->wait('router_rebuild'); $this->lock->wait('router_rebuild');
return; return FALSE;
} }
$yaml_discovery = new YamlDiscovery('routing', $this->moduleHandler->getModuleDirectories()); $yaml_discovery = $this->getYamlDiscovery();
foreach ($yaml_discovery->findAll() as $module => $routes) { foreach ($yaml_discovery->findAll() as $module => $routes) {
$collection = new RouteCollection(); $collection = new RouteCollection();
...@@ -111,6 +122,20 @@ public function rebuild() { ...@@ -111,6 +122,20 @@ public function rebuild() {
$this->dumper->dump(array('route_set' => 'dynamic_routes')); $this->dumper->dump(array('route_set' => 'dynamic_routes'));
$this->lock->release('router_rebuild'); $this->lock->release('router_rebuild');
return TRUE;
}
/**
* Returns the YAML discovery for getting all the .routing.yml files.
*
* @return \Drupal\Component\Discovery\YamlDiscovery
* The yaml discovery.
*/
protected function getYamlDiscovery() {
if (!isset($this->yamlDiscovery)) {
$this->yamlDiscovery = new YamlDiscovery('routing', $this->moduleHandler->getModuleDirectories());
}
return $this->yamlDiscovery;
} }
} }
...@@ -43,6 +43,44 @@ public function dropTables(Connection $connection) { ...@@ -43,6 +43,44 @@ public function dropTables(Connection $connection) {
} }
} }
/**
* Returns a static version of the routes.
*/
public function staticSampleRouteCollection() {
$routes = array();
$routes['route_a'] = array(
'path' => '/path/one',
'requirements' => array(
'_method' => 'GET',
),
);
$routes['route_b'] = array(
'path' => '/path/one',
'requirements' => array(
'_method' => 'PUT',
),
);
$routes['route_c'] = array(
'path' => '/path/two',
'requirements' => array(
'_method' => 'GET',
'_format' => 'json'
),
);
$routes['route_d'] = array(
'path' => '/path/three',
);
$routes['route_e'] = array(
'path' => '/path/two',
'requirements' => array(
'_method' => 'GET|HEAD',
'_format' => 'html'
),
);
return $routes;
}
/** /**
* Returns a standard set of routes for testing. * Returns a standard set of routes for testing.
* *
......
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Routing\RouteBuilderTest.
*/
namespace Drupal\Tests\Core\Routing;
use Drupal\Component\Discovery\YamlDiscovery;
use Drupal\Core\Routing\RouteBuilder;
use Drupal\Core\Routing\RouteBuildEvent;
use Drupal\Core\Routing\RoutingEvents;
use Drupal\system\Tests\Routing\RoutingFixtures;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
* Tests the route builder.
*
* @group Drupal
* @group Routing
*
* @see \Drupal\Core\Routing\RouteBuilder
*/
class RouteBuilderTest extends UnitTestCase {
/**
* The actual tested route builder.
*
* @var \Drupal\Core\Routing\RouteBuilder
*/
protected $routeBuilder;
/**
* The mocked matcher dumper.
*
* @var \Drupal\Core\Routing\MatcherDumperInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $dumper;
/**
* The mocked lock backend.
*
* @var \Drupal\Core\Lock\LockBackendInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $lock;
/**
* The mocked event dispatcher.
*
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $dispatcher;
/**
* The mocked yaml discovery.
*
* @var \Drupal\Component\Discovery\YamlDiscovery|\PHPUnit_Framework_MockObject_MockObject
*/
protected $yamlDiscovery;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
public static function getInfo() {
return array(
'name' => 'Route Builder',
'description' => 'Tests the route builder.',
'group' => 'Routing',
);
}
protected function setUp() {
$this->dumper = $this->getMock('Drupal\Core\Routing\MatcherDumperInterface');
$this->lock = $this->getMock('Drupal\Core\Lock\LockBackendInterface');
$this->dispatcher = $this->getMock('\Symfony\Component\EventDispatcher\EventDispatcherInterface');
$this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
$this->yamlDiscovery = $this->getMockBuilder('\Drupal\Component\Discovery\YamlDiscovery')
->disableOriginalConstructor()
->getMock();
$this->routeBuilder = new TestRouteBuilder($this->dumper, $this->lock, $this->dispatcher, $this->moduleHandler);
$this->routeBuilder->setYamlDiscovery($this->yamlDiscovery);
}
/**
* Tests that the route rebuilding both locks and unlocks.
*/
public function testRebuildLockingUnlocking() {
$this->lock->expects($this->once())
->method('acquire')
->with('router_rebuild')
->will($this->returnValue(TRUE));
$this->lock->expects($this->once())
->method('release')
->with('router_rebuild');
$this->yamlDiscovery->expects($this->any())
->method('findAll')
->will($this->returnValue(array()));
$this->assertTrue($this->routeBuilder->rebuild());
}
/**
* Tests route rebuilding with a blocking lock.
*/
public function testRebuildBlockingLock() {
$this->lock->expects($this->once())
->method('acquire')
->with('router_rebuild')
->will($this->returnValue(FALSE));
$this->lock->expects($this->once())
->method('wait')
->with('router_rebuild');
$this->lock->expects($this->never())
->method('release');
$this->yamlDiscovery->expects($this->never())
->method('findAll');
$this->assertFalse($this->routeBuilder->rebuild());
}
/**
* Tests that provided routes by a module is put into the dumper/dispatcher.
*
* @see \Drupal\Core\Routing\RouteBuilder::rebuild()
*/
public function testRebuildWithStaticModuleRoutes() {
$this->lock->expects($this->once())
->method('acquire')
->with('router_rebuild')
->will($this->returnValue(TRUE));
$routing_fixtures = new RoutingFixtures();
$routes = $routing_fixtures->staticSampleRouteCollection();
$this->yamlDiscovery->expects($this->once())
->method('findAll')
->will($this->returnValue(array('test_module' => $routes)));
// Ensure that the dispatch events for altering are fired.
$this->dispatcher->expects($this->at(0))
->method('dispatch')
->with($this->equalTo(RoutingEvents::ALTER), $this->isInstanceOf('Drupal\Core\Routing\RouteBuildEvent'));
$empty_collection = new RouteCollection();
$route_build_event = new RouteBuildEvent($empty_collection, 'dynamic_routes');
// Ensure that the dynamic routes events are fired.
$this->dispatcher->expects($this->at(1))
->method('dispatch')
->with(RoutingEvents::DYNAMIC, $route_build_event);
$this->dispatcher->expects($this->at(2))
->method('dispatch')
->with(RoutingEvents::ALTER, $route_build_event);
// Ensure that the routes are set to the dumper and dumped.
$this->dumper->expects($this->at(0))
->method('addRoutes')
->with($routing_fixtures->sampleRouteCollection());
$this->dumper->expects($this->at(1))
->method('dump')
->with(array('route_set' => 'test_module'));
$this->dumper->expects($this->at(2))
->method('addRoutes')
->with($empty_collection);
$this->dumper->expects($this->at(3))
->method('dump')
->with(array('route_set' => 'dynamic_routes'));
$this->assertTrue($this->routeBuilder->rebuild());
}
/**
* Tests the rebuild with some dynamic routes.
*
* @see \Drupal\Core\Routing\RouteBuilder::rebuild()
*/
public function testRebuildWithDynamicRoutes() {
$this->lock->expects($this->once())
->method('acquire')
->with('router_rebuild')
->will($this->returnValue(TRUE));
$this->yamlDiscovery->expects($this->once())
->method('findAll')
->will($this->returnValue(array()));
$route_collection_filled = new RouteCollection();
$route_collection_filled->add('test_route', new Route('/test-route'));
$this->dispatcher->expects($this->at(0))
->method('dispatch')
->with($this->equalTo(RoutingEvents::DYNAMIC))
->will($this->returnCallback(function ($object, RouteBuildEvent $event) {
$event->getRouteCollection()->add('test_route', new Route('/test-route'));
}));
$this->dispatcher->expects($this->at(1))
->method('dispatch')
->with($this->equalTo(RoutingEvents::ALTER));
$this->dumper->expects($this->once())
->method('addRoutes')
->with($route_collection_filled);
$this->dumper->expects($this->once())
->method('dump')
->with(array('route_set' => 'dynamic_routes'));
$this->assertTrue($this->routeBuilder->rebuild());
}
}
/**
* Extends the core route builder with a setter method for the yaml discovery.
*/
class TestRouteBuilder extends RouteBuilder {
/**
* Sets the yaml discovery.
*
* @param \Drupal\Component\Discovery\YamlDiscovery $yaml_discovery
* The yaml discovery to set.
*/
public function setYamlDiscovery(YamlDiscovery $yaml_discovery) {
$this->yamlDiscovery = $yaml_discovery;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment