From a816f7e49fd8ac7d707fab97527d424d1000f541 Mon Sep 17 00:00:00 2001
From: xjm <xjm@65776.no-reply.drupal.org>
Date: Thu, 19 Mar 2020 16:34:25 -0500
Subject: [PATCH] Issue #3118087 by dww, JoshaHubbers, jungle, tedbow,
 RajabNatshah, Kingdutch, JonMcL, xjm, Nick Hope, wroehrig, wxman, broeker,
 mlozano7, kazajhodo, suit4, xmacinfo, BrightBold: If any extension has a
 missing or invalid version, Update manager throws errors and is confused
 about site update status

---
 .../aaa_update_test/aaa_update_test.info.yml  |  1 -
 .../src/Functional/UpdateContribTest.php      | 37 +++++++++++++++++++
 core/modules/update/update.compare.inc        | 11 ++++++
 3 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/core/modules/update/tests/modules/aaa_update_test/aaa_update_test.info.yml b/core/modules/update/tests/modules/aaa_update_test/aaa_update_test.info.yml
index 19367eac8cd5..ee90601b12de 100644
--- a/core/modules/update/tests/modules/aaa_update_test/aaa_update_test.info.yml
+++ b/core/modules/update/tests/modules/aaa_update_test/aaa_update_test.info.yml
@@ -2,4 +2,3 @@ name: 'AAA Update test'
 type: module
 description: 'Support module for update module testing.'
 package: Testing
-version: VERSION
diff --git a/core/modules/update/tests/src/Functional/UpdateContribTest.php b/core/modules/update/tests/src/Functional/UpdateContribTest.php
index 7c50fafd89cd..0fff16789608 100644
--- a/core/modules/update/tests/src/Functional/UpdateContribTest.php
+++ b/core/modules/update/tests/src/Functional/UpdateContribTest.php
@@ -794,6 +794,43 @@ public function testUnsupportedRelease() {
     $this->confirmUnsupportedStatus('8.x-1.1', '8.x-2.0', 'Recommended version:');
   }
 
+  /**
+   * Tests messages for invalid, empty and missing version strings.
+   */
+  public function testNonStandardVersionStrings() {
+    $version_infos = [
+      'invalid' => [
+        'version' => 'llama',
+        'expected' => 'Invalid version: llama',
+      ],
+      'empty' => [
+        'version' => '',
+        'expected' => 'Empty version',
+      ],
+      'null' => [
+        'expected' => 'Invalid version: Unknown',
+      ],
+    ];
+    foreach ($version_infos as $version_info) {
+      $system_info = [
+        'aaa_update_test' => [
+          'project' => 'aaa_update_test',
+          'hidden' => FALSE,
+        ],
+      ];
+      if (isset($version_info['version'])) {
+        $system_info['aaa_update_test']['version'] = $version_info['version'];
+      }
+      $this->config('update_test.settings')->set('system_info', $system_info)->save();
+      $this->refreshUpdateStatus([
+        'drupal' => '0.0',
+        $this->updateProject => '1_0-supported',
+      ]);
+      $this->standardTests();
+      $this->assertSession()->elementTextContains('css', $this->updateTableLocator, $version_info['expected']);
+    }
+  }
+
   /**
    * Asserts that a core compatibility message is correct for an update.
    *
diff --git a/core/modules/update/update.compare.inc b/core/modules/update/update.compare.inc
index d318e6c48633..1eadbed71f31 100644
--- a/core/modules/update/update.compare.inc
+++ b/core/modules/update/update.compare.inc
@@ -196,6 +196,9 @@ function update_calculate_project_data($available) {
  * version (e.g., 5.x-1.5-beta1, 5.x-1.5-beta2, and 5.x-1.5). Development
  * snapshots for a given major version are always listed last.
  *
+ * NOTE: This function *must* set a value for $project_data['status'] before
+ * returning, or the rest of the Update Manager will break in unexpected ways.
+ *
  * @param $project_data
  *   An array containing information about a specific project.
  * @param $available
@@ -263,11 +266,19 @@ function update_calculate_project_update_status(&$project_data, $available) {
   }
 
   // Figure out the target major version.
+  // Off Drupal.org, '0' could be a valid version string, so don't use empty().
+  if (!isset($project_data['existing_version']) || $project_data['existing_version'] === '') {
+    $project_data['status'] = UpdateFetcherInterface::UNKNOWN;
+    $project_data['reason'] = t('Empty version');
+    return;
+  }
   try {
     $existing_major = ModuleVersion::createFromVersionString($project_data['existing_version'])->getMajorVersion();
   }
   catch (UnexpectedValueException $exception) {
     // If the version has an unexpected value we can't determine updates.
+    $project_data['status'] = UpdateFetcherInterface::UNKNOWN;
+    $project_data['reason'] = t('Invalid version: @existing_version', ['@existing_version' => $project_data['existing_version']]);
     return;
   }
   $supported_branches = [];
-- 
GitLab