diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index ae5e9ecd2c0d3b20e04304c7b54f62aa50c878f2..aefa468ce311e2816f52da5f9a6903afb146ed5c 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,6 +1,11 @@
 
 Libraries 8.x-3.x, xxxx-xx-xx
 -----------------------------
+#2825940 by tstoeckler, rjacobs: Remove LibrariesServiceProvider
+#2816115 by rjacobs: Remove ExtensionHandler service
+#2770983 by rjacobs: Update services.yml to reference new registry URL of http://cgit.drupalcode.org/libraries_registry/plain/registry/8
+#2770983 by rjacobs: Update shipped config to reference new registry URL of http://cgit.drupalcode.org/libraries_registry/plain/registry/8
+#2815189 by rjacobs, tstoeckler: Library dependency checking can fail for install profile
 #2770983 by tstoeckler, rjacobs: Fetch definitions remotely and store them locally.
 #2770983 by tstoeckler: Make Libraries API work on Windows.
 #2770983 by tstoeckler: Allow libraries to be symlinked to their right place.
diff --git a/config/install/libraries.settings.yml b/config/install/libraries.settings.yml
index 99af8fd2ed8211ad149c7bb2d6aa445749916fe6..0c0aaf2585ead04aee56b0eabe641ecb0bff5fcc 100644
--- a/config/install/libraries.settings.yml
+++ b/config/install/libraries.settings.yml
@@ -5,4 +5,5 @@ definition:
     path: 'public://library-definitions'
   remote:
     enable: TRUE
-    url: 'http://cgit.drupalcode.org/libraries_registry/plain/registry/8'
+    urls:
+      - 'http://cgit.drupalcode.org/libraries_registry/plain/registry/8'
diff --git a/config/schema/libraries.schema.yml b/config/schema/libraries.schema.yml
index 900b011d293eeca5ce1b6e5f86d458ee9ad1a87f..35af8cb67918d30d2c5354c4304698c9d6f51068 100644
--- a/config/schema/libraries.schema.yml
+++ b/config/schema/libraries.schema.yml
@@ -2,26 +2,29 @@
 
 libraries.settings:
   type: config_object
-  title: 'Libraries API settings'
+  label: 'Libraries API settings'
   mapping:
     definition:
       type: mapping
-      title: 'Library definition settings'
+      label: 'Library definition settings'
       mapping:
         local:
           type: mapping
-          title: 'Local'
+          label: 'Local'
           mapping:
             path:
               type: path
-              title: 'Local path'
+              label: 'Local path'
         remote:
           type: mapping
           title: 'Remote'
           mapping:
             enable:
               type: boolean
-              title: 'Enable remote fetching of library definitions'
-            url:
-              type: uri
-              title: 'The URL of the canonical library registry.'
+              label: 'Enable remote fetching of library definitions'
+            urls:
+              type: sequence
+              label: 'A list of remote library registry URLs'
+              sequence:
+                type: uri
+                label: 'The URL of a remote library registry'
diff --git a/libraries.services.yml b/libraries.services.yml
index 9484f7bd92d3a846722a5accbf46633666462178..b2880ad5724639f929802a12a69d90ca7818599f 100644
--- a/libraries.services.yml
+++ b/libraries.services.yml
@@ -5,22 +5,31 @@ services:
       - '@libraries.definition.discovery'
       - '@plugin.manager.libraries.library_type'
 
-  # These services are modified depending on the values of the
-  # 'libraries.settings' configuration object. See LibrariesServiceProvider.
+  # By default Libraries API downloads library definitions from a number of
+  # remote library registries, the canonical one being
+  # https://www.drupal.org/project/libraries_registry, and stores them locally
+  # in the public://library-definitions directory. The URLs of the remote
+  # library registries and the local base path can be configured. The remote
+  # fetching can also be disabled altogether.
   libraries.definition.discovery:
-    class: Drupal\libraries\ExternalLibrary\Definition\ChainDefinitionDiscovery
-    arguments: ['@serialization.yaml']
-    calls:
-      - [addDiscovery, ['@libraries.definition.discovery.local']]
-  libraries.definition.discovery.local:
-    class: Drupal\libraries\ExternalLibrary\Definition\WritableFileDefinitionDiscovery
-    arguments: ['@serialization.yaml', 'public://library-definitions']
-  libraries.definition.discovery.remote:
-    class: Drupal\libraries\ExternalLibrary\Definition\GuzzleDefinitionDiscovery
+    class: Drupal\libraries\ExternalLibrary\Definition\DefinitionDiscoveryInterface
+    factory: 'libraries.definition.discovery.factory:get'
+  libraries.definition.discovery.factory:
+    class: Drupal\libraries\ExternalLibrary\Definition\DefinitionDiscoveryFactory
     arguments:
+      - '@config.factory'
+      - '@serialization.json'
       - '@http_client'
       - '@serialization.json'
-      - 'http://cgit.drupalcode.org/libraries_registry/plain/registry/8'
+  # If you instead want to check your library definitions into version control
+  # and use YAML for them instead of JSON, you can place the following service
+  # definition in your site's services.yml file:
+  # libraries.definition.discovery:
+  #   class: Drupal\libraries\ExternalLibrary\Definition\FileDefinitionDiscovery
+  #   arguments:
+  #     - '@serialization.yaml'
+  #     # Replace this with the location of the library definitions in your setup.
+  #     - '../library-definitions'
 
   plugin.manager.libraries.library_type:
     class: Drupal\libraries\ExternalLibrary\Type\LibraryTypeFactory
@@ -34,7 +43,7 @@ services:
 
   libraries.config_subscriber:
     class: Drupal\libraries\Config\LibrariesConfigSubscriber
-    arguments: ['@kernel']
+    arguments: ['@service_container']
     tags:
       - { name: event_subscriber }
 
diff --git a/src/Config/LibrariesConfigSubscriber.php b/src/Config/LibrariesConfigSubscriber.php
index 09a1752de69d72f7b395a74d7c392b2fdcd8ad5c..6578f42c6d6eaae190575fb48d42832ad92f28bf 100644
--- a/src/Config/LibrariesConfigSubscriber.php
+++ b/src/Config/LibrariesConfigSubscriber.php
@@ -4,7 +4,7 @@ namespace Drupal\libraries\Config;
 
 use Drupal\Core\Config\ConfigCrudEvent;
 use Drupal\Core\Config\ConfigEvents;
-use Drupal\Core\DrupalKernelInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 
 /**
@@ -13,31 +13,31 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 class LibrariesConfigSubscriber implements EventSubscriberInterface {
 
   /**
-   * The Drupal kernel.
+   * The service container.
    *
-   * @var \Drupal\Core\DrupalKernelInterface
+   * @var \Symfony\Component\DependencyInjection\ContainerInterface
    */
-  protected $kernel;
+  protected $container;
 
   /**
    * Constructs a Libraries API configuration subscriber.
    *
-   * @param \Drupal\Core\DrupalKernelInterface $kernel
-   *   The Drupal kernel.
+   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
+   *   The service container.
    */
-  public function __construct(DrupalKernelInterface $kernel) {
-    $this->kernel = $kernel;
+  public function __construct(ContainerInterface $container) {
+    $this->container = $container;
   }
 
   /**
-   * Invalidates the container when the definition settings are updated.
+   * Unsets the definition discovery service when its configuration changes.
    *
    * @param \Drupal\Core\Config\ConfigCrudEvent $event
    *   The configuration event.
    */
   public function onConfigSave(ConfigCrudEvent $event) {
     if (($event->getConfig()->getName() === 'libraries.settings') && $event->isChanged('definition')) {
-      $this->kernel->invalidateContainer();
+      $this->container->set('libraries.definition.discovery', NULL);
     }
   }
 
diff --git a/src/ExternalLibrary/Definition/DefinitionDiscoveryFactory.php b/src/ExternalLibrary/Definition/DefinitionDiscoveryFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..970385e5f0ebacd40ab50952b84a55377207bd70
--- /dev/null
+++ b/src/ExternalLibrary/Definition/DefinitionDiscoveryFactory.php
@@ -0,0 +1,104 @@
+<?php
+
+namespace Drupal\libraries\ExternalLibrary\Definition;
+
+use Drupal\Component\Serialization\SerializationInterface;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use GuzzleHttp\ClientInterface;
+
+/**
+ * Instantiates a library definition discovery based on configuration.
+ */
+class DefinitionDiscoveryFactory {
+
+  /**
+   * The configuration factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * The serializer for local definition files.
+   *
+   * @var \Drupal\Component\Serialization\SerializationInterface
+   */
+  protected $localSerializer;
+
+  /**
+   * The HTTP client used to fetch remote definitions.
+   *
+   * @var \GuzzleHttp\ClientInterface
+   */
+  protected $httpClient;
+
+  /**
+   * The serializer for remote definitions.
+   *
+   * @var \Drupal\Component\Serialization\SerializationInterface
+   */
+  protected $remoteSerializer;
+
+  /**
+   * Constructs a definition discovery factory.
+   *
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The configuration factory.
+   * @param \Drupal\Component\Serialization\SerializationInterface $local_serializer
+   *   The serializer for local definition files.
+   * @param \GuzzleHttp\ClientInterface $http_client
+   *   The HTTP client used to fetch remote definitions.
+   * @param \Drupal\Component\Serialization\SerializationInterface $remote_serializer
+   *   The serializer for remote definitions.
+   */
+  public function __construct(
+    ConfigFactoryInterface $config_factory,
+    SerializationInterface $local_serializer,
+    ClientInterface $http_client,
+    SerializationInterface $remote_serializer
+  ) {
+    $this->configFactory = $config_factory;
+    $this->localSerializer = $local_serializer;
+    $this->httpClient = $http_client;
+    $this->remoteSerializer = $remote_serializer;
+  }
+
+  /**
+   * Gets a library definition discovery.
+   *
+   * @return \Drupal\libraries\ExternalLibrary\Definition\DefinitionDiscoveryInterface
+   *   The library definition discovery.
+   */
+  public function get() {
+    $config = $this->configFactory->get('libraries.settings');
+
+    if ($config->get('definition.remote.enable')) {
+      $discovery = new ChainDefinitionDiscovery();
+
+      $local_discovery = new WritableFileDefinitionDiscovery(
+        $this->localSerializer,
+        $config->get('definition.local.path')
+      );
+      $discovery->addDiscovery($local_discovery);
+
+      foreach ($config->get('definition.remote.urls') as $remote_url) {
+        $remote_discovery = new GuzzleDefinitionDiscovery(
+          $this->httpClient,
+          $this->remoteSerializer,
+          $remote_url
+        );
+
+        $discovery->addDiscovery($remote_discovery);
+      }
+    }
+    else {
+      $discovery = new FileDefinitionDiscovery(
+        $this->localSerializer,
+        $config->get('definition.local.path')
+      );
+    }
+
+    return $discovery;
+  }
+
+}
diff --git a/src/ExternalLibrary/Definition/GuzzleDefinitionDiscovery.php b/src/ExternalLibrary/Definition/GuzzleDefinitionDiscovery.php
index e3fa7c13672a873bdb3d87be12c03ab52b2711fd..59745b78c7fbd6523287da0bce6f14ce601d7f22 100644
--- a/src/ExternalLibrary/Definition/GuzzleDefinitionDiscovery.php
+++ b/src/ExternalLibrary/Definition/GuzzleDefinitionDiscovery.php
@@ -58,7 +58,7 @@ class GuzzleDefinitionDiscovery extends FileDefinitionDiscoveryBase implements D
   protected function getSerializedDefinition($id) {
     try {
       $response = $this->httpClient->request('GET', $this->getFileUri($id));
-      return $response->getBody()->getContents();
+      return (string) $response->getBody();
     }
     catch (GuzzleException $exception) {
       throw new LibraryDefinitionNotFoundException($id, '', 0, $exception);
diff --git a/src/LibrariesServiceProvider.php b/src/LibrariesServiceProvider.php
deleted file mode 100644
index e747336456716166e7838f7b6ac82ae0f28abd29..0000000000000000000000000000000000000000
--- a/src/LibrariesServiceProvider.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-
-namespace Drupal\libraries;
-
-use Drupal\Core\DependencyInjection\ContainerBuilder;
-use Drupal\Core\DependencyInjection\ServiceModifierInterface;
-use Symfony\Component\DependencyInjection\Reference;
-
-/**
- * Modifies Libraries API services based on configuration.
- */
-class LibrariesServiceProvider implements ServiceModifierInterface {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function alter(ContainerBuilder $container) {
-    if ($container->has('config.factory')) {
-      // The configuration factory depends on the cache factory, but that
-      // depends on the 'cache_default_bin_backends' parameter that has not yet
-      // been set by \Drupal\Core\Cache\ListCacheBinsPass::process() at this
-      // point.
-      $parameter_name = 'cache_default_bin_backends';
-      if (!$container->hasParameter($parameter_name)) {
-        $container->setParameter($parameter_name, []);
-      }
-
-      /** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */
-      $config_factory = $container->get('config.factory');
-
-      $config = $config_factory->get('libraries.settings');
-      if (!$config->isNew()) {
-        // Set the local definition path.
-        $container
-          ->getDefinition('libraries.definition.discovery.local')
-          ->replaceArgument(1, $config->get('definition.local.path'));
-
-        // Set the remote definition URL. Note that this is set even if
-        // the remote discovery is not enabled below in case the
-        // 'libraries.definition.discovery.remote' service is used explicitly.
-        $container
-          ->getDefinition('libraries.definition.discovery.remote')
-          ->replaceArgument(2, $config->get('definition.remote.url'));
-
-        // Because it is less convenient to remove a method call than to add
-        // one, the remote discovery is not registered in libraries.services.yml
-        // and instead added here, even though the 'definition.remote.enable'
-        // configuration value is TRUE by default.
-        if ($config->get('definition.remote.enable')) {
-          // Add the remote discovery to the list of chained discoveries.
-          $container
-            ->getDefinition('libraries.definition.discovery')
-            ->addMethodCall('addDiscovery', [new Reference('libraries.definition.discovery.remote')]);
-        }
-      }
-
-      // At this point the event dispatcher has not yet been populated with
-      // event subscribers by RegisterEventSubscribersPass::process() but has
-      // already bin injected in the configuration factory. Reset those services
-      // accordingly.
-      $container->set('event_dispatcher', NULL);
-      $container->set('config.factory', NULL);
-    }
-  }
-
-}
diff --git a/src/StreamWrapper/LibraryDefinitionsStream.php b/src/StreamWrapper/LibraryDefinitionsStream.php
index 642a591044700b3dceaf9abfb81a320c21510702..7cf0764ec0c75d3cd9cc2d0384c15f395c2811cd 100644
--- a/src/StreamWrapper/LibraryDefinitionsStream.php
+++ b/src/StreamWrapper/LibraryDefinitionsStream.php
@@ -8,7 +8,7 @@ use Drupal\Core\StreamWrapper\LocalStream;
  * Provides a stream wrapper for library definitions.
  *
  * Can be used with the 'library-definitions' scheme, for example
- * 'library-definitions://example.yml' for a library ID of 'example'.
+ * 'library-definitions://example.json' for a library ID of 'example'.
  *
  * By default this stream wrapper reads from a single directory that is
  * configurable and points to the 'library-definitions' directory within the
diff --git a/tests/library_definitions/test_asset_library.yml b/tests/library_definitions/test_asset_library.yml
deleted file mode 100644
index 4c712e6064dc99358aa4d4260153f1a3895fbde3..0000000000000000000000000000000000000000
--- a/tests/library_definitions/test_asset_library.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-type: asset
-version_detector:
-  id: static
-  configuration:
-    version: '1.0.0'
-remote_url: http://example.com
-css:
-  base:
-    example.css: {  }
-js:
-  example.js: {  }
diff --git a/tests/library_definitions/test_asset_multiple_library.yml b/tests/library_definitions/test_asset_multiple_library.yml
deleted file mode 100644
index 093e9c830c9c56eb6ccfa75e00583f67683f9a25..0000000000000000000000000000000000000000
--- a/tests/library_definitions/test_asset_multiple_library.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-type: asset_multiple
-version_detector:
-  id: static
-  configuration:
-    version: '1.0.0'
-remote_url: http://example.com
-libraries:
-  first:
-    css:
-      base:
-        example.first.css: {  }
-    js:
-      example.first.js: {  }
-  second:
-    css:
-      base:
-        example.second.css: {  }
-    js:
-      example.second.js: {  }
diff --git a/tests/library_definitions/test_php_file_library.yml b/tests/library_definitions/test_php_file_library.yml
deleted file mode 100644
index ced08c5d16c88913715dfef520ecabd1e3130114..0000000000000000000000000000000000000000
--- a/tests/library_definitions/test_php_file_library.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-type: php_file
-files: [test_php_file_library.php]
diff --git a/tests/src/Functional/ExternalLibrary/Definition/ChainDefinitionDiscoveryTest.php b/tests/src/Functional/ExternalLibrary/Definition/ChainDefinitionDiscoveryTest.php
deleted file mode 100644
index 321391974d0917be6a758d2eeb99a46f1904e1f4..0000000000000000000000000000000000000000
--- a/tests/src/Functional/ExternalLibrary/Definition/ChainDefinitionDiscoveryTest.php
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-
-namespace Drupal\Tests\libraries\Functional\ExternalLibrary\Definition;
-
-use Drupal\Tests\BrowserTestBase;
-
-/**
- * Tests that remote library definitions are found and downloaded.
- *
- * This is a browser test because Guzzle is not usable from a kernel test.
- *
- * @group libraries
- *
- * @todo Make this a kernel test when https://www.drupal.org/node/2571475 is in.
- */
-class ChainDefinitionDiscoveryTest extends BrowserTestBase {
-
-  /**
-   * The chained library definition discovery.
-   *
-   * @var \Drupal\libraries\ExternalLibrary\Definition\DefinitionDiscoveryInterface
-   */
-  protected $discovery;
-
-  /**
-   * The local library definition discovery.
-   *
-   * @var \Drupal\libraries\ExternalLibrary\Definition\DefinitionDiscoveryInterface
-   */
-  protected $localDiscovery;
-
-  /**
-   * The remote library definition discovery.
-   *
-   * @var \Drupal\libraries\ExternalLibrary\Definition\DefinitionDiscoveryInterface
-   */
-  protected $remoteDiscovery;
-
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = ['libraries'];
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    /** @var \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */
-    $module_handler = $this->container->get('module_handler');
-    /** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */
-    $config_factory = $this->container->get('config.factory');
-
-    // Set up the remote library definition URL to point to the local website.
-    $base_url = getenv('SIMPLETEST_BASE_URL');
-    $module_path = $module_handler->getModule('libraries')->getPath();
-    $url = "$base_url/$module_path/tests/library_definitions";
-    $config_factory->getEditable('libraries.settings')
-      ->set('definition.remote.url', $url)
-      ->save();
-    // LibrariesConfigSubscriber::onConfigSave() invalidates the container so
-    // that it is rebuilt on the next request. We need the container rebuilt
-    // immediately, however.
-    $this->rebuildContainer();
-
-    $this->discovery = $this->container->get('libraries.definition.discovery');
-    $this->localDiscovery = $this->container->get('libraries.definition.discovery.local');
-    $this->remoteDiscovery = $this->container->get('libraries.definition.discovery.remote');
-  }
-
-  /**
-   * Tests that remote definitions are written locally.
-   */
-  public function testRemoteFetching() {
-    $library_id = 'test_asset_library';
-    $expected_definition = [
-      'type' => 'asset',
-      'version_detector' => [
-        'id' => 'static',
-        'configuration' => [
-          'version' => '1.0.0'
-        ],
-      ],
-      'remote_url' => 'http://example.com',
-      'css' => [
-        'base' => [
-          'example.css' => [],
-        ],
-      ],
-      'js' => [
-        'example.js' => [],
-      ],
-    ];
-
-    $this->assertFalse($this->localDiscovery->hasDefinition($library_id));
-    $this->assertTrue($this->remoteDiscovery->hasDefinition($library_id));
-    $this->assertEquals($this->remoteDiscovery->getDefinition($library_id), $expected_definition);
-
-    $this->assertTrue($this->discovery->hasDefinition($library_id));
-    $this->assertEquals($this->discovery->getDefinition($library_id), $expected_definition);
-
-    $this->assertTrue($this->localDiscovery->hasDefinition($library_id));
-    $this->assertEquals($this->localDiscovery->getDefinition($library_id), $expected_definition);
-  }
-
-}
diff --git a/tests/src/Functional/ExternalLibrary/Definition/DefinitionDiscoveryFactoryTest.php b/tests/src/Functional/ExternalLibrary/Definition/DefinitionDiscoveryFactoryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..14bf74e4f6ecfbbd5e1a7a693c4a88349af084be
--- /dev/null
+++ b/tests/src/Functional/ExternalLibrary/Definition/DefinitionDiscoveryFactoryTest.php
@@ -0,0 +1,118 @@
+<?php
+
+namespace Drupal\Tests\libraries\Functional\ExternalLibrary\Definition;
+
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests that remote library definitions are found and downloaded.
+ *
+ * This is a browser test because Guzzle is not usable from a kernel test.
+ *
+ * @group libraries
+ *
+ * @todo Make this a kernel test when https://www.drupal.org/node/2571475 is in.
+ */
+class DefinitionDiscoveryFactoryTest extends BrowserTestBase {
+
+  /**
+   * The 'libraries.settings' configuration object.
+   *
+   * @var \Drupal\Core\Config\Config
+   */
+  protected $config;
+
+  /**
+   * The path to the test library definitions.
+   *
+   * @var string
+   */
+  protected $definitionPath;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['libraries'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    /** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */
+    $config_factory = $this->container->get('config.factory');
+    $this->config = $config_factory->getEditable('libraries.settings');
+
+    // Set up the remote library definition URL to point to the local website.
+    /** @var \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */
+    $module_handler = $this->container->get('module_handler');
+    $module_path = $module_handler->getModule('libraries')->getPath();
+    $this->definitionPath = "$module_path/tests/library_definitions";
+  }
+
+  /**
+   * Tests that the discovery works according to the configuration.
+   */
+  public function testDiscovery() {
+    $library_id = 'test_asset_library';
+    $expected_definition = [
+      'type' => 'asset',
+      'version_detector' => [
+        'id' => 'static',
+        'configuration' => [
+          'version' => '1.0.0'
+        ],
+      ],
+      'remote_url' => 'http://example.com',
+      'css' => [
+        'base' => [
+          'example.css' => [],
+        ],
+      ],
+      'js' => [
+        'example.js' => [],
+      ],
+    ];
+    $discovery_service_id = 'libraries.definition.discovery';
+
+    // Test the local discovery with an incorrect path.
+    $this->config
+      ->set('definition.local.path', 'path/that/does/not/exist')
+      ->set('definition.remote.enable', FALSE)
+      ->save();
+    $discovery = $this->container->get($discovery_service_id);
+    $this->assertFalse($discovery->hasDefinition($library_id));
+
+    // Test the local discovery with a proper path.
+    $this->config
+      ->set('definition.local.path', $this->definitionPath)
+      ->save();
+    $discovery = $this->container->get($discovery_service_id);
+    $this->assertTrue($discovery->hasDefinition($library_id));
+
+    // Test a remote discovery with an incorrect path.
+    $definitions_directory = 'public://library-definitions';
+    $this->config
+      ->set('definition.local.path', $definitions_directory)
+      ->set('definition.remote.enable', TRUE)
+      ->set('definition.remote.urls', ["$this->baseUrl/path/that/does/not/exist"])
+      ->save();
+    $discovery = $this->container->get($discovery_service_id);
+    $this->assertFalse($discovery->hasDefinition($library_id));
+
+    // Test a remote discovery with a proper path.
+    $this->config
+      ->set('definition.remote.urls', ["$this->baseUrl/$this->definitionPath"])
+      ->save();
+    /** @var \Drupal\libraries\ExternalLibrary\Definition\DefinitionDiscoveryInterface $discovery */
+    $discovery = $this->container->get($discovery_service_id);
+    $definition_file = "$definitions_directory/$library_id.json";
+    $this->assertFalse(file_exists($definition_file));
+    $this->assertTrue($discovery->hasDefinition($library_id));
+    $this->assertFalse(file_exists($definition_file));
+    $this->assertEquals($discovery->getDefinition($library_id), $expected_definition);
+    $this->assertTrue(file_exists($definition_file));
+  }
+
+}