$v) { if (!isset($a2[$k])) { //debug("\$a2[$k] is not set"); return FALSE; } if (is_array($a1[$k]) && is_array($a2[$k])) { if (!$this->_nestedCompare($a1[$k], $a2[$k])) { //debug("_nestedCompare(\$a1[$k], \$a2[$k]) is false"); return FALSE; } } elseif ($a1[$k] !== $a2[$k]) { //debug("\$a1[$k] !== \$a2[$k] : " . var_export($a1[$k], TRUE) . " " . var_export($a2[$k], TRUE)); return FALSE; } } return TRUE; } } /** * @file * Unit test class that provides tests for base functionality of the Apachesolr * Module without having the need of a Solr Server */ class DrupalSolrOfflineEnvironmentWebTestCase extends DrupalSolrOfflineWebTestCase { /** * A global basic user who can search. */ var $basic_user; /** * A global administrative user who can administer search. */ var $admin_user; public static function getInfo() { return array( 'name' => 'Solr Search Environments', 'description' => 'Tests search environments functionality of the Solr module', 'group' => 'ApacheSolr', ); } /** * Implementation of setUp(). */ function setUp() { parent::setUp('apachesolr', 'search', 'apachesolr_search', 'apachesolr_test'); // Create a basic user, which is subject to moderation. $permissions = array( 'access content', 'search content', ); $basic_user = $this->drupalCreateUser($permissions); // Create an admin user that can bypass revision moderation. $permissions = array( 'access content', 'search content', 'administer nodes', 'administer search', ); $admin_user = $this->drupalCreateUser($permissions); // Assign users to their test suite-wide properties. $this->basic_user = $basic_user; $this->admin_user = $admin_user; } /** * Asserts that the module was installed and that a notice appears that the server is offline */ function testServerOffline() { // Load the default server. $env_id = apachesolr_default_environment(); $environment = apachesolr_environment_load($env_id); $environment['url'] = 'http://localhost/solr/core_that_should_not_exist'; apachesolr_environment_save($environment); $status = apachesolr_server_status($environment['url']); $this->assertFalse($status, t('A false URL could not be loaded and is offline')); $this->drupalLogin($this->admin_user); $this->drupalGet('admin/config/search/apachesolr'); $text = t('The server seems to be unavailable. Please verify the server settings'); $this->assertText($text, t('When checking the status of the server it gives the correct message to inform the user that the server is not reachable')); } /** * Asserts that the module was installed and that a notice appears that the server is offline */ function testIndexFileIncluded() { $env_id = apachesolr_default_environment(); $environment = apachesolr_environment_load($env_id); $environment['url'] = 'http://localhost/solr/core_that_should_not_exist'; apachesolr_environment_save($environment); $paths = array( 'user', 'node', 'admin/config/search/apachesolr', 'admin/config/search/apachesolr/search-pages', 'admin/config/search/apachesolr/search-pages/core_search/edit', 'admin/structure/block/manage/apachesolr_search/mlt-001/configure', 'admin/config/search/apachesolr/settings/solr/bias', 'admin/config/search/apachesolr/settings/solr/index', 'admin/config/search/apachesolr/settings/solr/edit', 'admin/reports/apachesolr', 'admin/reports/apachesolr/conf', 'search/site', ); $this->drupalLogin($this->admin_user); foreach ($paths as $path) { $this->drupalGet($path); $text = 'apachesolr.index.inc was included'; $this->assertNoText($text, t('Apachesolr.index.inc was not included')); } } /** * Asserts that we can edit a search environment */ function testEditSearchEnvironment() { $this->drupalLogin($this->admin_user); $this->drupalGet('admin/config/search/apachesolr/settings'); $this->clickLink(t('Edit')); $this->assertText(t('Example: http://localhost:8983/solr'), t('Edit page was successfully loaded')); $edit = array('name' => 'new description foo bar', 'url' => 'http://localhost:8983/solr/core_does_not_exists'); $this->drupalPost($this->getUrl(), $edit, t('Save')); $this->assertResponse(200); $this->drupalGet('admin/config/search/apachesolr/settings'); $this->assertText(t('new description foo bar'), t('Search environment description was successfully edited')); $this->assertText('http://localhost:8983/solr/core_does_not_exists', t('Search environment url was successfully edited')); } /** * Asserts that we can use various url forms for the search environment */ function testEditSearchEnvironmentURLs() { // Set the various url schemes that will be tested $urls = array( 'http://user@localhost:8983/solr/core_does_not_exists', 'http://user:pass@localhost:8983/solr/core_does_not_exists', 'http://user:pass@localhost/solr/core_does_not_exists', 'https://localhost:8983/solr/core_does_not_exists' ); $this->drupalLogin($this->admin_user); foreach ($urls as $url) { $this->drupalGet('admin/config/search/apachesolr/settings'); $this->clickLink(t('Edit')); $this->assertText(t('Example: http://localhost:8983/solr'), t('Edit page was successfully loaded')); $edit = array('url' => $url); $this->drupalPost($this->getUrl(), $edit, t('Save')); $this->assertResponse(200); $this->drupalGet('admin/config/search/apachesolr/settings'); $this->assertText($url, t('Search environment url was successfully set to !url', array('!url' => $url))); } } /** * Asserts that we can clone a search environment */ function testCloneSearchEnvironment() { $this->drupalLogin($this->admin_user); $this->drupalGet('admin/config/search/apachesolr/settings'); $this->assertText(t('Clone'), t('Clone button is available')); $this->drupalGet('admin/config/search/apachesolr/settings/solr/clone'); $this->assertText(t('Are you sure you want to clone search environment localhost server'), t('Clone confirmation page was successfully loaded')); $this->drupalPost($this->getUrl(), array(), t('Clone')); $this->assertResponse(200); $this->drupalGet('admin/config/search/apachesolr/settings'); $this->assertText(t('localhost server [cloned]'), t('Search Environment was successfully cloned')); // Check if the bundles and configurations are exactly the same // after we clear the caches. apachesolr_environments_clear_cache(); $envs = apachesolr_load_all_environments(); $this->assertEqual(count($envs), 2, 'Now we have 2 environments'); $orig_env = $envs['solr']; unset($envs['solr']); $cloned_env = array_pop($envs); $this->assertTrue($this->_nestedCompare($orig_env['index_bundles'], $cloned_env['index_bundles'])); $this->assertTrue($this->_nestedCompare($orig_env['conf'], $cloned_env['conf'])); } /** * Asserts that we can edit a search environment */ function testCreateNewSearchEnvironment() { // Create a new environment $this->drupalLogin($this->admin_user); $this->drupalGet('admin/config/search/apachesolr/settings'); $this->assertText(t('Add search environment'), t('Create new environment link is available')); $this->clickLink(t('Add search environment')); $this->assertText(t('Make this Solr search environment the default'), t('Environment creation page successfully added')); $edit = array('url' => 'http://localhost:8983/solr', 'name' => 'my test description', 'env_id' => 'solr_test'); $this->drupalPost($this->getUrl(), $edit, t('Save')); $this->assertResponse(200); $this->drupalGet('admin/config/search/apachesolr/settings'); $this->assertText(t('my test description'), t('Search Environment was successfully created')); // Make this new search environment the default $this->drupalGet('admin/config/search/apachesolr/settings'); // Click on the second environment edit link $this->clickLink(t('Edit'), 1); $this->assertText(t('Example: http://localhost:8983/solr'), t('Edit page was successfully loaded')); $edit = array('make_default' => 1, 'conf[apachesolr_read_only]' => APACHESOLR_READ_ONLY); $this->drupalPost($this->getUrl(), $edit, t('Save')); $this->assertResponse(200); $this->drupalGet('admin/config/search/apachesolr/settings'); $this->assertText(t('my test description (Default)'), t('New Search environment was successfully changed to default environment')); // Clear our cache. apachesolr_environments_clear_cache(); $mode = apachesolr_environment_variable_get('solr_test', 'apachesolr_read_only', APACHESOLR_READ_WRITE); $this->assertEqual($mode, APACHESOLR_READ_ONLY, 'Environment successfully changed to read only'); } } /** * @file * Unit test class that provides tests for base functionality of the Apachesolr * Module without having the need of a Solr Server */ class DrupalSolrOfflineSearchPagesWebTestCase extends DrupalSolrOfflineWebTestCase { /** * A global basic user who can search. */ var $basic_user; /** * A global administrative user who can administer search. */ var $admin_user; public static function getInfo() { return array( 'name' => 'Solr Search Pages', 'description' => 'Tests search pages functionality of the Solr module', 'group' => 'ApacheSolr', ); } /** * Implementation of setUp(). */ function setUp() { parent::setUp('apachesolr', 'apachesolr_search', 'search', 'apachesolr_test'); // Create a basic user, which is subject to moderation. $permissions = array( 'access content', 'search content', ); $basic_user = $this->drupalCreateUser($permissions); // Create an admin user that can bypass revision moderation. $permissions = array( 'access content', 'search content', 'administer nodes', 'administer search', ); $admin_user = $this->drupalCreateUser($permissions); // Assign users to their test suite-wide properties. $this->basic_user = $basic_user; $this->admin_user = $admin_user; // Make sure our environment does not exists $env_id = apachesolr_default_environment(NULL, TRUE); $environment = apachesolr_environment_load($env_id, TRUE); $environment['url'] = 'http://localhost/solr/core_that_should_not_exist'; apachesolr_environment_save($environment); // Reset all caches apachesolr_load_all_environments(TRUE); } /** * Asserts that we can edit a search environment */ function testCheckCoreSearchPage() { // Create a new environment $this->drupalLogin($this->admin_user); $this->drupalGet('admin/config/search/apachesolr/search-pages'); $this->assertText(t('Core Search'), t('Core Search page is available')); } /** * Asserts that we can edit a search environment */ function testEditSearchPage() { $this->drupalLogin($this->admin_user); $this->drupalGet('admin/config/search/apachesolr/search-pages'); $this->clickLink(t('Edit')); $this->assertText(t('The human-readable name of the search page configuration'), t('Edit page was successfully loaded')); $edit = array( 'label' => 'Test Search Page', 'description' => 'Test Description', 'page_title' => 'Test Title', 'search_path' => 'search/searchdifferentpath', ); $this->drupalPost($this->getUrl(), $edit, t('Save')); $this->assertResponse(200); // Make sure the menu is recognized drupal_static_reset('apachesolr_search_load_all_search_pages'); menu_cache_clear_all(); menu_rebuild(); $this->drupalGet('admin/config/search/apachesolr/search-pages'); $this->assertText(t('Test Search Page'), t('Search page was successfully edited')); $this->assertText('search/searchdifferentpath', t('Search path was updated')); $this->drupalGet('search/searchdifferentpath'); $this->assertText(t('Search is temporarily unavailable. If the problem persists, please contact the site administrator.'), t('Search path was successfully created and is accessible')); } /** * Asserts that we can clone a search page */ function testCloneSearchPage() { $this->drupalLogin($this->admin_user); $this->drupalGet('admin/config/search/apachesolr/search-pages'); $this->assertText(t('Clone'), t('Clone button is available')); $this->drupalGet('admin/config/search/apachesolr/search-pages/core_search/clone'); $this->assertText(t('Are you sure you want to clone search page Core Search?'), t('Clone confirmation page was successfully loaded')); $this->drupalPost($this->getUrl(), array(), t('Clone')); $this->assertResponse(200); drupal_static_reset('apachesolr_search_load_all_search_pages'); $this->drupalGet('admin/config/search/apachesolr/search-pages'); $this->assertText(t('Core Search [cloned]'), 'Search page was successfully cloned'); } /** * Asserts that we can edit a search environment */ function testNewAndRemoveSearchPage() { // Create a new search page $this->drupalLogin($this->admin_user); $this->drupalGet('admin/config/search/apachesolr/search-pages'); $this->assertText(t('Add search page'), t('Create new search page link is available')); $this->clickLink(t('Add search page')); $this->assertText(t('The human-readable name of the search page configuration.'), t('Search page creation page successfully added')); $edit = array( 'page_id' => 'solr_testingsuite', 'env_id' => 'solr', 'label' => 'Test Search Page', 'description' => 'Test Description', 'page_title' => 'Test Title', 'search_path' => 'search/searchdifferentpath', ); $this->drupalPost($this->getUrl(), $edit, t('Save')); $this->assertResponse(200); // Make sure the menu is recognized drupal_static_reset('apachesolr_search_load_all_search_pages'); menu_cache_clear_all(); menu_rebuild(); $this->drupalGet('admin/config/search/apachesolr/search-pages'); $this->assertText(t('Test Search Page'), t('Search Page was successfully created')); // Remove the same environment $this->clickLink(t('Delete')); $this->assertText(t('search page configuration will be deleted.This action cannot be undone.'), t('Delete confirmation page was successfully loaded')); $this->drupalPost($this->getUrl(), array(), t('Delete')); $this->assertResponse(200); drupal_static_reset('apachesolr_search_load_all_search_pages'); $this->drupalGet('admin/config/search/apachesolr/search-pages'); $this->assertNoText(t('Test Search Page'), t('Search Environment was successfully deleted')); apachesolr_environment_save(array('env_id' => 'DummySolr', 'service_class' => 'DummySolr', 'name' => 'dummy server', 'url' => 'http://localhost:8983/solr')); $solr = new DummySolr($url = NULL, $env_id = 'DummySolr'); $params = array( 'rows' => 5, ); $results = apachesolr_search_run('apachesolr_test', $params, '', '', 0, $solr); $query = apachesolr_current_query('DummySolr'); $this->assertEqual($query->getParam('rows'), 5, 'Passed in rows param overrode default'); } } class DrupalSolrNodeTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Solr Node add, deletion, indexing and document building tests', 'description' => 'Tests if we can successfully add and delete nodes', 'group' => 'ApacheSolr', ); } /** * Implementation of setUp(). */ function setUp() { parent::setUp('apachesolr', 'apachesolr_search', 'search', 'apachesolr_test'); } function testApacheSolrNodeAddDelete() { // Login as basic user to perform initial content creation. // Create an admin user that can bypass revision moderation. $permissions = array( 'access content', 'search content', 'administer nodes', 'administer search', 'access content overview', 'bypass node access', ); $admin_user = $this->drupalCreateUser($permissions); $this->drupalLogin($admin_user); // enable our bundles to be indexed, and clear caches apachesolr_index_set_bundles('solr', 'node', array('page', 'article')); entity_info_cache_clear(); apachesolr_environments_clear_cache(); // Define types of node bundles that we want to index $types = array('page', 'article'); foreach ($types as $type) { $edit = array(); // Create a node of the type $type. $edit['uid'] = $admin_user->uid; $edit['type'] = $type; $edit['title'] = $this->randomName(16); $node = $this->drupalCreateNode($edit); $this->assertTrue(is_object($node) && isset($node->nid), t('Article type @type has been created.', array('@type' => $type))); // Check that the node has been created. $node = $this->drupalGetNodeByTitle($edit['title']); $this->assertTrue($node, t('Created article @type found in database.', array('@type' => $type))); // Check that the node has status 1 $indexer_table = apachesolr_get_indexer_table('node'); $query = db_select($indexer_table, 'aien') ->condition('entity_id', $node->nid) ->fields('aien', array('entity_id', 'status')); $db_node = $query->execute()->fetchObject(); $this->assertEqual($db_node->status, 1, t('Node @entity_id has status 1', array('@entity_id' => $db_node->entity_id))); // Delete the node $this->drupalPost('node/' . $node->nid . '/delete', array(), t('Delete')); // check if the entity delete does its work. It should have set the // status to 0 so it will be deleted when solr comes online $indexer_table = apachesolr_get_indexer_table('node'); $nodes_in_tracking_table = db_select($indexer_table, 'aien') ->condition('entity_id', $node->nid) ->countQuery() ->execute() ->fetchField(); if ($nodes_in_tracking_table > 0) { $db_node = db_select($indexer_table, 'aien') ->condition('entity_id', $node->nid) ->fields('aien', array('entity_id', 'status')) ->execute() ->fetchObject(); $this->assertEqual($db_node->status, 0, t('Node @entity_id has status 0', array('@entity_id' => $db_node->entity_id))); } else { // Check that all of the nodes (should only have 1) have status 0, it // is set as 0 because it is pending to be deleted $this->assertEqual($nodes_in_tracking_table, 0, t('No more nodes in the tracking table')); } // Check that all the nodes have been deleted. $count = db_select('node', 'n') ->condition('n.nid', $node->nid) ->countQuery() ->execute() ->fetchField(); $this->assertEqual($count, 0, t('No more nodes left in the node table.')); } } function testApacheSolrNodeReindex() { // Login as basic user to perform initial content creation. // Create an admin user that can bypass revision moderation. $permissions = array( 'access content', 'search content', 'administer nodes', 'administer search', 'access content overview', 'bypass node access', ); $admin_user = $this->drupalCreateUser($permissions); $this->drupalLogin($admin_user); // enable our bundles to be indexed, and clear caches apachesolr_index_set_bundles('solr', 'node', array('page', 'article')); entity_info_cache_clear(); apachesolr_environments_clear_cache(); // Define types of node bundles that we want to index $types = array('page', 'article'); // Create 20 nodes (10 times 2) foreach ($types as $type) { for ($i = 0; $i < 5; $i++) { $edit = array(); // Create a node of the type $type. $edit['uid'] = $admin_user->uid; $edit['type'] = $type; $edit['title'] = $this->randomName(16); $node = $this->drupalCreateNode($edit); } } // Set a static timestamp $timestamp = 1382019301; $env_id = apachesolr_default_environment(); // Clear the last timestamp so we know that our nodes have to be indexed. apachesolr_environment_variable_set($env_id, 'apachesolr_index_last', array()); // Set apachesolr_index_entities_node.changed to the same value // (REQUEST_TIME). $table = apachesolr_get_indexer_table('node'); db_update($table) ->fields(array('changed' => $timestamp, 'status' => 1)) ->execute(); // Fake that we actually indexed before apachesolr_set_last_index_position($env_id, 'node', $timestamp + 1, 10); // Set the changed date to after our previous index cycle db_update($table) ->fields(array('changed' => $timestamp + 10, 'status' => 1)) ->condition('entity_id', 9, '<=') ->execute(); // Get the next 5 entities to index. $set = apachesolr_index_get_entities_to_index($env_id, 'node', 5); $count = count($set); $this->assertEqual($count, 5, t('We found 5 entities to index.')); // Mark the last item from that 5 as last indexed. $last_row = end($set); apachesolr_set_last_index_position($env_id, 'node', $last_row->changed, $last_row->entity_id); // Get the next batch of 5 and this should be 4 items. $set = apachesolr_index_get_entities_to_index($env_id, 'node', 4); $count = count($set); $this->assertEqual($count, 4, t('We found 4 entities to index.')); // Mark the last item from that 4 as last indexed. $last_row = end($set); apachesolr_set_last_index_position($env_id, 'node', $last_row->changed, $last_row->entity_id); // Get the next batch of 5 and this should be 0 items $set = apachesolr_index_get_entities_to_index($env_id, 'node', 5); $count = count($set); $this->assertEqual($count, 0, t('We found 0 entities to index.')); } function testNodeToDocument() { // enable our bundles to be indexed, and clear caches apachesolr_index_set_bundles('solr', 'node', array('article')); entity_info_cache_clear(); apachesolr_environments_clear_cache(); $edit = array(); // Create a node of the type article. $type = 'article'; $edit['uid'] = 1; $edit['type'] = $type; $edit['title'] = $this->randomName(16); $edit['body'][LANGUAGE_NONE][0]['value'] = 'some other ORDINARY_TEXT '; // Make sure the format allows all tags. $edit['body'][LANGUAGE_NONE][0]['format'] = 'full_html'; $tags_to_index = _apachesolr_tags_to_index(); // Tags that are not boosted normally. $other_tags = array('div' => 'tags_inline', 'span' => 'tags_inline'); $all_tags = $tags_to_index + $other_tags; $tag_content = array(); foreach ($all_tags as $tag_name => $field_name) { $tag_content[$tag_name] = strtoupper($tag_name) . '_TAG_CONTENT'; if ($tag_name == 'a') { $edit['body'][LANGUAGE_NONE][0]['value'] .= "<{$tag_name} href=\"http://example.com\">{$tag_content[$tag_name]} other filler "; } else { $edit['body'][LANGUAGE_NONE][0]['value'] .= "<{$tag_name}>{$tag_content[$tag_name]} dummy text "; } } $node = $this->drupalCreateNode($edit); $this->assertTrue(is_object($node) && isset($node->nid), t('Article type @type has been created.', array('@type' => $type))); $item = new stdClass(); $item->entity_id = $node->nid; $item->entity_type = 'node'; $item->bundle = $node->type; $env_id = apachesolr_default_environment(); $docs = apachesolr_index_entity_to_documents($item, $env_id); $this->assertEqual(count($docs), 1, 'Only one document from one node'); $document = end($docs); $this->assertTrue(strpos($document->content,'ORDINARY_TEXT') !== FALSE, "Found in content field expected: ORDINARY_TEXT"); foreach ($tags_to_index as $tag_name => $field_name) { $this->assertTrue(strpos($document->content, $tag_content[$tag_name]) !== FALSE, "Found in content field expected: {$tag_content[$tag_name]}"); $this->assertTrue(!empty($document->{$field_name}) && strpos($document->{$field_name}, $tag_content[$tag_name]) !== FALSE, "Found in {$field_name} field expected: {$tag_content[$tag_name]}"); $this->assertTrue(empty($document->{$field_name}) || strpos($document->{$field_name},'ORDINARY_TEXT') === FALSE, "NOT Found in {$field_name}: ORDINARY_TEXT"); } foreach ($other_tags as $tag_name => $field_name) { $this->assertTrue(strpos($document->content, $tag_content[$tag_name]) !== FALSE, "Found in content field expected: {$tag_content[$tag_name]}"); $this->assertTrue(empty($document->{$field_name}) || strpos($document->{$field_name}, $tag_content[$tag_name]) === FALSE, "NOT found in {$field_name}: {$tag_content[$tag_name]}"); } } } class DrupalSolrOfflineUnitTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'Solr Base Framework Tests Unit Test', 'description' => 'Unit test functionality of the Solr module', 'group' => 'ApacheSolr', ); } protected function setUp() { parent::setUp(); require_once dirname(dirname(realpath(__FILE__))) . '/apachesolr.module'; $this->script_content = <<GOOD_CONTENT

EOF; $this->embed_content = <<GOOD_CONTENT

OTHER_CONTENT EOF; $this->iframe_content = <<

GOOD_CONTENT

EOF; $this->comment_content = <<GOOD_CONTENT

OTHER_CONTENT EOF; } /** * Test ordering of parsed filter positions. * * Regression test for http://drupal.org/node/891962 */ function testContentFilters() { $cleaned = apachesolr_clean_text($this->script_content); $this->assertFalse(strpos($cleaned, 'script'), 'Script tags removed'); $this->assertFalse(strpos($cleaned, 'accordion_teachers'), 'Script tags conent removed'); $this->assertTrue(strpos(trim($cleaned), 'GOOD_CONTENT') === 0, 'Real content retained'); $cleaned = apachesolr_clean_text($this->embed_content); $this->assertFalse(strpos($cleaned, 'object'), 'object tags removed'); $this->assertFalse(strpos($cleaned, 'embed'), 'embed tags removed'); $this->assertFalse(strpos($cleaned, '8Vmnq5dBF7Y'), 'object tags conent removed'); $this->assertFalse(strpos($cleaned, 'shockwave-flash'), 'embed tags conent removed'); $this->assertTrue(strpos(trim($cleaned), 'GOOD_CONTENT') === 0, 'Real content retained'); $this->assertTrue(strpos($cleaned, 'OTHER_CONTENT') > 0, 'Other content retained'); $cleaned = apachesolr_clean_text($this->iframe_content); $this->assertFalse(strpos($cleaned, 'iframe'), 'iframe tags removed'); $this->assertFalse(strpos($cleaned, '8Vmnq5dBF7Y'), 'iframe tags conent removed'); $this->assertTrue(strpos(trim($cleaned), 'GOOD_CONTENT') === 0, 'Real content retained'); $cleaned = apachesolr_clean_text($this->comment_content); $this->assertFalse(strpos($cleaned, 'COMMENT'), 'html comment content removed '); $this->assertTrue(strpos(trim($cleaned), 'GOOD_CONTENT') === 0, 'Real content retained'); } }