annotate core/modules/search/tests/src/Functional/SearchMultilingualEntityTest.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 129ea1e6d783
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\Tests\search\Functional;
Chris@0 4
Chris@0 5 use Drupal\field\Entity\FieldStorageConfig;
Chris@0 6 use Drupal\language\Entity\ConfigurableLanguage;
Chris@0 7
Chris@0 8 /**
Chris@0 9 * Tests entities with multilingual fields.
Chris@0 10 *
Chris@0 11 * @group search
Chris@0 12 */
Chris@0 13 class SearchMultilingualEntityTest extends SearchTestBase {
Chris@0 14
Chris@0 15 /**
Chris@0 16 * List of searchable nodes.
Chris@0 17 *
Chris@0 18 * @var \Drupal\node\NodeInterface[]
Chris@0 19 */
Chris@0 20 protected $searchableNodes = [];
Chris@0 21
Chris@0 22 /**
Chris@0 23 * Node search plugin.
Chris@0 24 *
Chris@0 25 * @var \Drupal\node\Plugin\Search\NodeSearch
Chris@0 26 */
Chris@0 27 protected $plugin;
Chris@0 28
Chris@0 29 public static $modules = ['language', 'locale', 'comment'];
Chris@0 30
Chris@0 31 protected function setUp() {
Chris@0 32 parent::setUp();
Chris@0 33
Chris@0 34 // Create a user who can administer search, do searches, see the status
Chris@0 35 // report, and administer cron. Log in.
Chris@0 36 $user = $this->drupalCreateUser(['administer search', 'search content', 'use advanced search', 'access content', 'access site reports', 'administer site configuration']);
Chris@0 37 $this->drupalLogin($user);
Chris@0 38
Chris@0 39 // Set up the search plugin.
Chris@0 40 $this->plugin = $this->container->get('plugin.manager.search')->createInstance('node_search');
Chris@0 41
Chris@0 42 // Check indexing counts before adding any nodes.
Chris@0 43 $this->assertIndexCounts(0, 0, 'before adding nodes');
Chris@0 44 $this->assertDatabaseCounts(0, 0, 'before adding nodes');
Chris@0 45
Chris@0 46 // Add two new languages.
Chris@0 47 ConfigurableLanguage::createFromLangcode('hu')->save();
Chris@0 48 ConfigurableLanguage::createFromLangcode('sv')->save();
Chris@0 49
Chris@0 50 // Make the body field translatable. The title is already translatable by
Chris@0 51 // definition. The parent class has already created the article and page
Chris@0 52 // content types.
Chris@0 53 $field_storage = FieldStorageConfig::loadByName('node', 'body');
Chris@0 54 $field_storage->setTranslatable(TRUE);
Chris@0 55 $field_storage->save();
Chris@0 56
Chris@0 57 // Create a few page nodes with multilingual body values.
Chris@0 58 $default_format = filter_default_format();
Chris@0 59 $nodes = [
Chris@0 60 [
Chris@0 61 'title' => 'First node en',
Chris@0 62 'type' => 'page',
Chris@0 63 'body' => [['value' => $this->randomMachineName(32), 'format' => $default_format]],
Chris@0 64 'langcode' => 'en',
Chris@0 65 ],
Chris@0 66 [
Chris@0 67 'title' => 'Second node this is the English title',
Chris@0 68 'type' => 'page',
Chris@0 69 'body' => [['value' => $this->randomMachineName(32), 'format' => $default_format]],
Chris@0 70 'langcode' => 'en',
Chris@0 71 ],
Chris@0 72 [
Chris@0 73 'title' => 'Third node en',
Chris@0 74 'type' => 'page',
Chris@0 75 'body' => [['value' => $this->randomMachineName(32), 'format' => $default_format]],
Chris@0 76 'langcode' => 'en',
Chris@0 77 ],
Chris@0 78 // After the third node, we don't care what the settings are. But we
Chris@0 79 // need to have at least 5 to make sure the throttling is working
Chris@0 80 // correctly. So, let's make 8 total.
Chris@0 81 [],
Chris@0 82 [],
Chris@0 83 [],
Chris@0 84 [],
Chris@0 85 [],
Chris@0 86 ];
Chris@0 87 $this->searchableNodes = [];
Chris@0 88 foreach ($nodes as $setting) {
Chris@0 89 $this->searchableNodes[] = $this->drupalCreateNode($setting);
Chris@0 90 }
Chris@0 91
Chris@0 92 // Add a single translation to the second node.
Chris@0 93 $translation = $this->searchableNodes[1]->addTranslation('hu', ['title' => 'Second node hu']);
Chris@0 94 $translation->body->value = $this->randomMachineName(32);
Chris@0 95 $this->searchableNodes[1]->save();
Chris@0 96
Chris@0 97 // Add two translations to the third node.
Chris@0 98 $translation = $this->searchableNodes[2]->addTranslation('hu', ['title' => 'Third node this is the Hungarian title']);
Chris@0 99 $translation->body->value = $this->randomMachineName(32);
Chris@0 100 $translation = $this->searchableNodes[2]->addTranslation('sv', ['title' => 'Third node sv']);
Chris@0 101 $translation->body->value = $this->randomMachineName(32);
Chris@0 102 $this->searchableNodes[2]->save();
Chris@0 103
Chris@0 104 // Verify that we have 8 nodes left to do.
Chris@0 105 $this->assertIndexCounts(8, 8, 'before updating the search index');
Chris@0 106 $this->assertDatabaseCounts(0, 0, 'before updating the search index');
Chris@0 107 }
Chris@0 108
Chris@0 109 /**
Chris@0 110 * Tests the indexing throttle and search results with multilingual nodes.
Chris@0 111 */
Chris@0 112 public function testMultilingualSearch() {
Chris@0 113 // Index only 2 nodes per cron run. We cannot do this setting in the UI,
Chris@0 114 // because it doesn't go this low.
Chris@0 115 $this->config('search.settings')->set('index.cron_limit', 2)->save();
Chris@0 116 // Get a new search plugin, to make sure it has this setting.
Chris@0 117 $this->plugin = $this->container->get('plugin.manager.search')->createInstance('node_search');
Chris@0 118
Chris@0 119 // Update the index. This does the initial processing.
Chris@0 120 $this->plugin->updateIndex();
Chris@0 121 // Run the shutdown function. Testing is a unique case where indexing
Chris@0 122 // and searching has to happen in the same request, so running the shutdown
Chris@0 123 // function manually is needed to finish the indexing process.
Chris@0 124 search_update_totals();
Chris@0 125 $this->assertIndexCounts(6, 8, 'after updating partially');
Chris@0 126 $this->assertDatabaseCounts(2, 0, 'after updating partially');
Chris@0 127
Chris@0 128 // Now index the rest of the nodes.
Chris@0 129 // Make sure index throttle is high enough, via the UI.
Chris@0 130 $this->drupalPostForm('admin/config/search/pages', ['cron_limit' => 20], t('Save configuration'));
Chris@0 131 $this->assertEqual(20, $this->config('search.settings')->get('index.cron_limit', 100), 'Config setting was saved correctly');
Chris@0 132 // Get a new search plugin, to make sure it has this setting.
Chris@0 133 $this->plugin = $this->container->get('plugin.manager.search')->createInstance('node_search');
Chris@0 134
Chris@0 135 $this->plugin->updateIndex();
Chris@0 136 search_update_totals();
Chris@0 137 $this->assertIndexCounts(0, 8, 'after updating fully');
Chris@0 138 $this->assertDatabaseCounts(8, 0, 'after updating fully');
Chris@0 139
Chris@0 140 // Click the reindex button on the admin page, verify counts, and reindex.
Chris@0 141 $this->drupalPostForm('admin/config/search/pages', [], t('Re-index site'));
Chris@0 142 $this->drupalPostForm(NULL, [], t('Re-index site'));
Chris@0 143 $this->assertIndexCounts(8, 8, 'after reindex');
Chris@0 144 $this->assertDatabaseCounts(8, 0, 'after reindex');
Chris@0 145 $this->plugin->updateIndex();
Chris@0 146 search_update_totals();
Chris@0 147
Chris@0 148 // Test search results.
Chris@0 149
Chris@0 150 // This should find two results for the second and third node.
Chris@0 151 $this->plugin->setSearch('English OR Hungarian', [], []);
Chris@0 152 $search_result = $this->plugin->execute();
Chris@0 153 $this->assertEqual(count($search_result), 2, 'Found two results.');
Chris@0 154 // Nodes are saved directly after each other and have the same created time
Chris@0 155 // so testing for the order is not possible.
Chris@0 156 $results = [$search_result[0]['title'], $search_result[1]['title']];
Chris@0 157 $this->assertTrue(in_array('Third node this is the Hungarian title', $results), 'The search finds the correct Hungarian title.');
Chris@0 158 $this->assertTrue(in_array('Second node this is the English title', $results), 'The search finds the correct English title.');
Chris@0 159
Chris@0 160 // Now filter for Hungarian results only.
Chris@0 161 $this->plugin->setSearch('English OR Hungarian', ['f' => ['language:hu']], []);
Chris@0 162 $search_result = $this->plugin->execute();
Chris@0 163
Chris@0 164 $this->assertEqual(count($search_result), 1, 'The search found only one result');
Chris@0 165 $this->assertEqual($search_result[0]['title'], 'Third node this is the Hungarian title', 'The search finds the correct Hungarian title.');
Chris@0 166
Chris@0 167 // Test for search with common key word across multiple languages.
Chris@0 168 $this->plugin->setSearch('node', [], []);
Chris@0 169 $search_result = $this->plugin->execute();
Chris@0 170
Chris@0 171 $this->assertEqual(count($search_result), 6, 'The search found total six results');
Chris@0 172
Chris@0 173 // Test with language filters and common key word.
Chris@0 174 $this->plugin->setSearch('node', ['f' => ['language:hu']], []);
Chris@0 175 $search_result = $this->plugin->execute();
Chris@0 176
Chris@0 177 $this->assertEqual(count($search_result), 2, 'The search found 2 results');
Chris@0 178
Chris@0 179 // Test to check for the language of result items.
Chris@0 180 foreach ($search_result as $result) {
Chris@0 181 $this->assertEqual($result['langcode'], 'hu', 'The search found the correct Hungarian result');
Chris@0 182 }
Chris@0 183
Chris@0 184 // Mark one of the nodes for reindexing, using the API function, and
Chris@0 185 // verify indexing status.
Chris@0 186 search_mark_for_reindex('node_search', $this->searchableNodes[0]->id());
Chris@0 187 $this->assertIndexCounts(1, 8, 'after marking one node to reindex via API function');
Chris@0 188
Chris@0 189 // Update the index and verify the totals again.
Chris@0 190 $this->plugin = $this->container->get('plugin.manager.search')->createInstance('node_search');
Chris@0 191 $this->plugin->updateIndex();
Chris@0 192 search_update_totals();
Chris@0 193 $this->assertIndexCounts(0, 8, 'after indexing again');
Chris@0 194
Chris@0 195 // Mark one node for reindexing by saving it, and verify indexing status.
Chris@0 196 $this->searchableNodes[1]->save();
Chris@0 197 $this->assertIndexCounts(1, 8, 'after marking one node to reindex via save');
Chris@0 198
Chris@0 199 // The request time is always the same throughout test runs. Update the
Chris@0 200 // request time to a previous time, to simulate it having been marked
Chris@0 201 // previously.
Chris@0 202 $current = REQUEST_TIME;
Chris@0 203 $old = $current - 10;
Chris@0 204 db_update('search_dataset')
Chris@0 205 ->fields(['reindex' => $old])
Chris@0 206 ->condition('reindex', $current, '>=')
Chris@0 207 ->execute();
Chris@0 208
Chris@0 209 // Save the node again. Verify that the request time on it is not updated.
Chris@0 210 $this->searchableNodes[1]->save();
Chris@0 211 $result = db_select('search_dataset', 'd')
Chris@0 212 ->fields('d', ['reindex'])
Chris@0 213 ->condition('type', 'node_search')
Chris@0 214 ->condition('sid', $this->searchableNodes[1]->id())
Chris@0 215 ->execute()
Chris@0 216 ->fetchField();
Chris@0 217 $this->assertEqual($result, $old, 'Reindex time was not updated if node was already marked');
Chris@0 218
Chris@0 219 // Add a bogus entry to the search index table using a different search
Chris@0 220 // type. This will not appear in the index status, because it is not
Chris@0 221 // managed by a plugin.
Chris@0 222 search_index('foo', $this->searchableNodes[0]->id(), 'en', 'some text');
Chris@0 223 $this->assertIndexCounts(1, 8, 'after adding a different index item');
Chris@0 224
Chris@0 225 // Mark just this "foo" index for reindexing.
Chris@0 226 search_mark_for_reindex('foo');
Chris@0 227 $this->assertIndexCounts(1, 8, 'after reindexing the other search type');
Chris@0 228
Chris@0 229 // Mark everything for reindexing.
Chris@0 230 search_mark_for_reindex();
Chris@0 231 $this->assertIndexCounts(8, 8, 'after reindexing everything');
Chris@0 232
Chris@0 233 // Clear one item from the index, but with wrong language.
Chris@0 234 $this->assertDatabaseCounts(8, 1, 'before clear');
Chris@0 235 search_index_clear('node_search', $this->searchableNodes[0]->id(), 'hu');
Chris@0 236 $this->assertDatabaseCounts(8, 1, 'after clear with wrong language');
Chris@0 237 // Clear using correct language.
Chris@0 238 search_index_clear('node_search', $this->searchableNodes[0]->id(), 'en');
Chris@0 239 $this->assertDatabaseCounts(7, 1, 'after clear with right language');
Chris@0 240 // Don't specify language.
Chris@0 241 search_index_clear('node_search', $this->searchableNodes[1]->id());
Chris@0 242 $this->assertDatabaseCounts(6, 1, 'unspecified language clear');
Chris@0 243 // Clear everything in 'foo'.
Chris@0 244 search_index_clear('foo');
Chris@0 245 $this->assertDatabaseCounts(6, 0, 'other index clear');
Chris@0 246 // Clear everything.
Chris@0 247 search_index_clear();
Chris@0 248 $this->assertDatabaseCounts(0, 0, 'complete clear');
Chris@0 249 }
Chris@0 250
Chris@0 251 /**
Chris@0 252 * Verifies the indexing status counts.
Chris@0 253 *
Chris@0 254 * @param int $remaining
Chris@0 255 * Count of remaining items to verify.
Chris@0 256 * @param int $total
Chris@0 257 * Count of total items to verify.
Chris@0 258 * @param string $message
Chris@0 259 * Message to use, something like "after updating the search index".
Chris@0 260 */
Chris@0 261 protected function assertIndexCounts($remaining, $total, $message) {
Chris@0 262 // Check status via plugin method call.
Chris@0 263 $status = $this->plugin->indexStatus();
Chris@0 264 $this->assertEqual($status['remaining'], $remaining, 'Remaining items ' . $message . ' is ' . $remaining);
Chris@0 265 $this->assertEqual($status['total'], $total, 'Total items ' . $message . ' is ' . $total);
Chris@0 266
Chris@0 267 // Check text in progress section of Search settings page. Note that this
Chris@0 268 // test avoids using
Chris@0 269 // \Drupal\Core\StringTranslation\TranslationInterface::formatPlural(), so
Chris@0 270 // it tests for fragments of text.
Chris@0 271 $indexed = $total - $remaining;
Chris@0 272 $percent = ($total > 0) ? floor(100 * $indexed / $total) : 100;
Chris@0 273 $this->drupalGet('admin/config/search/pages');
Chris@0 274 $this->assertText($percent . '% of the site has been indexed.', 'Progress percent text at top of Search settings page is correct at: ' . $message);
Chris@0 275 $this->assertText($remaining . ' item', 'Remaining text at top of Search settings page is correct at: ' . $message);
Chris@0 276
Chris@0 277 // Check text in pages section of Search settings page.
Chris@0 278 $this->assertText($indexed . ' of ' . $total . ' indexed', 'Progress text in pages section of Search settings page is correct at: ' . $message);
Chris@0 279
Chris@0 280 // Check text on status report page.
Chris@0 281 $this->drupalGet('admin/reports/status');
Chris@0 282 $this->assertText('Search index progress', 'Search status section header is present on status report page');
Chris@0 283 $this->assertText($percent . '%', 'Correct percentage is shown on status report page at: ' . $message);
Chris@0 284 $this->assertText('(' . $remaining . ' remaining)', 'Correct remaining value is shown on status report page at: ' . $message);
Chris@0 285 }
Chris@0 286
Chris@0 287 /**
Chris@0 288 * Checks actual database counts of items in the search index.
Chris@0 289 *
Chris@0 290 * @param int $count_node
Chris@0 291 * Count of node items to assert.
Chris@0 292 * @param int $count_foo
Chris@0 293 * Count of "foo" items to assert.
Chris@0 294 * @param string $message
Chris@0 295 * Message suffix to use.
Chris@0 296 */
Chris@0 297 protected function assertDatabaseCounts($count_node, $count_foo, $message) {
Chris@0 298 // Count number of distinct nodes by ID.
Chris@0 299 $results = db_select('search_dataset', 'i')
Chris@0 300 ->fields('i', ['sid'])
Chris@0 301 ->condition('type', 'node_search')
Chris@0 302 ->groupBy('sid')
Chris@0 303 ->execute()
Chris@0 304 ->fetchCol();
Chris@0 305 $this->assertEqual($count_node, count($results), 'Node count was ' . $count_node . ' for ' . $message);
Chris@0 306
Chris@0 307 // Count number of "foo" records.
Chris@0 308 $results = db_select('search_dataset', 'i')
Chris@0 309 ->fields('i', ['sid'])
Chris@0 310 ->condition('type', 'foo')
Chris@0 311 ->execute()
Chris@0 312 ->fetchCol();
Chris@0 313 $this->assertEqual($count_foo, count($results), 'Foo count was ' . $count_foo . ' for ' . $message);
Chris@0 314
Chris@0 315 }
Chris@0 316
Chris@0 317 }