You are here

class AcquiaSearchUnitTestCase in Acquia Connector 7.3

Same name and namespace in other branches
  1. 7.2 acquia_search/tests/acquia_search.test \AcquiaSearchUnitTestCase

Unit tests of the functionality of the Acquia Search module.

Hierarchy

Expanded class hierarchy of AcquiaSearchUnitTestCase

File

acquia_search/tests/acquia_search.test, line 13
Tests for the Acquia Search module.

View source
class AcquiaSearchUnitTestCase extends DrupalUnitTestCase {

  /**
   * Id.
   *
   * @var string
   */
  protected $id;

  /**
   * Key.
   *
   * @var string
   */
  protected $key;

  /**
   * Salt.
   *
   * @var string
   */
  protected $salt;

  /**
   * Derived key.
   *
   * @var string
   */
  protected $derivedKey;

  /**
   * Needs comment.
   */
  public static function getInfo() {
    return array(
      'name' => 'Acquia Search unit tests',
      'description' => 'Tests the low level Acquia Search functions.',
      'group' => 'Acquia',
    );
  }

  /**
   * Overrides DrupalTestCase::setUp().
   */
  public function setUp() {
    parent::setUp();
    require_once dirname(dirname(__FILE__)) . '/acquia_search.module';
    require_once dirname(dirname(__FILE__)) . '/src/PreferredSearchCoreService.php';
    if (!function_exists('acquia_agent_settings')) {
      module_load_include('module', 'acquia_agent');
    }

    // Generate and store a random set of credentials.
    // Make them as close to the production values as possible
    // Something like AAAA-1234.
    $this->id = $this
      ->randomName(10);

    // Most of the keys and salts have a 32char lenght.
    $this->key = $this
      ->randomName(32);
    $this->salt = $this
      ->randomName(32);

    // Create a derived key from these values.
    $this->derivedKey = _acquia_search_create_derived_key($this->salt, $this->id, $this->key);
  }

  /**
   * Tests derived key generation.
   */
  public function testDerivedKey() {

    // Mimic the hashing code in the API function.
    $derivation_string = $this->id . 'solr' . $this->salt;

    // str_pad extends the string with the same string in this case
    // until it has filled 80 chars.
    $derived_key = hash_hmac('sha1', str_pad($derivation_string, 80, $derivation_string), $this->key);

    // $this->derivedKey is generated from the API function.
    // @see setUp()
    $this
      ->assertEqual($this->derivedKey, $derived_key, t('Derived key API function generates the expected hash.'), 'Acquia Search');
  }

  /**
   * Tests HMAC generation.
   */
  public function testHmacCookie() {

    // Generate the expected hash.
    $time = time();
    $nonce = $this
      ->randomName(32);
    $string = $time . $nonce . $this
      ->randomName();
    $hmac = hash_hmac('sha1', $time . $nonce . $string, $this->derivedKey);

    // @todo Make the API function more testable.
    $authenticator = acquia_search_authenticator($string, $nonce, $this->derivedKey, $time);
    preg_match('/acquia_solr_hmac=([a-zA-Z0-9]{40});/', $authenticator, $matches);
    $this
      ->assertEqual($hmac, $matches[1], t('HMAC API function generates the expected hmac hash.'), 'Acquia Search');
    preg_match('/acquia_solr_time=([0-9]{10});/', $authenticator, $matches);
    $this
      ->assertNotNull($matches, t('HMAC API function generates a timestamp.'), 'Acquia Search');
    preg_match('/acquia_solr_nonce=([a-zA-Z0-9]{32});/', $authenticator, $matches);
    $this
      ->assertEqual($nonce, $matches[1], t('HMAC API function generates the expected nonce.'), 'Acquia Search');
  }

  /**
   * Tests validating a response via the API functions.
   */
  public function testValidResponse() {

    // Generate the expected hash.
    $nonce = $this
      ->randomName(32);
    $string = $this
      ->randomName(32);
    $hmac = hash_hmac('sha1', $nonce . $string, $this->derivedKey);

    // Pass the expected hmac digest, API function should return TRUE.
    $valid = acquia_search_valid_response($hmac, $nonce, $string, $this->derivedKey);
    $this
      ->assertTrue($valid, t('Response flagged as valid when the expected hash is passed.'), 'Acquia Search');

    // Invalidate the hmac digest, API function should return FALSE.
    $bad_hmac = $hmac . 'invalidateHash';
    $invalid_hmac = acquia_search_valid_response($bad_hmac, $nonce, $string, $this->derivedKey);
    $this
      ->assertFalse($invalid_hmac, t('Response flagged as invalid when a malformed hash is passed.'), 'Acquia Search');

    // Invalidate the nonce, API function should return FALSE.
    $bad_nonce = $nonce . 'invalidateString';
    $invalid_nonce = acquia_search_valid_response($hmac, $bad_nonce, $bad_nonce, $this->derivedKey);
    $this
      ->assertFalse($invalid_nonce, t('Response flagged as invalid when a malformed nonce is passed.'), 'Acquia Search');

    // Invalidate the string, API function should return FALSE.
    $bad_string = $string . 'invalidateString';
    $invalid_string = acquia_search_valid_response($hmac, $nonce, $bad_string, $this->derivedKey);
    $this
      ->assertFalse($invalid_string, t('Response flagged as invalid when a malformed string is passed.'), 'Acquia Search');

    // Invalidate the derived key, API function should return FALSE.
    $bad_key = $this->derivedKey . 'invalidateKey';
    $invalid_key = acquia_search_valid_response($hmac, $nonce, $string, $bad_key);
    $this
      ->assertFalse($invalid_key, t('Response flagged as invalid when a malformed derived key is passed.'), 'Acquia Search');
  }

  /**
   * Tests extracting the hmac digest from the response header.
   */
  public function testExtractHmacHeader() {

    // Generate the expected hash.
    $nonce = $this
      ->randomName(32);
    $string = $this
      ->randomName(32);
    $hmac = hash_hmac('sha1', $nonce . $string, $this->derivedKey);

    // Pass header with an expected pragma.
    $header = array(
      'pragma' => 'hmac_digest=' . $hmac . ';',
    );
    $extracted = acquia_search_extract_hmac($header);
    $this
      ->assertEqual($hmac, $extracted, t('The HMAC digest was extracted from the response header.'), 'Acquia Search');

    // Pass header with a bad pragma.
    $bad_header1 = array(
      'pragma' => $this
        ->randomName(),
    );
    $bad_extracted1 = acquia_search_extract_hmac($bad_header1);
    $this
      ->assertEqual('', $bad_extracted1, t('Empty string returned by HMAC extraction function when an invalid pragma is passed.'), 'Acquia Search');

    // Pass in junk as the header.
    $bad_extracted2 = acquia_search_extract_hmac($this
      ->randomName());
    $this
      ->assertEqual('', $bad_extracted2, t('Empty string returned by HMAC extraction function when an invalid header is passed.'), 'Acquia Search');
  }

  /**
   * Tests that Acquia Search properly overrides the Apachesolr connection.
   *
   * This avoids unintended writing to a wrong search index.
   */
  public function testApacheSolrOverride() {
    global $conf;
    $acquia_identifier = $this->id;
    $site_folder = $this
      ->randomName(32);
    $solr_hostname = $this
      ->randomName(10) . '.acquia-search.com';
    $available_cores = array(
      array(
        'balancer' => $solr_hostname,
        'core_id' => "{$acquia_identifier}.dev.{$site_folder}",
      ),
      array(
        'balancer' => $solr_hostname,
        'core_id' => "{$acquia_identifier}.dev.testdbname",
      ),
      array(
        'balancer' => $solr_hostname,
        'core_id' => "{$acquia_identifier}",
      ),
    );
    $environments = $this
      ->getMockedEnvironments();

    // No Acquia hosting and DB detected - should override into Readonly.
    unset($conf['apachesolr_environments']);
    $ah_env = NULL;
    $ah_db_name = '';
    $core_service = new PreferredSearchCoreService($acquia_identifier, $ah_env, $site_folder, $ah_db_name, $available_cores);
    acquia_search_add_apachesolr_overrides($core_service, $environments);
    $this
      ->assertTrue($conf['apachesolr_environments']['ACQUIA']['conf']['apachesolr_read_only']);
    $this
      ->assertTrue(empty($conf['apachesolr_environments']['ACQUIA']['conf']['acquia_search_key']));

    // Acquia Dev hosting environment detected - configs point to the index on
    // the Dev environment.
    unset($conf['apachesolr_environments']);
    $ah_env = 'dev';
    $core_service = new PreferredSearchCoreService($acquia_identifier, $ah_env, $site_folder, $ah_db_name, $available_cores);
    acquia_search_add_apachesolr_overrides($core_service, $environments);
    $this
      ->assertTrue(empty($conf['apachesolr_environments']['ACQUIA']['conf']['apachesolr_read_only']));
    $this
      ->assertTrue(!empty($conf['apachesolr_environments']['ACQUIA']['conf']['acquia_search_key']));
    $this
      ->assertIdentical($conf['apachesolr_environments']['ACQUIA']['url'], "http://{$solr_hostname}/solr/{$acquia_identifier}.dev.{$site_folder}");

    // Acquia dev environment and a DB name.
    unset($conf['apachesolr_environments']);
    $ah_env = 'dev';
    $ah_db_name = 'testdbname';
    $core_service = new PreferredSearchCoreService($acquia_identifier, $ah_env, $site_folder, $ah_db_name, $available_cores);
    acquia_search_add_apachesolr_overrides($core_service, $environments);
    $this
      ->assertTrue(empty($conf['apachesolr_environments']['ACQUIA']['conf']['apachesolr_read_only']));
    $this
      ->assertTrue(!empty($conf['apachesolr_environments']['ACQUIA']['conf']['acquia_search_key']));
    $this
      ->assertIdentical($conf['apachesolr_environments']['ACQUIA']['url'], "http://{$solr_hostname}/solr/{$acquia_identifier}.dev.{$ah_db_name}");

    // Acquia Test environment and a DB name. According to the mock, no cores
    // available for the Test environment so it is read only.
    unset($conf['apachesolr_environments']);
    $ah_env = 'test';
    $ah_db_name = 'testdbname';
    $core_service = new PreferredSearchCoreService($acquia_identifier, $ah_env, $site_folder, $ah_db_name, $available_cores);
    acquia_search_add_apachesolr_overrides($core_service, $environments);
    $this
      ->assertTrue($conf['apachesolr_environments']['ACQUIA']['conf']['apachesolr_read_only']);
    $this
      ->assertTrue(empty($conf['apachesolr_environments']['ACQUIA']['conf']['acquia_search_key']));
    $this
      ->assertTrue(empty($conf['apachesolr_environments']['ACQUIA']['url']));

    // Acquia Prod environment and a DB name but AH_PRODUCTION isn't set - so
    // read only.
    unset($conf['apachesolr_environments']);
    $ah_env = 'prod';
    $ah_db_name = 'testdbname';
    $core_service = new PreferredSearchCoreService($acquia_identifier, $ah_env, $site_folder, $ah_db_name, $available_cores);
    acquia_search_add_apachesolr_overrides($core_service, $environments);
    $this
      ->assertTrue($conf['apachesolr_environments']['ACQUIA']['conf']['apachesolr_read_only']);
    $this
      ->assertTrue(empty($conf['apachesolr_environments']['ACQUIA']['conf']['acquia_search_key']));
    $this
      ->assertTrue(empty($conf['apachesolr_environments']['ACQUIA']['url']));

    // Acquia Prod environment and a DB name and AH_PRODUCTION is set - so it
    // should override to connect to the prod index.
    unset($conf['apachesolr_environments']);
    $_SERVER['AH_PRODUCTION'] = 1;
    $ah_env = 'prod';
    $ah_db_name = 'testdbname';
    $core_service = new PreferredSearchCoreService($acquia_identifier, $ah_env, $site_folder, $ah_db_name, $available_cores);
    acquia_search_add_apachesolr_overrides($core_service, $environments);
    $this
      ->assertTrue(empty($conf['apachesolr_environments']['ACQUIA']['conf']['apachesolr_read_only']));
    $this
      ->assertTrue(!empty($conf['apachesolr_environments']['ACQUIA']['conf']['acquia_search_key']));
    $this
      ->assertIdentical($conf['apachesolr_environments']['ACQUIA']['url'], "http://{$solr_hostname}/solr/{$acquia_identifier}");

    // Trying to override already overridden settings should not succeed.
    unset($_SERVER['AH_PRODUCTION']);
    $ah_env = 'dev';
    $ah_db_name = 'testdbname';
    $core_service = new PreferredSearchCoreService($acquia_identifier, $ah_env, $site_folder, $ah_db_name, $available_cores);
    acquia_search_add_apachesolr_overrides($core_service, $environments);
    $this
      ->assertTrue(empty($conf['apachesolr_environments']['ACQUIA']['conf']['apachesolr_read_only']));
    $this
      ->assertTrue(!empty($conf['apachesolr_environments']['ACQUIA']['conf']['acquia_search_key']));
    $this
      ->assertIdentical($conf['apachesolr_environments']['ACQUIA']['url'], "http://{$solr_hostname}/solr/{$acquia_identifier}");
  }

  /**
   * Test override.
   *
   * Tests that it selects the correct preferred search core ID for the
   * override URL when limited number of core ID is available.
   */
  public function testApacheSolrOverrideWhenCoreWithDbNameNotAvailable() {

    // When the core ID with the DB name in it is not available, it should
    // override the URL value with the core ID that has the site folder name
    // in it.
    global $conf;
    unset($conf['apachesolr_environments']);
    $acquia_identifier = $this->id;
    $site_folder = $this
      ->randomName(32);
    $solr_hostname = $this
      ->randomName(10) . '.acquia-search.com';
    $available_cores = array(
      array(
        'balancer' => $solr_hostname,
        'core_id' => "{$acquia_identifier}.dev.{$site_folder}",
      ),
      array(
        'balancer' => $solr_hostname,
        'core_id' => "{$acquia_identifier}",
      ),
    );
    $environments = $this
      ->getMockedEnvironments();
    $ah_env = 'dev';
    $ah_db_name = 'testdbname';
    $core_service = new PreferredSearchCoreService($acquia_identifier, $ah_env, $site_folder, $ah_db_name, $available_cores);
    acquia_search_add_apachesolr_overrides($core_service, $environments);
    $expected_url = "http://{$solr_hostname}/solr/{$acquia_identifier}.dev.{$site_folder}";
    $this
      ->assertIdentical($conf['apachesolr_environments']['ACQUIA']['url'], $expected_url);
  }

  /**
   * Tests that existing apachesolr Acquia Search environments get overridden.
   */
  public function testApacheSolrOverrideAllAcquiaEnvironments() {
    global $conf;
    unset($conf['apachesolr_environments']);
    $acquia_identifier = $this->id;
    $site_folder = $this
      ->randomName(32);
    $solr_hostname = $this
      ->randomName(10) . '.acquia-search.com';
    $available_cores = array(
      array(
        'balancer' => $solr_hostname,
        'core_id' => "{$acquia_identifier}.dev.{$site_folder}",
      ),
      array(
        'balancer' => $solr_hostname,
        'core_id' => "{$acquia_identifier}.dev.testdbname",
      ),
      array(
        'balancer' => $solr_hostname,
        'core_id' => "{$acquia_identifier}",
      ),
    );
    $environments = $this
      ->getMockedEnvironments();
    $ah_env = 'dev';
    $ah_db_name = 'testdbname';
    $core_service = new PreferredSearchCoreService($acquia_identifier, $ah_env, $site_folder, $ah_db_name, $available_cores);
    acquia_search_add_apachesolr_overrides($core_service, $environments);
    $expected_url = "http://{$solr_hostname}/solr/{$acquia_identifier}.dev.{$ah_db_name}";
    $this
      ->assertIdentical($conf['apachesolr_environments']['ACQUIA']['url'], $expected_url);
    $this
      ->assertIdentical($conf['apachesolr_environments']['ACQUIA_2']['url'], $expected_url);
    $this
      ->assertTrue(empty($conf['apachesolr_environments']['NON-ACQUIA']['url']));
  }

  /**
   * Returns mocked apachesolr environments.
   */
  public function getMockedEnvironments() {
    return array(
      'ACQUIA' => array(
        'env_id' => 'acquia_search_server_1',
        'name' => 'Acquia Search',
        'url' => 'http://mock.acquia-search.com/solr/ABCD-12345',
        'service_class' => 'AcquiaSearchService',
        'table' => 'apachesolr_environment',
        'type' => 'Normal',
        'export_type' => 1,
        'index_bundles' => array(
          'node' => array(
            0 => 'article',
            1 => 'page',
          ),
        ),
      ),
      'ACQUIA_2' => array(
        'env_id' => 'acquia_search_server_2',
        'name' => 'Acquia Search 2',
        'url' => 'http://mock.acquia-search.com/solr/XYZW-12345',
        'service_class' => 'AcquiaSearchService',
        'table' => 'apachesolr_environment',
        'type' => 'Normal',
        'export_type' => 1,
        'index_bundles' => array(
          'node' => array(
            0 => 'article',
            1 => 'page',
          ),
        ),
      ),
      'NON-ACQUIA' => array(
        'env_id' => 'solr',
        'name' => 'localhost server',
        'url' => 'http://localhost:8983/solr',
        'service_class' => '',
        'table' => 'apachesolr_environment',
        'type' => 'Normal',
        'export_type' => 1,
        'index_bundles' => array(
          'node' => array(
            0 => 'article',
            1 => 'page',
          ),
        ),
        'conf' => array(
          'apachesolr_index_last' => array(),
        ),
      ),
    );
  }

}

Members

Namesort descending Modifiers Type Description Overrides
AcquiaSearchUnitTestCase::$derivedKey protected property Derived key.
AcquiaSearchUnitTestCase::$id protected property Id.
AcquiaSearchUnitTestCase::$key protected property Key.
AcquiaSearchUnitTestCase::$salt protected property Salt.
AcquiaSearchUnitTestCase::getInfo public static function Needs comment.
AcquiaSearchUnitTestCase::getMockedEnvironments public function Returns mocked apachesolr environments.
AcquiaSearchUnitTestCase::setUp public function Overrides DrupalTestCase::setUp(). Overrides DrupalUnitTestCase::setUp
AcquiaSearchUnitTestCase::testApacheSolrOverride public function Tests that Acquia Search properly overrides the Apachesolr connection.
AcquiaSearchUnitTestCase::testApacheSolrOverrideAllAcquiaEnvironments public function Tests that existing apachesolr Acquia Search environments get overridden.
AcquiaSearchUnitTestCase::testApacheSolrOverrideWhenCoreWithDbNameNotAvailable public function Test override.
AcquiaSearchUnitTestCase::testDerivedKey public function Tests derived key generation.
AcquiaSearchUnitTestCase::testExtractHmacHeader public function Tests extracting the hmac digest from the response header.
AcquiaSearchUnitTestCase::testHmacCookie public function Tests HMAC generation.
AcquiaSearchUnitTestCase::testValidResponse public function Tests validating a response via the API functions.
DrupalTestCase::$assertions protected property Assertions thrown in that test case.
DrupalTestCase::$databasePrefix protected property The database prefix of this test run.
DrupalTestCase::$originalFileDirectory protected property The original file directory, before it was changed for testing purposes.
DrupalTestCase::$results public property Current results of this test case.
DrupalTestCase::$setup protected property Flag to indicate whether the test has been set up.
DrupalTestCase::$setupDatabasePrefix protected property
DrupalTestCase::$setupEnvironment protected property
DrupalTestCase::$skipClasses protected property This class is skipped when looking for the source of an assertion.
DrupalTestCase::$testId protected property The test run ID.
DrupalTestCase::$timeLimit protected property Time limit for the test.
DrupalTestCase::$useSetupInstallationCache public property Whether to cache the installation part of the setUp() method.
DrupalTestCase::$useSetupModulesCache public property Whether to cache the modules installation part of the setUp() method.
DrupalTestCase::$verboseDirectoryUrl protected property URL to the verbose output file directory.
DrupalTestCase::assert protected function Internal helper: stores the assert.
DrupalTestCase::assertEqual protected function Check to see if two values are equal.
DrupalTestCase::assertFalse protected function Check to see if a value is false (an empty string, 0, NULL, or FALSE).
DrupalTestCase::assertIdentical protected function Check to see if two values are identical.
DrupalTestCase::assertNotEqual protected function Check to see if two values are not equal.
DrupalTestCase::assertNotIdentical protected function Check to see if two values are not identical.
DrupalTestCase::assertNotNull protected function Check to see if a value is not NULL.
DrupalTestCase::assertNull protected function Check to see if a value is NULL.
DrupalTestCase::assertTrue protected function Check to see if a value is not false (not an empty string, 0, NULL, or FALSE).
DrupalTestCase::deleteAssert public static function Delete an assertion record by message ID.
DrupalTestCase::error protected function Fire an error assertion. 1
DrupalTestCase::errorHandler public function Handle errors during test runs. 1
DrupalTestCase::exceptionHandler protected function Handle exceptions.
DrupalTestCase::fail protected function Fire an assertion that is always negative.
DrupalTestCase::generatePermutations public static function Converts a list of possible parameters into a stack of permutations.
DrupalTestCase::getAssertionCall protected function Cycles through backtrace until the first non-assertion method is found.
DrupalTestCase::getDatabaseConnection public static function Returns the database connection to the site running Simpletest.
DrupalTestCase::insertAssert public static function Store an assertion from outside the testing context.
DrupalTestCase::pass protected function Fire an assertion that is always positive.
DrupalTestCase::randomName public static function Generates a random string containing letters and numbers.
DrupalTestCase::randomString public static function Generates a random string of ASCII characters of codes 32 to 126.
DrupalTestCase::run public function Run all tests in this class.
DrupalTestCase::verbose protected function Logs a verbose message in a text file.
DrupalUnitTestCase::tearDown protected function 1
DrupalUnitTestCase::__construct function Constructor for DrupalUnitTestCase. Overrides DrupalTestCase::__construct