Completed
Push — dev2 ( 6bca8c...710c23 )
by Gordon
03:03
created

SearchAndIndexingTest::search()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 8

Duplication

Lines 11
Ratio 100 %
Metric Value
dl 11
loc 11
rs 9.4286
cc 1
eloc 8
nc 1
nop 3
1
<?php
2
3
use SilverStripe\Elastica\ElasticSearcher;
4
5
/**
6
 * Test the functionality of the Searchable extension
7
 * @package elastica
8
 */
9
class SearchAndIndexingTest extends ElasticsearchBaseTest {
10
	public static $fixture_file = 'elastica/tests/lotsOfPhotos.yml';
11
12
13
	/*
14
	Notes:
15
	Searching string on number fields fails
16
	http://elasticsearch-users.115913.n3.nabble.com/Error-when-searching-multiple-fields-with-different-types-td3897459.html
17
18
19
	*/
20
	public function testNonTextFields() {
21
		$numericFields = array(
22
			'FlickrID' => 1,
23
			'TakenAt' => 1,
24
			'FirstViewed' => 1,
25
			'Aperture' => 1,
26
			'ShutterSpeed' => 1,
27
			'FocalLength35mm' => 1,
28
			'ISO' => 1
29
		);
30
31
		$this->search('New Zealand', 0, $numericFields);
32
33
		//There are 10 entries in the fixtures, 3 default indexed pages
34
		$this->search(400, 13, $numericFields);
35
36
	}
37
38
	public function testInvalidSearchFields() {
39
		// FIXME test to check unweighted fields
40
	}
41
42
	public function testSetStopwordsConfigurationCSV() {
43
		$stopwords = "a,the,then,this";
44
		$englishIndex = new EnglishIndexSettings();
45
		$englishIndex->setStopwords($stopwords);
46
		$expected = array('a','the','then','this');
47
		$this->assertEquals($expected, $englishIndex->getStopwords());
48
	}
49
50
51
	public function testSetStopwordsConfigurationArray() {
52
		$stopwords = array('a','the','then','this');
53
		$englishIndex = new EnglishIndexSettings();
54
		$englishIndex->setStopwords($stopwords);
55
		$expected = array('a','the','then','this');
56
		$this->assertEquals($expected, $englishIndex->getStopwords());
57
	}
58
59
60
	public function testConfigurationInvalidStopwords() {
61
		$stopwords = 45; // deliberately invalid
62
		$englishIndex = new EnglishIndexSettings();
63
		try {
64
			$englishIndex->setStopwords($stopwords);
65
			// should not get this far, should fail
66
			$this->assertTrue(false, "Invalid stopwords were not correctly prevented");
67
		} catch (Exception $e) {
68
			$this->assertTrue(true, "Invalid stopwords correctly prevented");
69
		}
70
	}
71
72
73
	/*
74
	Search for stop words and assert that they are not found
75
	 */
76
	public function testConfiguredStopWords() {
77
		$englishIndex = new EnglishIndexSettings();
78
		$stopwords = $englishIndex->getStopwords();
79
		$expected = array('that','into','a','an','and','are','as','at','be','but','by','for','if',
80
			'in','into','is','it','of','on','or','such','that','the','their','then','there','these',
81
			'they','this','to','was','will','with');
82
		$this->assertEquals($expected, $stopwords);
83
	}
84
85
86
87
	public function testGetResults() {
88
		// several checks needed  here including aggregations
89
	}
90
91
92
	public function testResultListGetMap() {
93
		$resultList = $this->getResultsFor('New Zealand',10);
94
		//default is ID -> Title, useful for dropdowns
95
		$mapping = $resultList->map();
96
		$ctr = 0;
97
		foreach ($resultList->getIterator() as $item) {
98
			$mappedTitle = $mapping[$item->ID];
99
			$this->assertEquals($item->Title, $mappedTitle);
100
			$ctr++;
101
		}
102
	}
103
104
105
	public function testResultListColumn() {
106
		$resultList = $this->getResultsFor('New Zealand',10);
107
		$ids = $resultList->column();
108
109
		$expected = array();
110
		foreach ($resultList as $item) {
111
			array_push($expected, $item->ID);
112
		}
113
114
		$this->assertEquals($expected,$ids);
115
116
		$expected = array();
117
		foreach ($resultList as $item) {
118
			array_push($expected, $item->Title);
119
		}
120
		$titles = $resultList->column('Title');
121
		$this->assertEquals($expected,$titles);
122
	}
123
124
125
	public function testEach() {
126
		$callback = function($fp) {
127
		    $this->assertTrue(true, 'Callback reached');
128
		};
129
		$resultList = $this->getResultsFor('New Zealand',10);
130
		$resultList->each($callback);
131
	}
132
133
134
	/*
135
	The search term 'New Zealand' was used against Flickr to create the fixtures file, so this means
136
	that all of the fixtures should have 'New Zealand' in them.  Test page length from 1 to 100
137
	 */
138
	public function testResultListPageLength() {
139
		for ($i=1; $i <= 100 ; $i++) {
140
			$resultList = $this->getResultsFor('New Zealand',$i);
141
			$this->assertEquals($i, $resultList->count());
142
		}
143
	}
144
145
146
	public function testResultListIndex() {
147
		$resultList = $this->getResultsFor('New Zealand',10);
148
		$index = $resultList->getService()->getIndex();
149
		$this->assertEquals('elastica_ss_module_test_en_us', $index->getName());
150
	}
151
152
153
	public function testResultListGetQuery() {
154
		$resultList = $this->getResultsFor('New Zealand',10);
155
		$query = $resultList->getQuery()->toArray();
156
157
		$expected = array();
158
		$expected['query'] = array('multi_match' => array(
159
				'query' => 'New Zealand',
160
				'fields' => array('Title', 'Title.*', 'Description', 'Description.*'),
161
				'type' => 'most_fields',
162
				'lenient' => true
163
			)
164
		);
165
		$expected['size'] = 10;
166
		$expected['from'] = 0;
167
168
169
		$this->assertEquals($expected['size'], $query['size']);
170
		$this->assertEquals($expected['from'], $query['from']);
171
		$this->assertEquals($expected['query'], $query['query']);
172
	}
173
174
175
	/*
176
	Check that the time for the search was more than zero
177
	 */
178
	public function testResultListGetTotalTime() {
179
		$resultList = $this->getResultsFor('New Zealand',10);
180
		$time = $resultList->getTotalTime();
181
		$this->assertGreaterThan(0, $time);
182
	}
183
184
185
	/*
186
	Test the result list iterator function
187
	 */
188
	public function testResultListGetIterator() {
189
		$resultList = $this->getResultsFor('New Zealand',100);
190
		$ctr = 0;
191
		foreach ($resultList->getIterator() as $result) {
192
			$ctr++;
193
		}
194
		$this->assertEquals(100,$ctr);
195
	}
196
197
198
	/*
199
	Check some basic properties of the array returned for a result
200
	 */
201
	public function testToArrayFunction() {
202
		$resultList = $this->getResultsFor('New Zealand',1);
203
		$result = $resultList->toArray();
204
205
		$this->assertEquals(1,sizeof($result));
206
		$fp = $result[0];
207
		$this->assertEquals('FlickrPhotoTO', $fp->ClassName);
208
		$this->assertEquals(2147483647, $fp->FlickrID);
209
		$this->assertTrue(preg_match('/New Zealand/',$fp->Title) == 1);
210
	}
211
212
213
	/*
214
	Check some basic properties of the array returned for a result
215
	 */
216
	public function testToNestedArrayFunction() {
217
		$resultList = $this->getResultsFor('New Zealand',4);
218
		$result = $resultList->toNestedArray();
219
220
		$this->assertEquals(4,sizeof($result));
221
		$fp = $result[0];
222
		$this->assertEquals('FlickrPhotoTO', $fp['ClassName']);
223
		$this->assertEquals(2147483647, $fp['FlickrID']);
224
		$this->assertTrue(preg_match('/New Zealand/',$fp['Title']) == 1);
225
	}
226
227
228 View Code Duplication
	public function testResultListOffsetExistsNotImplemented() {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
229
		try {
230
			$resultList = $this->getResultsFor('New Zealand',10);
231
			$resultList->offsetExists(10);
232
			$this->assertFalse(true, "This line should not have been reached");
233
		} catch (Exception $e) {
234
			$this->assertEquals('Not implemented', $e->getMessage());
235
		}
236
	}
237
238
239 View Code Duplication
	public function testResultListOffsetGetNotImplemented() {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
240
		try {
241
			$resultList = $this->getResultsFor('New Zealand',10);
242
			$resultList->offsetGet(10);
243
			$this->assertFalse(true, "This line should not have been reached");
244
		} catch (Exception $e) {
245
			$this->assertEquals('Not implemented', $e->getMessage());
246
		}
247
	}
248
249
250 View Code Duplication
	public function testResultListOffsetSetNotImplemented() {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
251
		try {
252
			$resultList = $this->getResultsFor('New Zealand',10);
253
			$resultList->offsetSet(10,null);
254
			$this->assertFalse(true, "This line should not have been reached");
255
		} catch (Exception $e) {
256
			$this->assertEquals('Not implemented', $e->getMessage());
257
		}
258
	}
259
260
261 View Code Duplication
	public function testResultListOffsetUnsetNotImplemented() {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
262
		try {
263
			$resultList = $this->getResultsFor('New Zealand',10);
264
			$resultList->offsetUnset(10);
265
			$this->assertFalse(true, "This line should not have been reached");
266
		} catch (Exception $e) {
267
			$this->assertEquals('Not implemented', $e->getMessage());
268
		}
269
	}
270
271
272 View Code Duplication
	public function testResultListAddNotImplemented() {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
273
		try {
274
			$resultList = $this->getResultsFor('New Zealand',10);
275
			$fp = new FlickrPhotoTO();
276
			$resultList->add($fp);
277
			$this->assertFalse(true, "This line should not have been reached");
278
		} catch (Exception $e) {
279
			$this->assertEquals('Not implemented', $e->getMessage());
280
		}
281
	}
282
283
284 View Code Duplication
	public function testResultListRemoveNotImplemented() {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
285
		try {
286
			$resultList = $this->getResultsFor('New Zealand',10);
287
			$fp = new FlickrPhotoTO();
288
			$resultList->remove($fp);
289
			$this->assertFalse(true, "This line should not have been reached");
290
		} catch (Exception $e) {
291
			$this->assertEquals('Not implemented', $e->getMessage());
292
		}
293
	}
294
295
296 View Code Duplication
	public function testResultListFindNotImplemented() {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
297
		try {
298
			$resultList = $this->getResultsFor('New Zealand',10);
299
			$fp = new FlickrPhotoTO();
300
			$resultList->find(4,$fp);
301
			$this->assertFalse(true, "This line should not have been reached");
302
		} catch (Exception $e) {
303
			$this->assertEquals('Not implemented', $e->getMessage());
304
		}
305
	}
306
307
308
309
310
	public function testResultListToArray() {
311
		$sfs = SearchableField::get()->filter(array('ClazzName' => 'FlickrPhotoTO', 'Type' => 'string'));
312
		foreach ($sfs->getIterator() as $sf) {
313
			echo "T2 $sf->ClazzName $sf->Name $sf->Type\n";
314
			$sf->ShowHighlights = true;
315
			$sf->write();
316
		}
317
318
		$fields = array('Title' => 1, 'Description' => 1);
319
		$resultList = $this->getResultsFor('New Zealand', 10, $fields);
320
		echo get_class($resultList);
321
322
		$toarr = $resultList->toArray();
323
324
		foreach ($toarr as $item) {
325
			$hl = $item->SearchHighlights;
326
			echo "HL:$hl"; // MORNING FIXME
327
		}
328
329
330
	}
331
332 View Code Duplication
	public function testResultListFirstNotImplemented() {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
333
		try {
334
			$resultList = $this->getResultsFor('New Zealand',10);
335
			$resultList->first();
336
			$this->assertFalse(true, "This line should not have been reached");
337
		} catch (Exception $e) {
338
			$this->assertEquals('Not implemented', $e->getMessage());
339
		}
340
	}
341
342
343 View Code Duplication
	public function testResultListLastNotImplemented() {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
344
		try {
345
			$resultList = $this->getResultsFor('New Zealand',10);
346
			$resultList->last();
347
			$this->assertFalse(true, "This line should not have been reached");
348
		} catch (Exception $e) {
349
			$this->assertEquals('Not implemented', $e->getMessage());
350
		}
351
	}
352
353
354
	public function testFoldedIndexes() {
355
		$this->markTestIncomplete('Folded test to do');
356
	}
357
358
359
	public function testSynonymIndexes() {
360
		$this->markTestIncomplete('Synonym test to do');
361
	}
362
363
364
	public function testNonExistentField() {
365
		try {
366
			// this should fail as field Fwlubble does not exist
367
			$this->search('zealand', 0, array('Fwlubble' => 1));
368
			$this->assertTrue(false, "Field Fwlubble does not exist and an exception should have been thrown");
369
		} catch (Exception $e) {
370
			$this->assertTrue(true, "Field Fwlubble does not exist, exception thrown as expected");
371
		}
372
373
	}
374
375
376
	public function testPriming() {
377
		$searchableClasses = SearchableClass::get();
378
		$sortedNames = $searchableClasses->Map('Name')->toArray();
379
		sort($sortedNames);
380
381
		$expected = array(
382
		'0' => 'FlickrAuthorTO',
383
		'1' => 'FlickrPhotoTO',
384
		'2' => 'FlickrSetTO',
385
		'3' => 'FlickrTagTO',
386
		'4' => 'Page',
387
		'5' => 'SearchableTestPage',
388
		'6' => 'SiteTree'
389
		);
390
		$this->assertEquals($expected, $sortedNames);
391
392
		$searchableFields = SearchableField::get();
393
		$expected = array(
394
			'0' => 'Aperture',
395
			'1' => 'AspectRatio',
396
			'2' => 'Content',
397
			'3' => 'Country',
398
			'4' => 'Description',
399
			'5' => 'DisplayName',
400
			'6' => 'FirstViewed',
401
			'7' => 'FlickrID',
402
			'8' => 'FlickrPhotoTOs',
403
			'9' => 'FlickrSetTOs',
404
			'10' => 'FlickrTagTOs',
405
			'11' => 'FocalLength35mm',
406
			'12' => 'ISO',
407
			'13' => 'PageDate',
408
			'14' => 'PathAlias',
409
			'15' => 'Photographer',
410
			'16' => 'RawValue',
411
			'17' => 'ShutterSpeed',
412
			'18' => 'TakenAt',
413
			'19' => 'TakenAtDT',
414
			'20' => 'TestMethod',
415
			'21' => 'TestMethodHTML',
416
			'22' => 'Title'
417
		);
418
419
		$sortedNames = array_keys($searchableFields->Map('Name')->toArray());
420
		sort($sortedNames);
421
		$this->assertEquals($expected, $sortedNames);
422
	}
423
424
425
	/**
426
	 * Test searching
427
	 * http://stackoverflow.com/questions/28305250/elasticsearch-customize-score-for-synonyms-stemming
428
	 */
429 View Code Duplication
	private function search($query, $resultsExpected = 10, $fields = null) {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
430
		$es = new ElasticSearcher();
431
		$es->setStart(0);
432
		$es->setPageLength(100);
433
		//$es->addFilter('IsInSiteTree', false);
0 ignored issues
show
Unused Code Comprehensibility introduced by
80% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
434
		$es->setClasses('FlickrPhotoTO');
435
		$results = $es->search($query, $fields);
436
437
		$this->assertEquals($resultsExpected, $results->count());
438
		return $results->count();
439
	}
440
441
442 View Code Duplication
	private function getResultsFor($query, $pageLength = 10, $fields = array('Title' => 1, 'Description' => 1)) {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
443
		$es = new ElasticSearcher();
444
		$es->setStart(0);
445
		$es->setPageLength($pageLength);
446
		$es->setClasses('FlickrPhotoTO');
447
		$resultList = $es->search($query, $fields)->getList();
448
		$this->assertEquals('SilverStripe\Elastica\ResultList', get_class($resultList));
449
		return $resultList;
450
	}
451
452
453
}
454