Chris@4
|
1 <?php
|
Chris@4
|
2
|
Chris@4
|
3 namespace Drupal\Tests\search\Functional;
|
Chris@4
|
4
|
Chris@4
|
5 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
|
Chris@4
|
6 use Drupal\comment\Tests\CommentTestTrait;
|
Chris@5
|
7 use Drupal\Core\Database\Database;
|
Chris@4
|
8 use Drupal\Core\Url;
|
Chris@4
|
9 use Drupal\filter\Entity\FilterFormat;
|
Chris@4
|
10 use Drupal\search\Entity\SearchPage;
|
Chris@4
|
11 use Drupal\Tests\BrowserTestBase;
|
Chris@4
|
12 use Drupal\Tests\Traits\Core\CronRunTrait;
|
Chris@4
|
13
|
Chris@4
|
14 /**
|
Chris@4
|
15 * Indexes content and tests ranking factors.
|
Chris@4
|
16 *
|
Chris@4
|
17 * @group search
|
Chris@4
|
18 */
|
Chris@4
|
19 class SearchRankingTest extends BrowserTestBase {
|
Chris@4
|
20
|
Chris@4
|
21 use CommentTestTrait;
|
Chris@4
|
22 use CronRunTrait;
|
Chris@4
|
23
|
Chris@4
|
24 /**
|
Chris@4
|
25 * The node search page.
|
Chris@4
|
26 *
|
Chris@4
|
27 * @var \Drupal\search\SearchPageInterface
|
Chris@4
|
28 */
|
Chris@4
|
29 protected $nodeSearch;
|
Chris@4
|
30
|
Chris@4
|
31 /**
|
Chris@4
|
32 * {@inheritdoc}
|
Chris@4
|
33 */
|
Chris@4
|
34 protected static $modules = ['node', 'search', 'statistics', 'comment'];
|
Chris@4
|
35
|
Chris@4
|
36 protected function setUp() {
|
Chris@4
|
37 parent::setUp();
|
Chris@4
|
38
|
Chris@4
|
39 $this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
|
Chris@4
|
40
|
Chris@4
|
41 // Create a plugin instance.
|
Chris@4
|
42 $this->nodeSearch = SearchPage::load('node_search');
|
Chris@4
|
43
|
Chris@4
|
44 // Log in with sufficient privileges.
|
Chris@4
|
45 $this->drupalLogin($this->drupalCreateUser(['post comments', 'skip comment approval', 'create page content', 'administer search']));
|
Chris@4
|
46 }
|
Chris@4
|
47
|
Chris@4
|
48 public function testRankings() {
|
Chris@4
|
49 // Add a comment field.
|
Chris@4
|
50 $this->addDefaultCommentField('node', 'page');
|
Chris@4
|
51
|
Chris@4
|
52 // Build a list of the rankings to test.
|
Chris@4
|
53 $node_ranks = ['sticky', 'promote', 'relevance', 'recent', 'comments', 'views'];
|
Chris@4
|
54
|
Chris@4
|
55 // Create nodes for testing.
|
Chris@4
|
56 $nodes = [];
|
Chris@4
|
57 foreach ($node_ranks as $node_rank) {
|
Chris@4
|
58 $settings = [
|
Chris@4
|
59 'type' => 'page',
|
Chris@4
|
60 'comment' => [
|
Chris@4
|
61 ['status' => CommentItemInterface::HIDDEN],
|
Chris@4
|
62 ],
|
Chris@4
|
63 'title' => 'Drupal rocks',
|
Chris@4
|
64 'body' => [['value' => "Drupal's search rocks"]],
|
Chris@4
|
65 // Node is one day old.
|
Chris@4
|
66 'created' => REQUEST_TIME - 24 * 3600,
|
Chris@4
|
67 'sticky' => 0,
|
Chris@4
|
68 'promote' => 0,
|
Chris@4
|
69 ];
|
Chris@4
|
70 foreach ([0, 1] as $num) {
|
Chris@4
|
71 if ($num == 1) {
|
Chris@4
|
72 switch ($node_rank) {
|
Chris@4
|
73 case 'sticky':
|
Chris@4
|
74 case 'promote':
|
Chris@4
|
75 $settings[$node_rank] = 1;
|
Chris@4
|
76 break;
|
Chris@4
|
77 case 'relevance':
|
Chris@4
|
78 $settings['body'][0]['value'] .= " really rocks";
|
Chris@4
|
79 break;
|
Chris@4
|
80 case 'recent':
|
Chris@4
|
81 // Node is 1 hour hold.
|
Chris@4
|
82 $settings['created'] = REQUEST_TIME - 3600;
|
Chris@4
|
83 break;
|
Chris@4
|
84 case 'comments':
|
Chris@4
|
85 $settings['comment'][0]['status'] = CommentItemInterface::OPEN;
|
Chris@4
|
86 break;
|
Chris@4
|
87 }
|
Chris@4
|
88 }
|
Chris@4
|
89 $nodes[$node_rank][$num] = $this->drupalCreateNode($settings);
|
Chris@4
|
90 }
|
Chris@4
|
91 }
|
Chris@4
|
92
|
Chris@4
|
93 // Add a comment to one of the nodes.
|
Chris@4
|
94 $edit = [];
|
Chris@4
|
95 $edit['subject[0][value]'] = 'my comment title';
|
Chris@4
|
96 $edit['comment_body[0][value]'] = 'some random comment';
|
Chris@4
|
97 $this->drupalGet('comment/reply/node/' . $nodes['comments'][1]->id() . '/comment');
|
Chris@4
|
98 $this->drupalPostForm(NULL, $edit, t('Preview'));
|
Chris@4
|
99 $this->drupalPostForm(NULL, $edit, t('Save'));
|
Chris@4
|
100
|
Chris@4
|
101 // Enable counting of statistics.
|
Chris@4
|
102 $this->config('statistics.settings')->set('count_content_views', 1)->save();
|
Chris@4
|
103
|
Chris@4
|
104 // Simulating content views is kind of difficult in the test. Leave that
|
Chris@4
|
105 // to the Statistics module. So instead go ahead and manually update the
|
Chris@4
|
106 // counter for this node.
|
Chris@4
|
107 $nid = $nodes['views'][1]->id();
|
Chris@5
|
108 Database::getConnection()->insert('node_counter')
|
Chris@4
|
109 ->fields(['totalcount' => 5, 'daycount' => 5, 'timestamp' => REQUEST_TIME, 'nid' => $nid])
|
Chris@4
|
110 ->execute();
|
Chris@4
|
111
|
Chris@4
|
112 // Run cron to update the search index and comment/statistics totals.
|
Chris@4
|
113 $this->cronRun();
|
Chris@4
|
114
|
Chris@4
|
115 // Test that the settings form displays the content ranking section.
|
Chris@4
|
116 $this->drupalGet('admin/config/search/pages/manage/node_search');
|
Chris@4
|
117 $this->assertText(t('Content ranking'));
|
Chris@4
|
118
|
Chris@4
|
119 // Check that all rankings are visible and set to 0.
|
Chris@4
|
120 foreach ($node_ranks as $node_rank) {
|
Chris@4
|
121 $this->assertTrue($this->xpath('//select[@id="edit-rankings-' . $node_rank . '-value"]//option[@value="0"]'), 'Select list to prioritize ' . $node_rank . ' for node ranks is visible and set to 0.');
|
Chris@4
|
122 }
|
Chris@4
|
123
|
Chris@4
|
124 // Test each of the possible rankings.
|
Chris@4
|
125 $edit = [];
|
Chris@4
|
126 foreach ($node_ranks as $node_rank) {
|
Chris@4
|
127 // Enable the ranking we are testing.
|
Chris@4
|
128 $edit['rankings[' . $node_rank . '][value]'] = 10;
|
Chris@4
|
129 $this->drupalPostForm('admin/config/search/pages/manage/node_search', $edit, t('Save search page'));
|
Chris@4
|
130 $this->drupalGet('admin/config/search/pages/manage/node_search');
|
Chris@4
|
131 $this->assertTrue($this->xpath('//select[@id="edit-rankings-' . $node_rank . '-value"]//option[@value="10"]'), 'Select list to prioritize ' . $node_rank . ' for node ranks is visible and set to 10.');
|
Chris@4
|
132
|
Chris@4
|
133 // Reload the plugin to get the up-to-date values.
|
Chris@4
|
134 $this->nodeSearch = SearchPage::load('node_search');
|
Chris@4
|
135 // Do the search and assert the results.
|
Chris@4
|
136 $this->nodeSearch->getPlugin()->setSearch('rocks', [], []);
|
Chris@4
|
137 $set = $this->nodeSearch->getPlugin()->execute();
|
Chris@4
|
138 $this->assertEqual($set[0]['node']->id(), $nodes[$node_rank][1]->id(), 'Search ranking "' . $node_rank . '" order.');
|
Chris@4
|
139
|
Chris@4
|
140 // Clear this ranking for the next test.
|
Chris@4
|
141 $edit['rankings[' . $node_rank . '][value]'] = 0;
|
Chris@4
|
142 }
|
Chris@4
|
143
|
Chris@4
|
144 // Save the final node_rank change then check that all rankings are visible
|
Chris@4
|
145 // and have been set back to 0.
|
Chris@4
|
146 $this->drupalPostForm('admin/config/search/pages/manage/node_search', $edit, t('Save search page'));
|
Chris@4
|
147 $this->drupalGet('admin/config/search/pages/manage/node_search');
|
Chris@4
|
148 foreach ($node_ranks as $node_rank) {
|
Chris@4
|
149 $this->assertTrue($this->xpath('//select[@id="edit-rankings-' . $node_rank . '-value"]//option[@value="0"]'), 'Select list to prioritize ' . $node_rank . ' for node ranks is visible and set to 0.');
|
Chris@4
|
150 }
|
Chris@4
|
151
|
Chris@4
|
152 // Try with sticky, then promoted. This is a test for issue
|
Chris@4
|
153 // https://www.drupal.org/node/771596.
|
Chris@4
|
154 $node_ranks = [
|
Chris@4
|
155 'sticky' => 10,
|
Chris@4
|
156 'promote' => 1,
|
Chris@4
|
157 'relevance' => 0,
|
Chris@4
|
158 'recent' => 0,
|
Chris@4
|
159 'comments' => 0,
|
Chris@4
|
160 'views' => 0,
|
Chris@4
|
161 ];
|
Chris@4
|
162 $configuration = $this->nodeSearch->getPlugin()->getConfiguration();
|
Chris@4
|
163 foreach ($node_ranks as $var => $value) {
|
Chris@4
|
164 $configuration['rankings'][$var] = $value;
|
Chris@4
|
165 }
|
Chris@4
|
166 $this->nodeSearch->getPlugin()->setConfiguration($configuration);
|
Chris@4
|
167 $this->nodeSearch->save();
|
Chris@4
|
168
|
Chris@4
|
169 // Do the search and assert the results. The sticky node should show up
|
Chris@4
|
170 // first, then the promoted node, then all the rest.
|
Chris@4
|
171 $this->nodeSearch->getPlugin()->setSearch('rocks', [], []);
|
Chris@4
|
172 $set = $this->nodeSearch->getPlugin()->execute();
|
Chris@4
|
173 $this->assertEqual($set[0]['node']->id(), $nodes['sticky'][1]->id(), 'Search ranking for sticky first worked.');
|
Chris@4
|
174 $this->assertEqual($set[1]['node']->id(), $nodes['promote'][1]->id(), 'Search ranking for promoted second worked.');
|
Chris@4
|
175
|
Chris@4
|
176 // Try with recent, then comments. This is a test for issues
|
Chris@4
|
177 // https://www.drupal.org/node/771596 and
|
Chris@4
|
178 // https://www.drupal.org/node/303574.
|
Chris@4
|
179 $node_ranks = [
|
Chris@4
|
180 'sticky' => 0,
|
Chris@4
|
181 'promote' => 0,
|
Chris@4
|
182 'relevance' => 0,
|
Chris@4
|
183 'recent' => 10,
|
Chris@4
|
184 'comments' => 1,
|
Chris@4
|
185 'views' => 0,
|
Chris@4
|
186 ];
|
Chris@4
|
187 $configuration = $this->nodeSearch->getPlugin()->getConfiguration();
|
Chris@4
|
188 foreach ($node_ranks as $var => $value) {
|
Chris@4
|
189 $configuration['rankings'][$var] = $value;
|
Chris@4
|
190 }
|
Chris@4
|
191 $this->nodeSearch->getPlugin()->setConfiguration($configuration);
|
Chris@4
|
192 $this->nodeSearch->save();
|
Chris@4
|
193
|
Chris@4
|
194 // Do the search and assert the results. The recent node should show up
|
Chris@4
|
195 // first, then the commented node, then all the rest.
|
Chris@4
|
196 $this->nodeSearch->getPlugin()->setSearch('rocks', [], []);
|
Chris@4
|
197 $set = $this->nodeSearch->getPlugin()->execute();
|
Chris@4
|
198 $this->assertEqual($set[0]['node']->id(), $nodes['recent'][1]->id(), 'Search ranking for recent first worked.');
|
Chris@4
|
199 $this->assertEqual($set[1]['node']->id(), $nodes['comments'][1]->id(), 'Search ranking for comments second worked.');
|
Chris@4
|
200
|
Chris@4
|
201 }
|
Chris@4
|
202
|
Chris@4
|
203 /**
|
Chris@4
|
204 * Test rankings of HTML tags.
|
Chris@4
|
205 */
|
Chris@4
|
206 public function testHTMLRankings() {
|
Chris@4
|
207 $full_html_format = FilterFormat::create([
|
Chris@4
|
208 'format' => 'full_html',
|
Chris@4
|
209 'name' => 'Full HTML',
|
Chris@4
|
210 ]);
|
Chris@4
|
211 $full_html_format->save();
|
Chris@4
|
212
|
Chris@4
|
213 // Test HTML tags with different weights.
|
Chris@4
|
214 $sorted_tags = ['h1', 'h2', 'h3', 'h4', 'a', 'h5', 'h6', 'notag'];
|
Chris@4
|
215 $shuffled_tags = $sorted_tags;
|
Chris@4
|
216
|
Chris@4
|
217 // Shuffle tags to ensure HTML tags are ranked properly.
|
Chris@4
|
218 shuffle($shuffled_tags);
|
Chris@4
|
219 $settings = [
|
Chris@4
|
220 'type' => 'page',
|
Chris@4
|
221 'title' => 'Simple node',
|
Chris@4
|
222 ];
|
Chris@4
|
223 $nodes = [];
|
Chris@4
|
224 foreach ($shuffled_tags as $tag) {
|
Chris@4
|
225 switch ($tag) {
|
Chris@4
|
226 case 'a':
|
Chris@4
|
227 $settings['body'] = [['value' => \Drupal::l('Drupal Rocks', new Url('<front>')), 'format' => 'full_html']];
|
Chris@4
|
228 break;
|
Chris@4
|
229 case 'notag':
|
Chris@4
|
230 $settings['body'] = [['value' => 'Drupal Rocks']];
|
Chris@4
|
231 break;
|
Chris@4
|
232 default:
|
Chris@4
|
233 $settings['body'] = [['value' => "<$tag>Drupal Rocks</$tag>", 'format' => 'full_html']];
|
Chris@4
|
234 break;
|
Chris@4
|
235 }
|
Chris@4
|
236 $nodes[$tag] = $this->drupalCreateNode($settings);
|
Chris@4
|
237 }
|
Chris@4
|
238
|
Chris@4
|
239 // Update the search index.
|
Chris@4
|
240 $this->nodeSearch->getPlugin()->updateIndex();
|
Chris@4
|
241 search_update_totals();
|
Chris@4
|
242
|
Chris@4
|
243 $this->nodeSearch->getPlugin()->setSearch('rocks', [], []);
|
Chris@4
|
244 // Do the search and assert the results.
|
Chris@4
|
245 $set = $this->nodeSearch->getPlugin()->execute();
|
Chris@4
|
246
|
Chris@4
|
247 // Test the ranking of each tag.
|
Chris@4
|
248 foreach ($sorted_tags as $tag_rank => $tag) {
|
Chris@4
|
249 // Assert the results.
|
Chris@4
|
250 if ($tag == 'notag') {
|
Chris@4
|
251 $this->assertEqual($set[$tag_rank]['node']->id(), $nodes[$tag]->id(), 'Search tag ranking for plain text order.');
|
Chris@4
|
252 }
|
Chris@4
|
253 else {
|
Chris@4
|
254 $this->assertEqual($set[$tag_rank]['node']->id(), $nodes[$tag]->id(), 'Search tag ranking for "<' . $sorted_tags[$tag_rank] . '>" order.');
|
Chris@4
|
255 }
|
Chris@4
|
256 }
|
Chris@4
|
257
|
Chris@4
|
258 // Test tags with the same weight against the sorted tags.
|
Chris@4
|
259 $unsorted_tags = ['u', 'b', 'i', 'strong', 'em'];
|
Chris@4
|
260 foreach ($unsorted_tags as $tag) {
|
Chris@4
|
261 $settings['body'] = [['value' => "<$tag>Drupal Rocks</$tag>", 'format' => 'full_html']];
|
Chris@4
|
262 $node = $this->drupalCreateNode($settings);
|
Chris@4
|
263
|
Chris@4
|
264 // Update the search index.
|
Chris@4
|
265 $this->nodeSearch->getPlugin()->updateIndex();
|
Chris@4
|
266 search_update_totals();
|
Chris@4
|
267
|
Chris@4
|
268 $this->nodeSearch->getPlugin()->setSearch('rocks', [], []);
|
Chris@4
|
269 // Do the search and assert the results.
|
Chris@4
|
270 $set = $this->nodeSearch->getPlugin()->execute();
|
Chris@4
|
271
|
Chris@4
|
272 // Ranking should always be second to last.
|
Chris@4
|
273 $set = array_slice($set, -2, 1);
|
Chris@4
|
274
|
Chris@4
|
275 // Assert the results.
|
Chris@4
|
276 $this->assertEqual($set[0]['node']->id(), $node->id(), 'Search tag ranking for "<' . $tag . '>" order.');
|
Chris@4
|
277
|
Chris@4
|
278 // Delete node so it doesn't show up in subsequent search results.
|
Chris@4
|
279 $node->delete();
|
Chris@4
|
280 }
|
Chris@4
|
281 }
|
Chris@4
|
282
|
Chris@4
|
283 }
|