From 00c53328cb192e5b092d5e6acca91141b47bdcdc Mon Sep 17 00:00:00 2001
From: phenaproxima <phenaproxima@205645.no-reply.drupal.org>
Date: Thu, 16 Sep 2021 19:59:50 +0000
Subject: [PATCH] Issue #3233587 by phenaproxima, tedbow: Create a build test
 that tests calling API as cleanly as possible

---
 automatic_updates.services.yml                |  6 +++
 src/AutomaticUpdatesEvents.php                |  9 ++++
 src/Event/UpdateRefreshSubscriber.php         | 48 +++++++++++++++++++
 src/Updater.php                               |  1 +
 .../automatic_updates_test.routing.yml        | 10 +++-
 ...adataController.php => TestController.php} | 35 +++++++++++++-
 tests/src/Build/CoreUpdateTest.php            |  8 ++++
 tests/src/Build/UpdateTestBase.php            |  2 +-
 .../ComposerExecutableValidatorTest.php       |  1 +
 9 files changed, 115 insertions(+), 5 deletions(-)
 create mode 100644 src/Event/UpdateRefreshSubscriber.php
 rename tests/modules/automatic_updates_test/src/{MetadataController.php => TestController.php} (59%)

diff --git a/automatic_updates.services.yml b/automatic_updates.services.yml
index e2477e68f6..31c25511a1 100644
--- a/automatic_updates.services.yml
+++ b/automatic_updates.services.yml
@@ -14,6 +14,12 @@ services:
       - '%site.path%'
       - '@automatic_updates.path_locator'
     properties: { _serviceId: package_manager.cleaner }
+  automatic_updates.update_refresh_subscriber:
+    class: Drupal\automatic_updates\Event\UpdateRefreshSubscriber
+    arguments:
+      - '@update.manager'
+    tags:
+      - { name: event_subscriber }
   automatic_updates.excluded_paths_subscriber:
     class: Drupal\automatic_updates\Event\ExcludedPathsSubscriber
     arguments: ['%app.root%', '%site.path%', '@file_system', '@stream_wrapper_manager']
diff --git a/src/AutomaticUpdatesEvents.php b/src/AutomaticUpdatesEvents.php
index 7f04539a9c..dedef4e0cd 100644
--- a/src/AutomaticUpdatesEvents.php
+++ b/src/AutomaticUpdatesEvents.php
@@ -57,4 +57,13 @@ final class AutomaticUpdatesEvents {
    */
   const PRE_COMMIT = 'automatic_updates.pre_commit';
 
+  /**
+   * Name of the event fired when a staged update has been committed.
+   *
+   * @Event
+   *
+   * @var string
+   */
+  const POST_COMMIT = 'automatic_updates.post_commit';
+
 }
diff --git a/src/Event/UpdateRefreshSubscriber.php b/src/Event/UpdateRefreshSubscriber.php
new file mode 100644
index 0000000000..1a3378fbae
--- /dev/null
+++ b/src/Event/UpdateRefreshSubscriber.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Drupal\automatic_updates\Event;
+
+use Drupal\automatic_updates\AutomaticUpdatesEvents;
+use Drupal\update\UpdateManagerInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Clears stale update data once a staged update has been committed.
+ */
+class UpdateRefreshSubscriber implements EventSubscriberInterface {
+
+  /**
+   * The update manager service.
+   *
+   * @var \Drupal\update\UpdateManagerInterface
+   */
+  protected $updateManager;
+
+  /**
+   * Constructs an UpdateRefreshSubscriber object.
+   *
+   * @param \Drupal\update\UpdateManagerInterface $update_manager
+   *   The update manager service.
+   */
+  public function __construct(UpdateManagerInterface $update_manager) {
+    $this->updateManager = $update_manager;
+  }
+
+  /**
+   * Clears stale update data.
+   */
+  public function clearData(): void {
+    $this->updateManager->refreshUpdateData();
+    update_storage_clear();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    return [
+      AutomaticUpdatesEvents::POST_COMMIT => ['clearData', 1000],
+    ];
+  }
+
+}
diff --git a/src/Updater.php b/src/Updater.php
index 0624bf8173..fcd251a5e0 100644
--- a/src/Updater.php
+++ b/src/Updater.php
@@ -234,6 +234,7 @@ class Updater {
     /** @var \Drupal\automatic_updates\Event\PreCommitEvent $event */
     $event = $this->dispatchUpdateEvent(new PreCommitEvent(), AutomaticUpdatesEvents::PRE_COMMIT);
     $this->committer->commit($this->pathLocator->getStageDirectory(), $this->pathLocator->getActiveDirectory(), $this->getExclusions($event));
+    $this->dispatchUpdateEvent(new UpdateEvent(), AutomaticUpdatesEvents::POST_COMMIT);
   }
 
   /**
diff --git a/tests/modules/automatic_updates_test/automatic_updates_test.routing.yml b/tests/modules/automatic_updates_test/automatic_updates_test.routing.yml
index 3f4200e4f9..bf9090ff7a 100644
--- a/tests/modules/automatic_updates_test/automatic_updates_test.routing.yml
+++ b/tests/modules/automatic_updates_test/automatic_updates_test.routing.yml
@@ -1,7 +1,13 @@
-automatic_updates_test.update_test:
+automatic_updates_test.metadata:
   path: '/automatic-update-test/{project_name}/{version}'
   defaults:
     _title: 'Update test'
-    _controller: '\Drupal\automatic_updates_test\MetadataController::updateTest'
+    _controller: '\Drupal\automatic_updates_test\TestController::metadata'
+  requirements:
+    _access: 'TRUE'
+automatic_updates_test.update:
+  path: '/automatic-update-test/update/{to_version}'
+  defaults:
+    _controller: '\Drupal\automatic_updates_test\TestController::update'
   requirements:
     _access: 'TRUE'
diff --git a/tests/modules/automatic_updates_test/src/MetadataController.php b/tests/modules/automatic_updates_test/src/TestController.php
similarity index 59%
rename from tests/modules/automatic_updates_test/src/MetadataController.php
rename to tests/modules/automatic_updates_test/src/TestController.php
index c00cce391a..7772d1f01b 100644
--- a/tests/modules/automatic_updates_test/src/MetadataController.php
+++ b/tests/modules/automatic_updates_test/src/TestController.php
@@ -2,11 +2,42 @@
 
 namespace Drupal\automatic_updates_test;
 
+use Drupal\automatic_updates\UpdateRecommender;
+use Drupal\Component\Utility\Environment;
 use Drupal\Core\Controller\ControllerBase;
 use Symfony\Component\HttpFoundation\BinaryFileResponse;
 use Symfony\Component\HttpFoundation\Response;
 
-class MetadataController extends ControllerBase {
+class TestController extends ControllerBase {
+
+  /**
+   * Performs an in-place update to a given version of Drupal core.
+   *
+   * This executes the update immediately, in one request, without using the
+   * batch system or cron as wrappers.
+   *
+   * @param string $to_version
+   *   The version of core to update to.
+   *
+   * @return array
+   *   The renderable array of the page.
+   */
+  public function update(string $to_version): array {
+    // Let it take as long as it needs.
+    Environment::setTimeLimit(0);
+
+    /** @var \Drupal\automatic_updates\Updater $updater */
+    $updater = \Drupal::service('automatic_updates.updater');
+    $updater->begin(['drupal' => $to_version]);
+    $updater->stage();
+    $updater->commit();
+    $updater->clean();
+
+    $project = (new UpdateRecommender())->getProjectInfo();
+    return [
+      '#markup' => $project['existing_version'],
+    ];
+  }
 
   /**
    * Page callback: Prints mock XML for the Update Manager module.
@@ -16,7 +47,7 @@ class MetadataController extends ControllerBase {
    * testing automatic updates. This was done in order to use a different
    * directory of mock XML files.
    */
-  public function updateTest($project_name = 'drupal', $version = NULL): Response {
+  public function metadata($project_name = 'drupal', $version = NULL): Response {
     if ($project_name !== 'drupal') {
       return new Response();
     }
diff --git a/tests/src/Build/CoreUpdateTest.php b/tests/src/Build/CoreUpdateTest.php
index 3a7f02c459..763d554682 100644
--- a/tests/src/Build/CoreUpdateTest.php
+++ b/tests/src/Build/CoreUpdateTest.php
@@ -103,6 +103,14 @@ class CoreUpdateTest extends UpdateTestBase {
     ];
   }
 
+  /**
+   * Tests an end-to-end core update via the API.
+   */
+  public function testApi(): void {
+    $this->visit('/automatic-update-test/update/9.8.1');
+    $this->getMink()->assertSession()->pageTextContains('9.8.1');
+  }
+
   /**
    * Tests an end-to-end core update via the UI.
    */
diff --git a/tests/src/Build/UpdateTestBase.php b/tests/src/Build/UpdateTestBase.php
index a757c3d173..e995cb804d 100644
--- a/tests/src/Build/UpdateTestBase.php
+++ b/tests/src/Build/UpdateTestBase.php
@@ -83,7 +83,7 @@ abstract class UpdateTestBase extends QuickStartTestBase {
    * @param array $xml_map
    *   The update XML map, as used by update_test.settings.
    *
-   * @see \Drupal\automatic_updates_test\MetadataController::updateTest()
+   * @see \Drupal\automatic_updates_test\TestController::metadata()
    */
   protected function setReleaseMetadata(array $xml_map): void {
     $xml_map = var_export($xml_map, TRUE);
diff --git a/tests/src/Kernel/ReadinessValidation/ComposerExecutableValidatorTest.php b/tests/src/Kernel/ReadinessValidation/ComposerExecutableValidatorTest.php
index f57d5969e0..d9972cd6fa 100644
--- a/tests/src/Kernel/ReadinessValidation/ComposerExecutableValidatorTest.php
+++ b/tests/src/Kernel/ReadinessValidation/ComposerExecutableValidatorTest.php
@@ -25,6 +25,7 @@ class ComposerExecutableValidatorTest extends KernelTestBase {
   protected static $modules = [
     'automatic_updates',
     'package_manager',
+    'update',
   ];
 
   /**
-- 
GitLab