diff --git a/core/modules/update/src/UpdateManagerInterface.php b/core/modules/update/src/UpdateManagerInterface.php index 74dac9f67c9f171827ed1244e886b98f59d20f5f..32eb34cbba8d082a1c887fc460c9438605cad96e 100644 --- a/core/modules/update/src/UpdateManagerInterface.php +++ b/core/modules/update/src/UpdateManagerInterface.php @@ -82,8 +82,14 @@ public function getProjects(); /** * Processes a step in batch for fetching available update data. * + * Before calling this method, call + * UpdateManagerInterface::refreshUpdateData() to clear existing update data + * and initiate re-fetching. + * * @param array $context * Reference to an array used for Batch API storage. + * + * @see \Drupal\update\UpdateManagerInterface::refreshUpdateData() */ public function fetchDataBatch(&$context); diff --git a/core/modules/update/src/UpdateProcessor.php b/core/modules/update/src/UpdateProcessor.php index 25dfc7a004bc90dd42e104f726e64010cdda7828..8d42dd53622abfc868e156a0b2d9f5962c83cdfd 100644 --- a/core/modules/update/src/UpdateProcessor.php +++ b/core/modules/update/src/UpdateProcessor.php @@ -127,6 +127,11 @@ public function createFetchTask($project) { */ public function fetchData() { $end = time() + $this->updateSettings->get('fetch.timeout'); + if ($this->fetchQueue->numberOfItems()) { + // Delete any stored project data as that needs refreshing when + // update_calculate_project_data() is called. + $this->tempStore->delete('update_project_data'); + } while (time() < $end && ($item = $this->fetchQueue->claimItem())) { $this->processFetchTask($item->data); $this->fetchQueue->deleteItem($item); diff --git a/core/modules/update/tests/fixtures/release-history/drupal.broken.xml b/core/modules/update/tests/fixtures/release-history/drupal.broken.xml new file mode 100644 index 0000000000000000000000000000000000000000..1ba5d5e408acf5191e4c309a5cc643e69c6fc83a --- /dev/null +++ b/core/modules/update/tests/fixtures/release-history/drupal.broken.xml @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="utf-8"?> +<project xmlns:dc="http://purl.org/dc/elements/1.1/"> +</project> diff --git a/core/modules/update/tests/src/Functional/UpdateCoreTest.php b/core/modules/update/tests/src/Functional/UpdateCoreTest.php index 63a5b603a5b55ae8754ae729f5473863f8aab7fd..7cab37d06798828aac0c685f21f67da3e297bcc9 100644 --- a/core/modules/update/tests/src/Functional/UpdateCoreTest.php +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php @@ -862,6 +862,43 @@ public function testRevokedRelease() { } } + /** + * Checks that Drupal recovers after problems connecting to update server. + */ + public function testBrokenThenFixedUpdates() { + $this->drupalLogin($this->drupalCreateUser([ + 'administer site configuration', + 'access administration pages', + ])); + $this->setSystemInfo('8.0.0'); + // Instead of using refreshUpdateStatus(), set these manually. + $this->config('update.settings') + ->set('fetch.url', Url::fromRoute('update_test.update_test')->setAbsolute()->toString()) + ->save(); + // Use update XML that has no information to simulate a broken response from + // the update server. + $this->config('update_test.settings') + ->set('xml_map', ['drupal' => 'broken']) + ->save(); + + // This will retrieve broken updates. + $this->cronRun(); + $this->drupalGet('admin/reports/status'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->pageTextContains('There was a problem checking available updates for Drupal.'); + $this->config('update_test.settings') + ->set('xml_map', ['drupal' => 'sec.0.2']) + ->save(); + // Simulate the update_available_releases state expiring before cron is run + // and the state is used by \Drupal\update\UpdateManager::getProjects(). + \Drupal::keyValueExpirable('update_available_releases')->deleteAll(); + // This cron run should retrieve fixed updates. + $this->cronRun(); + $this->drupalGet('admin/structure'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->pageTextContains('There is a security update available for your version of Drupal.'); + } + /** * Tests messages when a project release is marked unsupported. *