From 77ea670bc2405fb9240b3b50e8e478bfb84b91b5 Mon Sep 17 00:00:00 2001
From: "yash.rode" <yash.rode@3685174.no-reply.drupal.org>
Date: Tue, 15 Nov 2022 23:25:55 +0000
Subject: [PATCH] Issue #3276645 by yash.rode, tedbow, Wim Leers, phenaproxima:
 Run status checkers after form core update

---
 .../tests/src/Functional/UpdaterFormTest.php  | 75 +++++++++++++++++++
 src/Controller/UpdateController.php           | 17 ++++-
 tests/src/Functional/UpdaterFormTest.php      | 68 +++++++++++++++++
 3 files changed, 158 insertions(+), 2 deletions(-)

diff --git a/automatic_updates_extensions/tests/src/Functional/UpdaterFormTest.php b/automatic_updates_extensions/tests/src/Functional/UpdaterFormTest.php
index 10b2988dd1..524d19f987 100644
--- a/automatic_updates_extensions/tests/src/Functional/UpdaterFormTest.php
+++ b/automatic_updates_extensions/tests/src/Functional/UpdaterFormTest.php
@@ -73,6 +73,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase {
       'administer site configuration',
       'administer software updates',
       'access site in maintenance mode',
+      'access administration pages',
     ]);
     // We need this fixture as only projects installed via composer will show up
     // on the form.
@@ -214,6 +215,80 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase {
     $this->assertNotSame($pre_apply_time, $post_apply_time);
   }
 
+  /**
+   * Data provider for testStatusCheckerRunAfterUpdate().
+   *
+   * @return bool[][]
+   *   The test cases.
+   */
+  public function providerStatusCheckerRunAfterUpdate(): array {
+    return [
+      'has database updates' => [TRUE],
+      'does not have database updates' => [FALSE],
+    ];
+  }
+
+  /**
+   * Tests status checks are run after an update.
+   *
+   * @param bool $has_database_updates
+   *   Whether the site has database updates or not.
+   *
+   * @dataProvider providerStatusCheckerRunAfterUpdate
+   */
+  public function testStatusCheckerRunAfterUpdate(bool $has_database_updates): void {
+    $this->useFixtureDirectoryAsStaged(__DIR__ . '/../../fixtures/stage_composer/semver_test');
+    $this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/semver_test.1.1.xml');
+    $this->setProjectInstalledVersion(['semver_test' => '8.1.0']);
+    $this->checkForUpdates();
+    $page = $this->getSession()->getPage();
+    // Navigate to the automatic updates form.
+    $this->drupalGet('/admin/modules/automatic-update-extensions');
+    $assert_session = $this->assertSession();
+    $assert_session->pageTextNotContains(static::$errorsExplanation);
+    $assert_session->pageTextNotContains(static::$warningsExplanation);
+
+    $this->assertTableShowsUpdates('Semver Test', '8.1.0', '8.1.1');
+    $this->assertUpdatesCount(1);
+    $page->checkField('projects[semver_test]');
+    $page->pressButton('Update');
+    $this->checkForMetaRefresh();
+    $this->assertUpdateStagedTimes(1);
+    // Set an error before completing the update. This error should be visible
+    // on admin pages after completing the update without having to explicitly
+    // run the status checks.
+    TestSubscriber1::setTestResult([ValidationResult::createError(['Error before continue.'])], StatusCheckEvent::class);
+    if ($has_database_updates) {
+      // Simulate a staged database update in the automatic_updates_test module.
+      // We must do this after the update has started, because the pending
+      // updates validator will prevent an update from starting.
+      $this->container->get('state')->set('automatic_updates_test.new_update', TRUE);
+      $page->pressButton('Continue');
+      $this->checkForMetaRefresh();
+      $this->assertSession()->addressEquals('/update.php');
+      $assert_session->pageTextNotContains('Possible database updates have been detected in the following extensions.');
+      $assert_session->pageTextContainsOnce('Please apply database updates to complete the update process.');
+      $page->clickLink('Continue');
+      // @see automatic_updates_update_1191934()
+      $assert_session->pageTextContains('Dynamic automatic_updates_update_1191934');
+      $page->clickLink('Apply pending updates');
+      $this->checkForMetaRefresh();
+      $assert_session->pageTextContains('Updates were attempted.');
+    }
+    else {
+      $page->pressButton('Continue');
+      $this->checkForMetaRefresh();
+      $assert_session->addressEquals('/admin/reports/updates');
+      $assert_session->pageTextContainsOnce('Update complete!');
+    }
+    // Status checks should display errors on admin page.
+    $this->drupalGet('/admin');
+    // Confirm that the status checks were run and the new error is displayed.
+    $assert_session->statusMessageContains('Error before continue.', 'error');
+    $assert_session->statusMessageContains(static::$errorsExplanation, 'error');
+    $assert_session->pageTextNotContains('Your site has not recently run an update readiness check. Run readiness checks now.');
+  }
+
   /**
    * Tests that an exception is thrown if a previous apply failed.
    */
diff --git a/src/Controller/UpdateController.php b/src/Controller/UpdateController.php
index dddbf90695..362e52297f 100644
--- a/src/Controller/UpdateController.php
+++ b/src/Controller/UpdateController.php
@@ -3,6 +3,7 @@
 namespace Drupal\automatic_updates\Controller;
 
 use Drupal\automatic_updates\BatchProcessor;
+use Drupal\automatic_updates\Validation\StatusChecker;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
@@ -35,6 +36,13 @@ final class UpdateController extends ControllerBase {
    */
   protected $routeMatch;
 
+  /**
+   * The status checker.
+   *
+   * @var \Drupal\automatic_updates\Validation\StatusChecker
+   */
+  protected $statusChecker;
+
   /**
    * Constructs an UpdateController object.
    *
@@ -44,11 +52,14 @@ final class UpdateController extends ControllerBase {
    *   The state service.
    * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
    *   The current route match.
+   * @param \Drupal\automatic_updates\Validation\StatusChecker $status_checker
+   *   The status checker service.
    */
-  public function __construct(PendingUpdatesValidator $pending_updates_validator, StateInterface $state, RouteMatchInterface $route_match) {
+  public function __construct(PendingUpdatesValidator $pending_updates_validator, StateInterface $state, RouteMatchInterface $route_match, StatusChecker $status_checker) {
     $this->pendingUpdatesValidator = $pending_updates_validator;
     $this->stateService = $state;
     $this->routeMatch = $route_match;
+    $this->statusChecker = $status_checker;
   }
 
   /**
@@ -58,7 +69,8 @@ final class UpdateController extends ControllerBase {
     return new static(
       $container->get('package_manager.validator.pending_updates'),
       $container->get('state'),
-      $container->get('current_route_match')
+      $container->get('current_route_match'),
+      $container->get('automatic_updates.status_checker')
     );
   }
 
@@ -76,6 +88,7 @@ final class UpdateController extends ControllerBase {
    *   A redirect to the appropriate destination.
    */
   public function onFinish(Request $request): RedirectResponse {
+    $this->statusChecker->run();
     if ($this->pendingUpdatesValidator->updatesExist()) {
       $message = $this->t('Please apply database updates to complete the update process.');
       $url = Url::fromRoute('system.db_update');
diff --git a/tests/src/Functional/UpdaterFormTest.php b/tests/src/Functional/UpdaterFormTest.php
index ad6f42d3c7..722d5e9988 100644
--- a/tests/src/Functional/UpdaterFormTest.php
+++ b/tests/src/Functional/UpdaterFormTest.php
@@ -722,6 +722,74 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase {
     $this->assertNotSame($pre_apply_time, $post_apply_time);
   }
 
+  /**
+   * Data provider for testStatusCheckerRunAfterUpdate().
+   *
+   * @return bool[][]
+   *   The test cases.
+   */
+  public function providerStatusCheckerRunAfterUpdate(): array {
+    return [
+      'has database updates' => [TRUE],
+      'does not have database updates' => [FALSE],
+    ];
+  }
+
+  /**
+   * Tests status checks are run after an update.
+   *
+   * @param bool $has_database_updates
+   *   Whether the site has database updates or not.
+   *
+   * @dataProvider providerStatusCheckerRunAfterUpdate
+   */
+  public function testStatusCheckerRunAfterUpdate(bool $has_database_updates) {
+    $assert_session = $this->assertSession();
+    $this->setCoreVersion('9.8.0');
+    $this->checkForUpdates();
+    $page = $this->getSession()->getPage();
+    // Navigate to the automatic updates form.
+    $this->drupalGet('/admin/modules/update');
+    Stager::setFixturePath(__DIR__ . '/../../fixtures/drupal-9.8.1-installed');
+    $page->pressButton('Update to 9.8.1');
+    $this->checkForMetaRefresh();
+    $this->assertUpdateStagedTimes(1);
+    $this->assertUpdateReady('9.8.1');
+    // Set an error before completing the update. This error should be visible
+    // on admin pages after completing the update without having to explicitly
+    // run the status checks.
+    TestSubscriber1::setTestResult([ValidationResult::createError(['Error before continue.'])], StatusCheckEvent::class);
+    if ($has_database_updates) {
+      // Simulate a staged database update in the automatic_updates_test module.
+      // We must do this after the update has started, because the pending
+      // updates validator will prevent an update from starting.
+      $this->container->get('state')->set('automatic_updates_test.new_update', TRUE);
+      $page->pressButton('Continue');
+      $this->checkForMetaRefresh();
+      $this->assertSession()->addressEquals('/update.php');
+      $assert_session->pageTextNotContains('Possible database updates have been detected in the following extension');
+      $assert_session->pageTextContainsOnce('Please apply database updates to complete the update process.');
+      $page->clickLink('Continue');
+      // @see automatic_updates_update_1191934()
+      $assert_session->pageTextContains('Dynamic automatic_updates_update_1191934');
+      $page->clickLink('Apply pending updates');
+      $this->checkForMetaRefresh();
+      $assert_session->pageTextContains('Updates were attempted.');
+    }
+    else {
+      $page->pressButton('Continue');
+      $this->checkForMetaRefresh();
+      $assert_session->addressEquals('/admin/reports/updates');
+      $assert_session->pageTextContainsOnce('Update complete!');
+    }
+    // Status checks should display errors on admin page.
+    $this->drupalGet('/admin');
+    // Confirm that the status checks were run and the new error is displayed.
+    $assert_session->statusMessageContains('Error before continue.', 'error');
+    $assert_session->statusMessageContains(static::$errorsExplanation, 'error');
+    $assert_session->pageTextNotContains('Your site has not recently run an update readiness check. Run readiness checks now.');
+  }
+
   /**
    * Data provider for testUpdateCompleteMessage().
    *
-- 
GitLab