From cfefb099255acc516258fa34a26a28de07e78de5 Mon Sep 17 00:00:00 2001
From: "kunal.sachdev" <kunal.sachdev@3685163.no-reply.drupal.org>
Date: Tue, 5 Oct 2021 15:21:58 +0000
Subject: [PATCH] Issue #3236299 by kunal.sachdev, phenaproxima, Suresh Prabhu
 Parkala, tedbow: User should not be allowed to do update if it is from minor
 version to another minor version

---
 automatic_updates.services.yml                |  2 +-
 src/Event/PackagesAwareTrait.php              | 38 +++++++++++++++++++
 src/Event/PreStartEvent.php                   | 29 +-------------
 src/Event/ReadinessCheckEvent.php             | 12 ++++++
 src/Validation/ReadinessValidationManager.php | 26 +++++++++++--
 src/Validator/UpdateVersionValidator.php      | 22 +++++++++--
 ...upal.0.0.xml => drupal.9.8.1-security.xml} |  0
 .../fixtures/release-history/drupal.9.8.1.xml | 38 +++++++++++++++++++
 tests/src/Build/CoreUpdateTest.php            |  2 +-
 .../AutomaticUpdatesFunctionalTestBase.php    | 11 ++++++
 .../Functional/FileSystemOperationsTest.php   |  6 ++-
 .../Functional/ReadinessValidationTest.php    | 17 ++++++---
 tests/src/Functional/UpdaterFormTest.php      | 35 +++++++++--------
 .../Kernel/AutomaticUpdatesKernelTestBase.php | 30 ++++++++++++++-
 .../ComposerExecutableValidatorTest.php       | 15 ++++++--
 .../ReadinessValidationManagerTest.php        | 14 ++++---
 tests/src/Kernel/UpdateRecommenderTest.php    |  3 +-
 tests/src/Kernel/UpdaterTest.php              |  3 +-
 18 files changed, 231 insertions(+), 72 deletions(-)
 create mode 100644 src/Event/PackagesAwareTrait.php
 create mode 100644 src/Event/ReadinessCheckEvent.php
 rename tests/fixtures/release-history/{drupal.0.0.xml => drupal.9.8.1-security.xml} (100%)
 create mode 100644 tests/fixtures/release-history/drupal.9.8.1.xml

diff --git a/automatic_updates.services.yml b/automatic_updates.services.yml
index 42613c5f9c..69c6156569 100644
--- a/automatic_updates.services.yml
+++ b/automatic_updates.services.yml
@@ -1,7 +1,7 @@
 services:
   automatic_updates.readiness_validation_manager:
     class: Drupal\automatic_updates\Validation\ReadinessValidationManager
-    arguments: ['@keyvalue.expirable', '@datetime.time','@event_dispatcher', 24]
+    arguments: ['@keyvalue.expirable', '@datetime.time', '@automatic_updates.updater', '@event_dispatcher', 24]
   automatic_updates.updater:
     class: Drupal\automatic_updates\Updater
     arguments: ['@state', '@string_translation','@package_manager.beginner', '@package_manager.stager', '@package_manager.cleaner', '@package_manager.committer', '@event_dispatcher', '@automatic_updates.path_locator']
diff --git a/src/Event/PackagesAwareTrait.php b/src/Event/PackagesAwareTrait.php
new file mode 100644
index 0000000000..2462b217ef
--- /dev/null
+++ b/src/Event/PackagesAwareTrait.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Drupal\automatic_updates\Event;
+
+/**
+ * Common functionality for events which can carry desired package versions.
+ */
+trait PackagesAwareTrait {
+
+  /**
+   * The desired package versions to update to, keyed by package name.
+   *
+   * @var string[]
+   */
+  protected $packageVersions;
+
+  /**
+   * Constructs a PreStartEvent.
+   *
+   * @param string[] $package_versions
+   *   (optional) The desired package versions to update to, keyed by package
+   *   name.
+   */
+  public function __construct(array $package_versions = []) {
+    $this->packageVersions = $package_versions;
+  }
+
+  /**
+   * Returns the desired package versions to update to.
+   *
+   * @return string[]
+   *   The desired package versions to update to, keyed by package name.
+   */
+  public function getPackageVersions(): array {
+    return $this->packageVersions;
+  }
+
+}
diff --git a/src/Event/PreStartEvent.php b/src/Event/PreStartEvent.php
index f5b32b9f4d..a58b422eda 100644
--- a/src/Event/PreStartEvent.php
+++ b/src/Event/PreStartEvent.php
@@ -8,33 +8,6 @@ namespace Drupal\automatic_updates\Event;
 class PreStartEvent extends UpdateEvent {
 
   use ExcludedPathsTrait;
-
-  /**
-   * The desired package versions to update to, keyed by package name.
-   *
-   * @var string[]
-   */
-  protected $packageVersions;
-
-  /**
-   * Constructs a PreStartEvent.
-   *
-   * @param string[] $package_versions
-   *   (optional) The desired package versions to update to, keyed by package
-   *   name.
-   */
-  public function __construct(array $package_versions = []) {
-    $this->packageVersions = $package_versions;
-  }
-
-  /**
-   * Returns the desired package versions to update to.
-   *
-   * @return string[]
-   *   The desired package versions to update to, keyed by package name.
-   */
-  public function getPackageVersions(): array {
-    return $this->packageVersions;
-  }
+  use PackagesAwareTrait;
 
 }
diff --git a/src/Event/ReadinessCheckEvent.php b/src/Event/ReadinessCheckEvent.php
new file mode 100644
index 0000000000..862a4581ca
--- /dev/null
+++ b/src/Event/ReadinessCheckEvent.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace Drupal\automatic_updates\Event;
+
+/**
+ * Event fired when checking if the site could perform an update.
+ */
+class ReadinessCheckEvent extends UpdateEvent {
+
+  use PackagesAwareTrait;
+
+}
diff --git a/src/Validation/ReadinessValidationManager.php b/src/Validation/ReadinessValidationManager.php
index e577c17d33..411fb59beb 100644
--- a/src/Validation/ReadinessValidationManager.php
+++ b/src/Validation/ReadinessValidationManager.php
@@ -3,7 +3,9 @@
 namespace Drupal\automatic_updates\Validation;
 
 use Drupal\automatic_updates\AutomaticUpdatesEvents;
-use Drupal\automatic_updates\Event\UpdateEvent;
+use Drupal\automatic_updates\Event\ReadinessCheckEvent;
+use Drupal\automatic_updates\Updater;
+use Drupal\automatic_updates\UpdateRecommender;
 use Drupal\Component\Datetime\TimeInterface;
 use Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface;
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -41,6 +43,13 @@ class ReadinessValidationManager {
    */
   protected $resultsTimeToLive;
 
+  /**
+   * The updater service.
+   *
+   * @var \Drupal\automatic_updates\Updater
+   */
+  protected $updater;
+
   /**
    * Constructs a ReadinessValidationManager.
    *
@@ -48,14 +57,17 @@ class ReadinessValidationManager {
    *   The key/value expirable factory.
    * @param \Drupal\Component\Datetime\TimeInterface $time
    *   The time service.
+   * @param \Drupal\automatic_updates\Updater $updater
+   *   The updater service.
    * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
    *   The event dispatcher service.
    * @param int $results_time_to_live
    *   The number of hours to store results.
    */
-  public function __construct(KeyValueExpirableFactoryInterface $key_value_expirable_factory, TimeInterface $time, EventDispatcherInterface $dispatcher, int $results_time_to_live) {
+  public function __construct(KeyValueExpirableFactoryInterface $key_value_expirable_factory, TimeInterface $time, Updater $updater, EventDispatcherInterface $dispatcher, int $results_time_to_live) {
     $this->keyValueExpirable = $key_value_expirable_factory->get('automatic_updates');
     $this->time = $time;
+    $this->updater = $updater;
     $this->eventDispatcher = $dispatcher;
     $this->resultsTimeToLive = $results_time_to_live;
   }
@@ -66,7 +78,15 @@ class ReadinessValidationManager {
    * @return $this
    */
   public function run(): self {
-    $event = new UpdateEvent();
+    $recommender = new UpdateRecommender();
+    $release = $recommender->getRecommendedRelease(TRUE);
+    if ($release) {
+      $package_versions = [$this->updater->getCorePackageName() => $release->getVersion()];
+    }
+    else {
+      $package_versions = [];
+    }
+    $event = new ReadinessCheckEvent($package_versions);
     $this->eventDispatcher->dispatch($event, AutomaticUpdatesEvents::READINESS_CHECK);
     $results = $event->getResults();
     $this->keyValueExpirable->setWithExpire(
diff --git a/src/Validator/UpdateVersionValidator.php b/src/Validator/UpdateVersionValidator.php
index bbbcc5f8ef..cf113191f7 100644
--- a/src/Validator/UpdateVersionValidator.php
+++ b/src/Validator/UpdateVersionValidator.php
@@ -3,7 +3,8 @@
 namespace Drupal\automatic_updates\Validator;
 
 use Drupal\automatic_updates\AutomaticUpdatesEvents;
-use Drupal\automatic_updates\Event\PreStartEvent;
+use Drupal\automatic_updates\Event\ReadinessCheckEvent;
+use Drupal\automatic_updates\Event\UpdateEvent;
 use Drupal\automatic_updates\Updater;
 use Drupal\automatic_updates\Validation\ValidationResult;
 use Drupal\Core\Extension\ExtensionVersion;
@@ -52,10 +53,10 @@ class UpdateVersionValidator implements EventSubscriberInterface {
   /**
    * Validates that core is not being updated to another minor or major version.
    *
-   * @param \Drupal\automatic_updates\Event\PreStartEvent $event
+   * @param \Drupal\automatic_updates\Event\PreStartEvent|\Drupal\automatic_updates\Event\ReadinessCheckEvent $event
    *   The event object.
    */
-  public function checkUpdateVersion(PreStartEvent $event): void {
+  public function checkUpdateVersion(UpdateEvent $event): void {
     $from_version = ExtensionVersion::createFromVersionString($this->getCoreVersion());
     $core_package_name = $this->updater->getCorePackageName();
     $to_version = ExtensionVersion::createFromVersionString($event->getPackageVersions()[$core_package_name]);
@@ -74,12 +75,27 @@ class UpdateVersionValidator implements EventSubscriberInterface {
     }
   }
 
+  /**
+   * Validates readiness check event.
+   *
+   * @param \Drupal\automatic_updates\Event\ReadinessCheckEvent $event
+   *   The readiness check event object.
+   */
+  public function checkReadinessUpdateVersion(ReadinessCheckEvent $event): void {
+    // During readiness checks, we might not know the desired package versions,
+    // which means there's nothing to validate.
+    if ($event->getPackageVersions()) {
+      $this->checkUpdateVersion($event);
+    }
+  }
+
   /**
    * {@inheritdoc}
    */
   public static function getSubscribedEvents() {
     return [
       AutomaticUpdatesEvents::PRE_START => 'checkUpdateVersion',
+      AutomaticUpdatesEvents::READINESS_CHECK => 'checkReadinessUpdateVersion',
     ];
   }
 
diff --git a/tests/fixtures/release-history/drupal.0.0.xml b/tests/fixtures/release-history/drupal.9.8.1-security.xml
similarity index 100%
rename from tests/fixtures/release-history/drupal.0.0.xml
rename to tests/fixtures/release-history/drupal.9.8.1-security.xml
diff --git a/tests/fixtures/release-history/drupal.9.8.1.xml b/tests/fixtures/release-history/drupal.9.8.1.xml
new file mode 100644
index 0000000000..4d5268378e
--- /dev/null
+++ b/tests/fixtures/release-history/drupal.9.8.1.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<project xmlns:dc="http://purl.org/dc/elements/1.1/">
+<title>Drupal</title>
+<short_name>drupal</short_name>
+<dc:creator>Drupal</dc:creator>
+<supported_branches>9.8.</supported_branches>
+<project_status>published</project_status>
+<link>http://example.com/project/drupal</link>
+  <terms>
+   <term><name>Projects</name><value>Drupal project</value></term>
+  </terms>
+<releases>
+ <release>
+  <name>Drupal 9.8.1</name>
+  <version>9.8.1</version>
+  <status>published</status>
+  <release_link>http://example.com/drupal-9-8-1-release</release_link>
+  <download_link>http://example.com/drupal-9-8-1.tar.gz</download_link>
+  <date>1250425521</date>
+  <terms>
+    <term><name>Release type</name><value>New features</value></term>
+    <term><name>Release type</name><value>Bug fixes</value></term>
+  </terms>
+ </release>
+ <release>
+   <name>Drupal 9.8.0</name>
+   <version>9.8.0</version>
+   <status>published</status>
+   <release_link>http://example.com/drupal-9-8-0-release</release_link>
+   <download_link>http://example.com/drupal-9-8-0.tar.gz</download_link>
+   <date>1250424521</date>
+   <terms>
+     <term><name>Release type</name><value>New features</value></term>
+     <term><name>Release type</name><value>Bug fixes</value></term>
+   </terms>
+ </release>
+</releases>
+</project>
diff --git a/tests/src/Build/CoreUpdateTest.php b/tests/src/Build/CoreUpdateTest.php
index c65ee9933d..323a6b5498 100644
--- a/tests/src/Build/CoreUpdateTest.php
+++ b/tests/src/Build/CoreUpdateTest.php
@@ -26,7 +26,7 @@ class CoreUpdateTest extends UpdateTestBase {
     // Install Drupal and ensure it's using the fake release metadata to fetch
     // information about available updates.
     $this->installQuickStart('minimal');
-    $this->setReleaseMetadata(['drupal' => '0.0']);
+    $this->setReleaseMetadata(['drupal' => '9.8.1-security']);
     $this->formLogin($this->adminUsername, $this->adminPassword);
     $this->installModules([
       'automatic_updates',
diff --git a/tests/src/Functional/AutomaticUpdatesFunctionalTestBase.php b/tests/src/Functional/AutomaticUpdatesFunctionalTestBase.php
index b55aed5bba..1bc7feb93c 100644
--- a/tests/src/Functional/AutomaticUpdatesFunctionalTestBase.php
+++ b/tests/src/Functional/AutomaticUpdatesFunctionalTestBase.php
@@ -45,4 +45,15 @@ abstract class AutomaticUpdatesFunctionalTestBase extends BrowserTestBase {
       ->save();
   }
 
+  /**
+   * Checks for available updates.
+   *
+   * Assumes that a user with appropriate permissions is logged in.
+   */
+  protected function checkForUpdates(): void {
+    $this->drupalGet('/admin/reports/updates');
+    $this->getSession()->getPage()->clickLink('Check manually');
+    $this->checkForMetaRefresh();
+  }
+
 }
diff --git a/tests/src/Functional/FileSystemOperationsTest.php b/tests/src/Functional/FileSystemOperationsTest.php
index 1347ceb3b4..5fce64a386 100644
--- a/tests/src/Functional/FileSystemOperationsTest.php
+++ b/tests/src/Functional/FileSystemOperationsTest.php
@@ -90,8 +90,12 @@ class FileSystemOperationsTest extends AutomaticUpdatesFunctionalTestBase {
     // \Drupal\automatic_updates\Validator\UpdateVersionValidator, that need to
     // fetch release metadata. We need to ensure that those HTTP request(s)
     // succeed, so set them up to point to our fake release metadata.
-    $this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/drupal.0.0.xml');
+    $this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/drupal.9.8.1-security.xml');
     $this->setCoreVersion('9.8.0');
+
+    $this->drupalLogin($this->rootUser);
+    $this->checkForUpdates();
+    $this->drupalLogout();
   }
 
   /**
diff --git a/tests/src/Functional/ReadinessValidationTest.php b/tests/src/Functional/ReadinessValidationTest.php
index 181f731a3d..999067ce79 100644
--- a/tests/src/Functional/ReadinessValidationTest.php
+++ b/tests/src/Functional/ReadinessValidationTest.php
@@ -8,7 +8,6 @@ use Drupal\automatic_updates_test2\ReadinessChecker\TestChecker2;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\system\SystemManager;
 use Drupal\Tests\automatic_updates\Traits\ValidationTestTrait;
-use Drupal\Tests\BrowserTestBase;
 use Drupal\Tests\Traits\Core\CronRunTrait;
 
 /**
@@ -16,7 +15,7 @@ use Drupal\Tests\Traits\Core\CronRunTrait;
  *
  * @group automatic_updates
  */
-class ReadinessValidationTest extends BrowserTestBase {
+class ReadinessValidationTest extends AutomaticUpdatesFunctionalTestBase {
 
   use StringTranslationTrait;
   use CronRunTrait;
@@ -53,6 +52,9 @@ class ReadinessValidationTest extends BrowserTestBase {
    */
   protected function setUp(): void {
     parent::setUp();
+    $this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/drupal.9.8.1.xml');
+    $this->setCoreVersion('9.8.1');
+
     $this->reportViewerUser = $this->createUser([
       'administer site configuration',
       'access administration pages',
@@ -81,6 +83,7 @@ class ReadinessValidationTest extends BrowserTestBase {
     // If the site is ready for updates, the users will see the same output
     // regardless of whether the user has permission to run updates.
     $this->drupalLogin($this->reportViewerUser);
+    $this->checkForUpdates();
     $this->drupalGet('admin/reports/status');
     $this->assertReadinessReportMatches('Your site is ready for automatic updates.', 'checked', FALSE);
     $this->drupalLogin($this->checkerRunnerUser);
@@ -300,20 +303,22 @@ class ReadinessValidationTest extends BrowserTestBase {
     $this->drupalGet('admin/reports/status');
     $assert->pageTextNotContains('Update readiness checks');
 
-    $this->container->get('module_installer')->install(['automatic_updates']);
+    // We have to install the automatic_updates_test module because it provides
+    // the functionality to retrieve our fake release history metadata.
+    $this->container->get('module_installer')->install(['automatic_updates', 'automatic_updates_test']);
     $this->drupalGet('admin/reports/status');
     $this->assertReadinessReportMatches('Your site is ready for automatic updates. Run readiness checks now.', 'checked');
 
     $expected_results = $this->testResults['checker_1']['1 error'];
-    TestChecker1::setTestResult($expected_results);
-    $this->container->get('module_installer')->install(['automatic_updates_test']);
+    TestChecker2::setTestResult($expected_results);
+    $this->container->get('module_installer')->install(['automatic_updates_test2']);
     $this->drupalGet('admin/structure');
     $assert->pageTextContainsOnce($expected_results[0]->getMessages()[0]);
 
     // Confirm that installing a module that does not provide a new checker does
     // not run the checkers on install.
     $unexpected_results = $this->testResults['checker_1']['2 errors 2 warnings'];
-    TestChecker1::setTestResult($unexpected_results);
+    TestChecker2::setTestResult($unexpected_results);
     $this->container->get('module_installer')->install(['help']);
     // Check for message on 'admin/structure' instead of the status report
     // because checkers will be run if needed on the status report.
diff --git a/tests/src/Functional/UpdaterFormTest.php b/tests/src/Functional/UpdaterFormTest.php
index dd5422aaf6..93d9a9d3a9 100644
--- a/tests/src/Functional/UpdaterFormTest.php
+++ b/tests/src/Functional/UpdaterFormTest.php
@@ -37,7 +37,10 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase {
    */
   protected function setUp(): void {
     parent::setUp();
-    $this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/drupal.0.0.xml');
+
+    $this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/drupal.9.8.1-security.xml');
+    $this->drupalLogin($this->rootUser);
+    $this->checkForUpdates();
   }
 
   /**
@@ -48,8 +51,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase {
    */
   public function testFormNotDisplayedIfAlreadyCurrent(): void {
     $this->setCoreVersion('9.8.1');
-
-    $this->drupalLogin($this->rootUser);
+    $this->checkForUpdates();
 
     $this->drupalGet('/admin/modules/automatic-update');
 
@@ -66,7 +68,6 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase {
     $this->drupalPlaceBlock('local_tasks_block', ['primary' => TRUE]);
     $assert_session = $this->assertSession();
     $this->setCoreVersion('9.8.0');
-    $this->drupalLogin($this->rootUser);
     $this->checkForUpdates();
 
     // Navigate to the automatic updates form.
@@ -85,6 +86,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase {
     $this->assertSame('9.8.1 (Release notes)', $cells[2]->getText());
     $release_notes = $assert_session->elementExists('named', ['link', 'Release notes'], $cells[2]);
     $this->assertSame('Release notes for Drupal', $release_notes->getAttribute('title'));
+    $assert_session->buttonExists('Update');
   }
 
   /**
@@ -100,7 +102,6 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase {
     $error = ValidationResult::createError([$message]);
     TestChecker1::setTestResult([$error]);
 
-    $this->drupalLogin($this->rootUser);
     $this->drupalGet('/admin/reports/status');
     $page->clickLink('Run readiness checks');
     $assert_session->pageTextContainsOnce((string) $message);
@@ -170,6 +171,19 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase {
     $assert_session->pageTextContains('Ready to update');
   }
 
+  /**
+   * Tests that updating to a different minor version isn't supported.
+   */
+  public function testMinorVersionUpdateNotSupported(): void {
+    $this->setCoreVersion('9.7.1');
+
+    $this->drupalGet('/admin/modules/automatic-update');
+
+    $assert_session = $this->assertSession();
+    $assert_session->pageTextContainsOnce('Updating from one minor version to another is not supported.');
+    $assert_session->buttonNotExists('Update');
+  }
+
   /**
    * Deletes a staged, failed update.
    */
@@ -180,15 +194,4 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase {
     $session->reload();
   }
 
-  /**
-   * Checks for available updates.
-   *
-   * Assumes that a user with appropriate permissions is logged in.
-   */
-  private function checkForUpdates(): void {
-    $this->drupalGet('/admin/reports/updates');
-    $this->getSession()->getPage()->clickLink('Check manually');
-    $this->checkForMetaRefresh();
-  }
-
 }
diff --git a/tests/src/Kernel/AutomaticUpdatesKernelTestBase.php b/tests/src/Kernel/AutomaticUpdatesKernelTestBase.php
index 47ab4b3eed..8f87e36c0d 100644
--- a/tests/src/Kernel/AutomaticUpdatesKernelTestBase.php
+++ b/tests/src/Kernel/AutomaticUpdatesKernelTestBase.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\automatic_updates\Kernel;
 
+use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\KernelTests\KernelTestBase;
 use GuzzleHttp\Client;
 use GuzzleHttp\Handler\MockHandler;
@@ -19,6 +20,18 @@ abstract class AutomaticUpdatesKernelTestBase extends KernelTestBase {
    */
   protected static $modules = ['update', 'update_test'];
 
+  /**
+   * The mocked HTTP client that returns metadata about available updates.
+   *
+   * We need to preserve this as a class property so that we can re-inject it
+   * into the container when a rebuild is triggered by module installation.
+   *
+   * @var \GuzzleHttp\Client
+   *
+   * @see ::register()
+   */
+  private $client;
+
   /**
    * Sets the current (running) version of core, as known to the Update module.
    *
@@ -31,6 +44,19 @@ abstract class AutomaticUpdatesKernelTestBase extends KernelTestBase {
       ->save();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function register(ContainerBuilder $container) {
+    parent::register($container);
+
+    // If we previously set up a mock HTTP client in ::setReleaseMetadata(),
+    // re-inject it into the container.
+    if ($this->client) {
+      $container->set('http_client', $this->client);
+    }
+  }
+
   /**
    * Sets the release metadata file to use when fetching available updates.
    *
@@ -41,10 +67,10 @@ abstract class AutomaticUpdatesKernelTestBase extends KernelTestBase {
     $metadata = Utils::tryFopen($file, 'r');
     $response = new Response(200, [], Utils::streamFor($metadata));
     $handler = new MockHandler([$response]);
-    $client = new Client([
+    $this->client = new Client([
       'handler' => HandlerStack::create($handler),
     ]);
-    $this->container->set('http_client', $client);
+    $this->container->set('http_client', $this->client);
   }
 
 }
diff --git a/tests/src/Kernel/ReadinessValidation/ComposerExecutableValidatorTest.php b/tests/src/Kernel/ReadinessValidation/ComposerExecutableValidatorTest.php
index d9972cd6fa..278f80adbf 100644
--- a/tests/src/Kernel/ReadinessValidation/ComposerExecutableValidatorTest.php
+++ b/tests/src/Kernel/ReadinessValidation/ComposerExecutableValidatorTest.php
@@ -4,7 +4,7 @@ namespace Drupal\Tests\automatic_updates\Kernel\ReadinessValidation;
 
 use Drupal\automatic_updates\Validation\ValidationResult;
 use Drupal\automatic_updates\Validator\ComposerExecutableValidator;
-use Drupal\KernelTests\KernelTestBase;
+use Drupal\Tests\automatic_updates\Kernel\AutomaticUpdatesKernelTestBase;
 use Drupal\Tests\automatic_updates\Traits\ValidationTestTrait;
 use PhpTuf\ComposerStager\Exception\IOException;
 use PhpTuf\ComposerStager\Infrastructure\Process\ExecutableFinderInterface;
@@ -15,7 +15,7 @@ use Prophecy\Argument;
  *
  * @group automatic_updates
  */
-class ComposerExecutableValidatorTest extends KernelTestBase {
+class ComposerExecutableValidatorTest extends AutomaticUpdatesKernelTestBase {
 
   use ValidationTestTrait;
 
@@ -25,9 +25,18 @@ class ComposerExecutableValidatorTest extends KernelTestBase {
   protected static $modules = [
     'automatic_updates',
     'package_manager',
-    'update',
   ];
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+    $this->installConfig('update');
+    $this->setCoreVersion('9.8.0');
+    $this->setReleaseMetadata(__DIR__ . '/../../../fixtures/release-history/drupal.9.8.1.xml');
+  }
+
   /**
    * Tests that an error is raised if the Composer executable isn't found.
    */
diff --git a/tests/src/Kernel/ReadinessValidation/ReadinessValidationManagerTest.php b/tests/src/Kernel/ReadinessValidation/ReadinessValidationManagerTest.php
index d044b1959e..f1a32b0c6d 100644
--- a/tests/src/Kernel/ReadinessValidation/ReadinessValidationManagerTest.php
+++ b/tests/src/Kernel/ReadinessValidation/ReadinessValidationManagerTest.php
@@ -4,8 +4,8 @@ namespace Drupal\Tests\automatic_updates\Kernel\ReadinessValidation;
 
 use Drupal\automatic_updates_test\ReadinessChecker\TestChecker1;
 use Drupal\automatic_updates_test2\ReadinessChecker\TestChecker2;
-use Drupal\KernelTests\KernelTestBase;
 use Drupal\system\SystemManager;
+use Drupal\Tests\automatic_updates\Kernel\AutomaticUpdatesKernelTestBase;
 use Drupal\Tests\automatic_updates\Traits\ValidationTestTrait;
 
 /**
@@ -13,7 +13,7 @@ use Drupal\Tests\automatic_updates\Traits\ValidationTestTrait;
  *
  * @group automatic_updates
  */
-class ReadinessValidationManagerTest extends KernelTestBase {
+class ReadinessValidationManagerTest extends AutomaticUpdatesKernelTestBase {
 
   use ValidationTestTrait;
 
@@ -34,15 +34,19 @@ class ReadinessValidationManagerTest extends KernelTestBase {
     $this->installEntitySchema('user');
     $this->installSchema('user', ['users_data']);
     $this->createTestValidationResults();
+
+    $this->installConfig('update');
+    $this->setCoreVersion('9.8.0');
+    $this->setReleaseMetadata(__DIR__ . '/../../../fixtures/release-history/drupal.9.8.1.xml');
   }
 
   /**
    * @covers ::getResults
    */
   public function testGetResults(): void {
-    $this->enableModules(['update', 'automatic_updates', 'automatic_updates_test2']);
-    $this->installConfig(['update', 'automatic_updates']);
-    $this->assertSame([], $this->getResultsFromManager(TRUE));
+    $this->enableModules(['automatic_updates', 'automatic_updates_test2']);
+    $this->assertCheckerResultsFromManager([], TRUE);
+
     $expected_results = [
       array_pop($this->testResults['checker_1']),
       array_pop($this->testResults['checker_2']),
diff --git a/tests/src/Kernel/UpdateRecommenderTest.php b/tests/src/Kernel/UpdateRecommenderTest.php
index 8de05d44d8..6be23292f4 100644
--- a/tests/src/Kernel/UpdateRecommenderTest.php
+++ b/tests/src/Kernel/UpdateRecommenderTest.php
@@ -25,6 +25,7 @@ class UpdateRecommenderTest extends AutomaticUpdatesKernelTestBase {
   protected function setUp(): void {
     parent::setUp();
     $this->installConfig('update');
+    $this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/drupal.9.8.1.xml');
   }
 
   /**
@@ -32,7 +33,6 @@ class UpdateRecommenderTest extends AutomaticUpdatesKernelTestBase {
    */
   public function testUpdateAvailable(): void {
     $this->setCoreVersion('9.8.0');
-    $this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/drupal.0.0.xml');
 
     $recommender = new UpdateRecommender();
     $recommended_release = $recommender->getRecommendedRelease(TRUE);
@@ -47,7 +47,6 @@ class UpdateRecommenderTest extends AutomaticUpdatesKernelTestBase {
    */
   public function testNoUpdateAvailable(): void {
     $this->setCoreVersion('9.8.1');
-    $this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/drupal.0.0.xml');
 
     $recommender = new UpdateRecommender();
     $recommended_release = $recommender->getRecommendedRelease(TRUE);
diff --git a/tests/src/Kernel/UpdaterTest.php b/tests/src/Kernel/UpdaterTest.php
index 2151697e8e..bd7750c98e 100644
--- a/tests/src/Kernel/UpdaterTest.php
+++ b/tests/src/Kernel/UpdaterTest.php
@@ -18,13 +18,14 @@ class UpdaterTest extends AutomaticUpdatesKernelTestBase {
     'automatic_updates',
     'automatic_updates_test',
     'package_manager',
+    'package_manager_bypass',
   ];
 
   /**
    * Tests that correct versions are staged after calling ::begin().
    */
   public function testCorrectVersionsStaged() {
-    $this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/drupal.0.0.xml');
+    $this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/drupal.9.8.1-security.xml');
 
     // Set the running core version to 9.8.0.
     $this->setCoreVersion('9.8.0');
-- 
GitLab