From 332530474ea2d69162d374cbadbf85c59e4d16aa Mon Sep 17 00:00:00 2001
From: webchick <webchick@24967.no-reply.drupal.org>
Date: Tue, 8 Oct 2013 22:36:58 -0700
Subject: [PATCH] Issue #2002116 by damiankloip, jhedstrom, ParisLiakos,
 dawehner: Convert
 core/modules/update/lib/Drupal/update/Tests/UpdateCoreUnitTest.php to
 phpunit.

---
 .../update/Tests/UpdateCoreUnitTest.php       |  77 ---------
 .../lib/Drupal/update/UpdateFetcher.php       | 149 ++++++++++++++++++
 .../Drupal/update/Tests/UpdateFetcherTest.php | 114 ++++++++++++++
 core/modules/update/update.fetch.inc          |  90 +----------
 core/modules/update/update.module             |   5 -
 5 files changed, 268 insertions(+), 167 deletions(-)
 delete mode 100644 core/modules/update/lib/Drupal/update/Tests/UpdateCoreUnitTest.php
 create mode 100644 core/modules/update/lib/Drupal/update/UpdateFetcher.php
 create mode 100644 core/modules/update/tests/Drupal/update/Tests/UpdateFetcherTest.php

diff --git a/core/modules/update/lib/Drupal/update/Tests/UpdateCoreUnitTest.php b/core/modules/update/lib/Drupal/update/Tests/UpdateCoreUnitTest.php
deleted file mode 100644
index 89c41c2b666a..000000000000
--- a/core/modules/update/lib/Drupal/update/Tests/UpdateCoreUnitTest.php
+++ /dev/null
@@ -1,77 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\update\Tests\UpdateCoreUnitTest.
- */
-
-namespace Drupal\update\Tests;
-
-use Drupal\simpletest\UnitTestBase;
-
-/**
- * Tests update functionality unrelated to the database.
- */
-class UpdateCoreUnitTest extends UnitTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('update');
-
-  public static function getInfo() {
-    return array(
-      'name' => "Unit tests",
-      'description' => 'Test update functionality unrelated to the database.',
-      'group' => 'Update',
-    );
-  }
-
-  function setUp() {
-    parent::setUp();
-    module_load_include('inc', 'update', 'update.fetch');
-  }
-
-  /**
-   * Tests that _update_build_fetch_url() builds the URL correctly.
-   */
-  function testUpdateBuildFetchUrl() {
-    //first test that we didn't break the trivial case
-    $project['name'] = 'update_test';
-    $project['project_type'] = '';
-    $project['info']['version'] = '';
-    $project['info']['project status url'] = 'http://www.example.com';
-    $project['includes'] = array('module1' => 'Module 1', 'module2' => 'Module 2');
-    $site_key = '';
-    $expected = 'http://www.example.com/' . $project['name'] . '/' . \Drupal::CORE_COMPATIBILITY;
-    $url = _update_build_fetch_url($project, $site_key);
-    $this->assertEqual($url, $expected, "'$url' when no site_key provided should be '$expected'.");
-
-    //For disabled projects it shouldn't add the site key either.
-    $site_key = 'site_key';
-    $project['project_type'] = 'disabled';
-    $expected = 'http://www.example.com/' . $project['name'] . '/' . \Drupal::CORE_COMPATIBILITY;
-    $url = _update_build_fetch_url($project, $site_key);
-    $this->assertEqual($url, $expected, "'$url' should be '$expected' for disabled projects.");
-
-    //for enabled projects, adding the site key
-    $project['project_type'] = '';
-    $expected = 'http://www.example.com/' . $project['name'] . '/' . \Drupal::CORE_COMPATIBILITY;
-    $expected .= '?site_key=site_key';
-    $expected .= '&list=' . rawurlencode('module1,module2');
-    $url = _update_build_fetch_url($project, $site_key);
-    $this->assertEqual($url, $expected, "When site_key provided, '$url' should be '$expected'.");
-
-    // http://drupal.org/node/1481156 test incorrect logic when URL contains
-    // a question mark.
-    $project['info']['project status url'] = 'http://www.example.com/?project=';
-    $expected = 'http://www.example.com/?project=/' . $project['name'] . '/' . \Drupal::CORE_COMPATIBILITY;
-    $expected .= '&site_key=site_key';
-    $expected .= '&list=' . rawurlencode('module1,module2');
-    $url = _update_build_fetch_url($project, $site_key);
-    $this->assertEqual($url, $expected, "When ? is present, '$url' should be '$expected'.");
-
-  }
-}
diff --git a/core/modules/update/lib/Drupal/update/UpdateFetcher.php b/core/modules/update/lib/Drupal/update/UpdateFetcher.php
new file mode 100644
index 000000000000..063988c37581
--- /dev/null
+++ b/core/modules/update/lib/Drupal/update/UpdateFetcher.php
@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\update\UpdateFetcher.
+ */
+
+namespace Drupal\update;
+
+use Drupal\Core\Config\ConfigFactory;
+use Guzzle\Http\ClientInterface;
+use Guzzle\Http\Exception\RequestException;
+
+/**
+ * Fetches project information from remote locations.
+ */
+class UpdateFetcher {
+
+  /**
+   * URL to check for updates, if a given project doesn't define its own.
+   */
+  const UPDATE_DEFAULT_URL = 'http://updates.drupal.org/release-history';
+
+  /**
+   * The fetch url configured in the update settings.
+   *
+   * @var string
+   */
+  protected $fetchUrl;
+
+  /**
+   * The HTTP client to fetch the feed data with.
+   *
+   * @var \Guzzle\Http\ClientInterface
+   */
+  protected $httpClient;
+
+  /**
+   * Constructs a UpdateFetcher.
+   *
+   * @param \Drupal\Core\Config\ConfigFactory $config_factory
+   *   The config factory.
+   * @param \Guzzle\Http\ClientInterface $http_client
+   *   A Guzzle client object.
+   */
+  public function __construct(ConfigFactory $config_factory, ClientInterface $http_client) {
+    $this->fetchUrl = $config_factory->get('update.settings')->get('fetch.url');
+    $this->httpClient = $http_client;
+  }
+
+  /**
+   * Retrieves the project information.
+   *
+   * @param array $project
+   *   The array of project information from update_get_projects().
+   * @param string $site_key
+   *   (optional) The anonymous site key hash. Defaults to an empty string.
+   *
+   * @return string
+   *   The project information fetched as string. Empty string upon failure.
+   */
+  public function fetchProjectData(array $project, $site_key = '') {
+    $url = $this->buildFetchUrl($project, $site_key);
+    $data = '';
+    try {
+      $data = $this->httpClient
+        ->get($url, array('Accept' => 'text/xml'))
+        ->send()
+        ->getBody(TRUE);
+    }
+    catch (RequestException $exception) {
+      watchdog_exception('update', $exception);
+    }
+    return $data;
+  }
+
+  /**
+   * Generates the URL to fetch information about project updates.
+   *
+   * This figures out the right URL to use, based on the project's .info.yml file
+   * and the global defaults. Appends optional query arguments when the site is
+   * configured to report usage stats.
+   *
+   * @param array $project
+   *   The array of project information from update_get_projects().
+   * @param string $site_key
+   *   (optional) The anonymous site key hash. Defaults to an empty string.
+   *
+   * @return string
+   *   The URL for fetching information about updates to the specified project.
+   *
+   * @see update_fetch_data()
+   * @see _update_process_fetch_task()
+   * @see update_get_projects()
+   */
+  public function buildFetchUrl(array $project, $site_key = '') {
+    $name = $project['name'];
+    $url = $this->getFetchBaseUrl($project);
+    $url .= '/' . $name . '/' . \Drupal::CORE_COMPATIBILITY;
+
+    // Only append usage infomation if we have a site key and the project is
+    // enabled. We do not want to record usage statistics for disabled projects.
+    if (!empty($site_key) && (strpos($project['project_type'], 'disabled') === FALSE)) {
+      // Append the site key.
+      $url .= (strpos($url, '?') !== FALSE) ? '&' : '?';
+      $url .= 'site_key=';
+      $url .= rawurlencode($site_key);
+
+      // Append the version.
+      if (!empty($project['info']['version'])) {
+        $url .= '&version=';
+        $url .= rawurlencode($project['info']['version']);
+      }
+
+      // Append the list of modules or themes enabled.
+      $list = array_keys($project['includes']);
+      $url .= '&list=';
+      $url .= rawurlencode(implode(',', $list));
+    }
+    return $url;
+  }
+
+  /**
+   * Returns the base of the URL to fetch available update data for a project.
+   *
+   * @param array $project
+   *   The array of project information from update_get_projects().
+   *
+   * @return string
+   *   The base of the URL used for fetching available update data. This does
+   *   not include the path elements to specify a particular project, version,
+   *   site_key, etc.
+   *
+   * @see \Drupal\update\UpdateFetcher::getFetchBaseUrl()
+   */
+  public function getFetchBaseUrl($project) {
+    if (isset($project['info']['project status url'])) {
+      $url = $project['info']['project status url'];
+    }
+    else {
+      $url = $this->fetchUrl;
+      if (empty($url)) {
+        $url = static::UPDATE_DEFAULT_URL;
+      }
+    }
+    return $url;
+  }
+
+}
diff --git a/core/modules/update/tests/Drupal/update/Tests/UpdateFetcherTest.php b/core/modules/update/tests/Drupal/update/Tests/UpdateFetcherTest.php
new file mode 100644
index 000000000000..e43a3ae47381
--- /dev/null
+++ b/core/modules/update/tests/Drupal/update/Tests/UpdateFetcherTest.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\update\Tests\UpdateFetcherTest.
+ */
+
+namespace Drupal\update\Tests;
+
+use Drupal\Tests\UnitTestCase;
+use Drupal\update\UpdateFetcher;
+
+if (!defined('DRUPAL_CORE_COMPATIBILITY')) {
+  define('DRUPAL_CORE_COMPATIBILITY', '8.x');
+}
+
+/**
+ * Tests update functionality unrelated to the database.
+ */
+class UpdateFetcherTest extends UnitTestCase {
+
+  /**
+   * The update fetcher to use.
+   *
+   * @var \Drupal\update\UpdateFetcher
+   */
+  protected $updateFetcher;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Core update tests',
+      'description' => 'Test update functionality unrelated to the database.',
+      'group' => 'Update',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    $config_factory = $this->getConfigFactoryStub(array('update.settings' => array('fetch_url' => 'http://www.example.com')));
+    $this->updateFetcher = new UpdateFetcher($config_factory, $this->getMock('Guzzle\Http\Client'));
+  }
+
+  /**
+   * Tests that buildFetchUrl() builds the URL correctly.
+   *
+   * @param array $project
+   *   A keyed array of project information matching results from update_get_projects().
+   * @param string $site_key
+   *   A string to mimic an anonymous site key hash.
+   * @param string $expected
+   *   The expected url returned from UpdateFetcher::buildFetchUrl()
+   *
+   * @dataProvider providerTestUpdateBuildFetchUrl
+   *
+   * @see \Drupal\update\UpdateFetcher::buildFetchUrl()
+   */
+  public function testUpdateBuildFetchUrl(array $project, $site_key, $expected) {
+    $url = $this->updateFetcher->buildFetchUrl($project, $site_key);
+    $this->assertEquals($url, $expected);
+  }
+
+  /**
+   * Provide test data for self::testUpdateBuildFetchUrl().
+   *
+   * @return array
+   *   An array of arrays, each containing:
+   *   - 'project' - An array matching a project's .info file structure.
+   *   - 'site_key' - An arbitrary site key.
+   *   - 'expected' - The expected url from UpdateFetcher::buildFetchUrl().
+   */
+  public function providerTestUpdateBuildFetchUrl() {
+    $data = array();
+
+    // First test that we didn't break the trivial case.
+    $project['name'] = 'update_test';
+    $project['project_type'] = '';
+    $project['info']['version'] = '';
+    $project['info']['project status url'] = 'http://www.example.com';
+    $project['includes'] = array('module1' => 'Module 1', 'module2' => 'Module 2');
+    $site_key = '';
+    $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY;
+
+    $data[] = array($project, $site_key, $expected);
+
+    // For disabled projects it shouldn't add the site key either.
+    $site_key = 'site_key';
+    $project['project_type'] = 'disabled';
+    $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY;
+
+    $data[] = array($project, $site_key, $expected);
+
+    // For enabled projects, adding the site key
+    $project['project_type'] = '';
+    $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY;
+    $expected .= '?site_key=site_key';
+    $expected .= '&list=' . rawurlencode('module1,module2');
+
+    $data[] = array($project, $site_key, $expected);
+
+    // http://drupal.org/node/1481156 test incorrect logic when URL contains
+    // a question mark.
+    $project['info']['project status url'] = 'http://www.example.com/?project=';
+    $expected = 'http://www.example.com/?project=/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY;
+    $expected .= '&site_key=site_key';
+    $expected .= '&list=' . rawurlencode('module1,module2');
+
+    $data[] = array($project, $site_key, $expected);
+
+    return $data;
+  }
+
+}
diff --git a/core/modules/update/update.fetch.inc b/core/modules/update/update.fetch.inc
index ac3c1b5a8efd..293256097d41 100644
--- a/core/modules/update/update.fetch.inc
+++ b/core/modules/update/update.fetch.inc
@@ -5,8 +5,8 @@
  * Code required only when fetching information about available updates.
  */
 
-use Guzzle\Http\Exception\RequestException;
 use Drupal\Component\Utility\Crypt;
+use Drupal\update\UpdateFetcher;
 
 /**
  * Page callback: Checks for updates and displays the update status report.
@@ -148,21 +148,13 @@ function _update_process_fetch_task($project) {
 
   $success = FALSE;
   $available = array();
-  $site_key = Crypt::hmacBase64($base_url, drupal_get_private_key());
-  $url = _update_build_fetch_url($project, $site_key);
-  $fetch_url_base = _update_get_fetch_url_base($project);
+  $site_key = Crypt::hmacBase64($base_url, \Drupal::service('private_key')->get());
+  $update_fetcher = new UpdateFetcher(\Drupal::service('config.factory'), \Drupal::service('http_default_client'));
+  $fetch_url_base = $update_fetcher->getFetchBaseUrl($project);
   $project_name = $project['name'];
 
   if (empty($fail[$fetch_url_base]) || $fail[$fetch_url_base] < $max_fetch_attempts) {
-    try {
-      $data = \Drupal::httpClient()
-        ->get($url, array('Accept' => 'text/xml'))
-        ->send()
-        ->getBody(TRUE);
-    }
-    catch (RequestException $exception) {
-      watchdog_exception('update', $exception);
-    }
+    $data = $update_fetcher->fetchProjectData($project, $site_key);
   }
 
   if (!empty($data)) {
@@ -257,78 +249,6 @@ function _update_create_fetch_task($project) {
   }
 }
 
-/**
- * Generates the URL to fetch information about project updates.
- *
- * This figures out the right URL to use, based on the project's .info.yml file
- * and the global defaults. Appends optional query arguments when the site is
- * configured to report usage stats.
- *
- * @param $project
- *   The array of project information from update_get_projects().
- * @param $site_key
- *   (optional) The anonymous site key hash. Defaults to an empty string.
- *
- * @return
- *   The URL for fetching information about updates to the specified project.
- *
- * @see update_fetch_data()
- * @see _update_process_fetch_task()
- * @see update_get_projects()
- */
-function _update_build_fetch_url($project, $site_key = '') {
-  $name = $project['name'];
-  $url = _update_get_fetch_url_base($project);
-  $url .= '/' . $name . '/' . \Drupal::CORE_COMPATIBILITY;
-
-  // Only append usage infomation if we have a site key and the project is
-  // enabled. We do not want to record usage statistics for disabled projects.
-  if (!empty($site_key) && (strpos($project['project_type'], 'disabled') === FALSE)) {
-    // Append the site key.
-    $url .= (strpos($url, '?') !== FALSE) ? '&' : '?';
-    $url .= 'site_key=';
-    $url .= rawurlencode($site_key);
-
-    // Append the version.
-    if (!empty($project['info']['version'])) {
-      $url .= '&version=';
-      $url .= rawurlencode($project['info']['version']);
-    }
-
-    // Append the list of modules or themes enabled.
-    $list = array_keys($project['includes']);
-    $url .= '&list=';
-    $url .= rawurlencode(implode(',', $list));
-  }
-  return $url;
-}
-
-/**
- * Returns the base of the URL to fetch available update data for a project.
- *
- * @param $project
- *   The array of project information from update_get_projects().
- *
- * @return
- *   The base of the URL used for fetching available update data. This does
- *   not include the path elements to specify a particular project, version,
- *   site_key, etc.
- *
- * @see _update_build_fetch_url()
- */
-function _update_get_fetch_url_base($project) {
-  if (isset($project['info']['project status url'])) {
-    $url = $project['info']['project status url'];
-  }
-  else {
-    $url = \Drupal::config('update.settings')->get('fetch.url');
-    if (empty($url)) {
-      $url = UPDATE_DEFAULT_URL;
-    }
-  }
-  return $url;
-}
-
 /**
  * Performs any notifications that should be done once cron fetches new data.
  *
diff --git a/core/modules/update/update.module b/core/modules/update/update.module
index 4258644819f6..3c04664708c8 100644
--- a/core/modules/update/update.module
+++ b/core/modules/update/update.module
@@ -11,11 +11,6 @@
  * ability to install contributed modules and themes via an user interface.
  */
 
-/**
- * URL to check for updates, if a given project doesn't define its own.
- */
-const UPDATE_DEFAULT_URL = 'http://updates.drupal.org/release-history';
-
 // These are internally used constants for this code, do not modify.
 
 /**
-- 
GitLab