diff --git a/core/lib/Drupal/Core/Menu/LocalActionManager.php b/core/lib/Drupal/Core/Menu/LocalActionManager.php
index 32ae80e57bb272624ab64f99fa8c37f116d90658..79e40c9f365891017e20d25d8d406900dc4c76c3 100644
--- a/core/lib/Drupal/Core/Menu/LocalActionManager.php
+++ b/core/lib/Drupal/Core/Menu/LocalActionManager.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\Menu\LocalActionInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\Component\Plugin\Discovery\ProcessDecorator;
@@ -94,7 +95,7 @@ class LocalActionManager extends DefaultPluginManager {
 /**
    * The plugin instances.
    *
-   * @var array
+   * @var \Drupal\Core\Menu\LocalActionInterface[]
    */
   protected $instances = array();
 
@@ -112,12 +113,14 @@ class LocalActionManager extends DefaultPluginManager {
    *   The module handler.
    * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
    *   Cache backend instance to use.
-   * @param \Drupal\Core\Language\LanguageManager $language_manager
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
    *   The language manager.
    * @param \Drupal\Core\Access\AccessManager $access_manager
    *   The access manager.
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   The current user.
    */
-  public function __construct(ControllerResolverInterface $controller_resolver, Request $request, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, LanguageManager $language_manager, AccessManager $access_manager, AccountInterface $account) {
+  public function __construct(ControllerResolverInterface $controller_resolver, Request $request, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, AccessManager $access_manager, AccountInterface $account) {
     // Skip calling the parent constructor, since that assumes annotation-based
     // discovery.
     $this->discovery = new YamlDiscovery('local_actions', $module_handler->getModuleDirectories());
@@ -179,10 +182,10 @@ public function getActionsForRoute($route_appears) {
       }
     }
     $links = array();
-    foreach ($this->instances[$route_appears] as $plugin) {
+    foreach ($this->instances[$route_appears] as $plugin_id => $plugin) {
       $route_name = $plugin->getRouteName();
       $route_parameters = $plugin->getRouteParameters($this->request);
-      $links[$route_name] = array(
+      $links[$plugin_id] = array(
         '#theme' => 'menu_local_action',
         '#link' => array(
           'title' => $this->getTitle($plugin),
diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6685b9c8d641a4644e0055e4c61dd9583e2491c4
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php
@@ -0,0 +1,386 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Menu\LocalActionManagerTest.
+ */
+
+namespace Drupal\Tests\Core\Menu;
+
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\Factory\FactoryInterface;
+use Drupal\Core\Access\AccessManager;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\Menu\LocalActionManager;
+use Drupal\Core\Routing\RouteProviderInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
+
+/**
+ * Tests the local action manager.
+ *
+ * @group Drupal
+ * @group Menu
+ *
+ * @covers \Drupal\Core\Menu\LocalActionManager
+ */
+class LocalActionManagerTest extends UnitTestCase {
+
+  /**
+   * The mocked controller resolver.
+   *
+   * @var \Drupal\Core\Controller\ControllerResolverInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $controllerResolver;
+
+  /**
+   * The mocked request.
+   *
+   * @var \Symfony\Component\HttpFoundation\Request|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $request;
+
+  /**
+   * The mocked module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $moduleHandler;
+
+  /**
+   * The mocked router provider.
+   *
+   * @var \Drupal\Core\Routing\RouteProviderInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $routeProvider;
+
+  /**
+   * The mocked cache backend.
+   *
+   * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $cacheBackend;
+
+  /**
+   * The mocked language manager.
+   *
+   * @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $languageManager;
+
+  /**
+   * The mocked access manager.
+   *
+   * @var \Drupal\Core\Access\AccessManager|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $accessManager;
+
+  /**
+   * The mocked account.
+   *
+   * @var \Drupal\Core\Session\AccountInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $account;
+
+  /**
+   * The mocked factory.
+   *
+   * @var \Drupal\Component\Plugin\Factory\FactoryInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $factory;
+
+  /**
+   * The mocked plugin discovery.
+   *
+   * @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $discovery;
+
+  /**
+   * The tested local action manager
+   *
+   * @var \Drupal\Tests\Core\Menu\TestLocalActionManager
+   */
+  protected $localActionManager;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Local actions manager',
+      'description' => 'Tests the local action manager.',
+      'group' => 'Menu',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    $this->controllerResolver = $this->getMock('Drupal\Core\Controller\ControllerResolverInterface');
+    $this->request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+    $this->routeProvider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface');
+    $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
+    $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
+    $this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
+    $this->languageManager->expects($this->any())
+      ->method('getCurrentLanguage')
+      ->will($this->returnValue(
+        new Language(array('langcode' => 'en'))
+      ));
+
+    $this->accessManager = $this->getMockBuilder('Drupal\Core\Access\AccessManager')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $this->account = $this->getMock('Drupal\Core\Session\AccountInterface');
+    $this->discovery = $this->getMock('Drupal\Component\Plugin\Discovery\DiscoveryInterface');
+    $this->factory = $this->getMock('Drupal\Component\Plugin\Factory\FactoryInterface');
+
+    $this->localActionManager = new TestLocalActionManager($this->controllerResolver, $this->request, $this->routeProvider, $this->moduleHandler, $this->cacheBackend, $this->languageManager, $this->accessManager, $this->account, $this->discovery, $this->factory);
+  }
+
+  /**
+   * @covers \Drupal\Core\Menu\LocalActionManager::getTitle()
+   */
+  public function testGetTitle() {
+    $local_action = $this->getMock('Drupal\Core\Menu\LocalActionInterface');
+    $local_action->expects($this->once())
+      ->method('getTitle')
+      ->with('test');
+
+    $this->controllerResolver->expects($this->once())
+      ->method('getArguments')
+      ->with($this->request, array($local_action, 'getTitle'))
+      ->will($this->returnValue(array('test')));
+
+    $this->localActionManager->getTitle($local_action);
+  }
+
+  /**
+   * @covers \Drupal\Core\Menu\LocalActionManager::getActionsForRoute()
+   *
+   * @dataProvider getActionsForRouteProvider
+   */
+  public function testGetActionsForRoute($route_appears, array $plugin_definitions, array $expected_actions) {
+    $this->discovery->expects($this->any())
+      ->method('getDefinitions')
+      ->will($this->returnValue($plugin_definitions));
+    $map = array();
+    foreach ($plugin_definitions as $plugin_id => $plugin_definition) {
+      $plugin = $this->getMock('Drupal\Core\Menu\LocalActionInterface');
+      $plugin->expects($this->any())
+        ->method('getRouteName')
+        ->will($this->returnValue($plugin_definition['route_name']));
+      $plugin->expects($this->any())
+        ->method('getRouteParameters')
+        ->will($this->returnValue(isset($plugin_definition['route_parameters']) ? $plugin_definition['route_parameters'] : array()));
+      $plugin->expects($this->any())
+        ->method('getTitle')
+        ->will($this->returnValue($plugin_definition['title']));
+      $this->controllerResolver->expects($this->any())
+      ->method('getArguments')
+      ->with($this->request, array($plugin, 'getTitle'))
+      ->will($this->returnValue(array()));
+
+      $plugin->expects($this->any())
+        ->method('getWeight')
+        ->will($this->returnValue($plugin_definition['weight']));
+      $this->controllerResolver->expects($this->any())
+        ->method('getArguments')
+        ->with($this->request, array($plugin, 'getTitle'))
+        ->will($this->returnValue(array()));
+      $map[] = array($plugin_id, array(), $plugin);
+    }
+    $this->factory->expects($this->any())
+      ->method('createInstance')
+      ->will($this->returnValueMap($map));
+
+    $this->assertEquals($expected_actions, $this->localActionManager->getActionsForRoute($route_appears));
+  }
+
+  public function getActionsForRouteProvider() {
+    // Single available and single expected plugins.
+    $data[] = array(
+      'test_route',
+      array(
+        'plugin_id_1' => array(
+          'appears_on' => array(
+            'test_route',
+          ),
+          'route_name' => 'test_route_2',
+          'title' => 'Plugin ID 1',
+          'weight' => 0,
+        ),
+      ),
+      array(
+        'plugin_id_1' => array(
+          '#theme' => 'menu_local_action',
+          '#link' => array(
+            'title' => 'Plugin ID 1',
+            'route_name' => 'test_route_2',
+            'route_parameters' => array(),
+            'localized_options' => '',
+          ),
+          '#access' => NULL,
+          '#weight' => 0,
+        ),
+      ),
+    );
+    // Multiple available and single expected plugins.
+    $data[] = array(
+      'test_route',
+      array(
+        'plugin_id_1' => array(
+          'appears_on' => array(
+            'test_route',
+          ),
+          'route_name' => 'test_route_2',
+          'title' => 'Plugin ID 1',
+          'weight' => 0,
+        ),
+        'plugin_id_2' => array(
+          'appears_on' => array(
+            'test_route2',
+          ),
+          'route_name' => 'test_route_3',
+          'title' => 'Plugin ID 2',
+          'weight' => 0,
+        ),
+      ),
+      array(
+        'plugin_id_1' => array(
+          '#theme' => 'menu_local_action',
+          '#link' => array(
+            'title' => 'Plugin ID 1',
+            'route_name' => 'test_route_2',
+            'route_parameters' => array(),
+            'localized_options' => '',
+          ),
+          '#access' => NULL,
+          '#weight' => 0,
+        ),
+      ),
+    );
+
+    // Multiple available and multiple expected plugins and specified weight.
+    $data[] = array(
+      'test_route',
+      array(
+        'plugin_id_1' => array(
+          'appears_on' => array(
+            'test_route',
+          ),
+          'route_name' => 'test_route_2',
+          'title' => 'Plugin ID 1',
+          'weight' => 1,
+        ),
+        'plugin_id_2' => array(
+          'appears_on' => array(
+            'test_route',
+          ),
+          'route_name' => 'test_route_3',
+          'title' => 'Plugin ID 2',
+          'weight' => 0,
+        ),
+      ),
+      array(
+        'plugin_id_1' => array(
+          '#theme' => 'menu_local_action',
+          '#link' => array(
+            'title' => 'Plugin ID 1',
+            'route_name' => 'test_route_2',
+            'route_parameters' => array(),
+            'localized_options' => '',
+          ),
+          '#access' => NULL,
+          '#weight' => 1,
+        ),
+        'plugin_id_2' => array(
+          '#theme' => 'menu_local_action',
+          '#link' => array(
+            'title' => 'Plugin ID 2',
+            'route_name' => 'test_route_3',
+            'route_parameters' => array(),
+            'localized_options' => '',
+          ),
+          '#access' => NULL,
+          '#weight' => 0,
+        ),
+      ),
+    );
+
+    // Two plugins with the same route name but different route parameters.
+    $data[] = array(
+      'test_route',
+      array(
+        'plugin_id_1' => array(
+          'appears_on' => array(
+            'test_route',
+          ),
+          'route_name' => 'test_route_2',
+          'route_parameters' => array('test1'),
+          'title' => 'Plugin ID 1',
+          'weight' => 1,
+        ),
+        'plugin_id_2' => array(
+          'appears_on' => array(
+            'test_route',
+          ),
+          'route_name' => 'test_route_2',
+          'route_parameters' => array('test2'),
+          'title' => 'Plugin ID 2',
+          'weight' => 0,
+        ),
+      ),
+      array(
+        'plugin_id_1' => array(
+          '#theme' => 'menu_local_action',
+          '#link' => array(
+            'title' => 'Plugin ID 1',
+            'route_name' => 'test_route_2',
+            'route_parameters' => array('test1'),
+            'localized_options' => '',
+          ),
+          '#access' => NULL,
+          '#weight' => 1,
+        ),
+        'plugin_id_2' => array(
+          '#theme' => 'menu_local_action',
+          '#link' => array(
+            'title' => 'Plugin ID 2',
+            'route_name' => 'test_route_2',
+            'route_parameters' => array('test2'),
+            'localized_options' => '',
+          ),
+          '#access' => NULL,
+          '#weight' => 0,
+        ),
+      ),
+    );
+
+    return $data;
+  }
+
+}
+
+class TestLocalActionManager extends LocalActionManager {
+
+  public function __construct(ControllerResolverInterface $controller_resolver, Request $request, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, AccessManager $access_manager, AccountInterface $account, DiscoveryInterface $discovery, FactoryInterface $factory) {
+    $this->discovery = $discovery;
+    $this->factory = $factory;
+    $this->routeProvider = $route_provider;
+    $this->accessManager = $access_manager;
+    $this->account = $account;
+    $this->controllerResolver = $controller_resolver;
+    $this->request = $request;
+    $this->alterInfo($module_handler, 'menu_local_actions');
+    $this->setCacheBackend($cache_backend, $language_manager, 'local_action_plugins', array('local_action' => TRUE));
+  }
+
+}