silverstripe /
silverstripe-fulltextsearch
| 1 | <?php |
||
| 2 | |||
| 3 | namespace SilverStripe\FullTextSearch\Tests; |
||
| 4 | |||
| 5 | use Apache_Solr_Document; |
||
| 6 | use Page; |
||
| 7 | use SilverStripe\Assets\File; |
||
| 8 | use SilverStripe\Assets\Image; |
||
| 9 | use SilverStripe\CMS\Model\SiteTree; |
||
| 10 | use SilverStripe\Core\Config\Config; |
||
| 11 | use SilverStripe\Core\Injector\Injector; |
||
| 12 | use SilverStripe\Dev\SapphireTest; |
||
| 13 | use SilverStripe\FullTextSearch\Search\FullTextSearch; |
||
| 14 | use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateImmediateProcessor; |
||
| 15 | use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateProcessor; |
||
| 16 | use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater; |
||
| 17 | use SilverStripe\FullTextSearch\Search\Variants\SearchVariantSubsites; |
||
| 18 | use SilverStripe\FullTextSearch\Solr\Services\Solr4Service; |
||
| 19 | use SilverStripe\FullTextSearch\Tests\SolrIndexSubsitesTest\SolrIndexSubsitesTest_Index; |
||
| 20 | use SilverStripe\FullTextSearch\Tests\SolrIndexVersionedTest\SolrDocumentMatcher; |
||
| 21 | use SilverStripe\ORM\DataObject; |
||
| 22 | use SilverStripe\Subsites\Model\Subsite; |
||
| 23 | use SilverStripe\Versioned\Versioned; |
||
| 24 | |||
| 25 | /** |
||
| 26 | * Subsite specific solr testing |
||
| 27 | */ |
||
| 28 | class SolrIndexSubsitesTest extends SapphireTest |
||
| 29 | { |
||
| 30 | protected static $fixture_file = 'SolrIndexSubsitesTest/SolrIndexSubsitesTest.yml'; |
||
| 31 | |||
| 32 | /** |
||
| 33 | * @var SolrIndexSubsitesTest_Index |
||
| 34 | */ |
||
| 35 | private static $index = null; |
||
| 36 | |||
| 37 | protected $server = null; |
||
| 38 | |||
| 39 | protected function setUp() |
||
| 40 | { |
||
| 41 | // Prevent parent::setUp() crashing on db build |
||
| 42 | if (!class_exists(Subsite::class)) { |
||
| 43 | static::$fixture_file = null; |
||
| 44 | } |
||
| 45 | |||
| 46 | parent::setUp(); |
||
| 47 | |||
| 48 | if (!class_exists(Subsite::class)) { |
||
| 49 | $this->markTestSkipped("These tests need the Subsite module installed to run"); |
||
| 50 | } |
||
| 51 | |||
| 52 | $this->server = $_SERVER; |
||
| 53 | |||
| 54 | if (self::$index === null) { |
||
| 55 | self::$index = singleton(SolrIndexSubsitesTest_Index::class); |
||
| 56 | } |
||
| 57 | |||
| 58 | Config::modify()->set(Injector::class, SearchUpdateProcessor::class, [ |
||
| 59 | 'class' => SearchUpdateImmediateProcessor::class, |
||
| 60 | ]); |
||
| 61 | |||
| 62 | FullTextSearch::force_index_list(self::$index); |
||
| 63 | SearchUpdater::clear_dirty_indexes(); |
||
| 64 | } |
||
| 65 | |||
| 66 | protected function tearDown() |
||
| 67 | { |
||
| 68 | if ($this->server) { |
||
| 69 | $_SERVER = $this->server; |
||
| 70 | $this->server = null; |
||
| 71 | } |
||
| 72 | parent::tearDown(); |
||
| 73 | } |
||
| 74 | |||
| 75 | protected function getServiceMock() |
||
| 76 | { |
||
| 77 | return $this->getMockBuilder(Solr4Service::class) |
||
| 78 | ->setMethods(['addDocument', 'commit']) |
||
| 79 | ->getMock(); |
||
| 80 | } |
||
| 81 | |||
| 82 | /** |
||
| 83 | * @param DataObject $object Item being added |
||
| 84 | * @param int $subsiteID |
||
| 85 | * @param string $stage |
||
| 86 | * @return string |
||
| 87 | */ |
||
| 88 | protected function getExpectedDocumentId($object, $subsiteID, $stage = null) |
||
| 89 | { |
||
| 90 | $id = $object->ID; |
||
| 91 | $class = DataObject::getSchema()->baseDataClass($object); |
||
| 92 | $variants = array(); |
||
| 93 | |||
| 94 | // Check subsite |
||
| 95 | if (class_exists(Subsite::class) |
||
| 96 | && DataObject::getSchema()->hasOneComponent($object->getClassName(), 'Subsite') |
||
| 97 | ) { |
||
| 98 | $variants[] = '"SearchVariantSubsites":"' . $subsiteID . '"'; |
||
| 99 | } |
||
| 100 | |||
| 101 | // Check versioned |
||
| 102 | if ($stage) { |
||
| 103 | $variants[] = '"SearchVariantVersioned":"' . $stage . '"'; |
||
| 104 | } |
||
| 105 | return $id . '-' . $class . '-{' . implode(',', $variants) . '}'; |
||
| 106 | } |
||
| 107 | |||
| 108 | public function testPublishing() |
||
| 109 | { |
||
| 110 | // Setup mocks |
||
| 111 | $serviceMock = $this->getServiceMock(); |
||
| 112 | self::$index->setService($serviceMock); |
||
| 113 | |||
| 114 | $subsite1 = $this->objFromFixture(Subsite::class, 'subsite1'); |
||
| 115 | |||
| 116 | // Add records to first subsite |
||
| 117 | Versioned::set_stage(Versioned::DRAFT); |
||
| 118 | $_SERVER['HTTP_HOST'] = 'www.subsite1.com'; |
||
| 119 | |||
| 120 | $file = new File(); |
||
| 121 | $file->Title = 'My File'; |
||
| 122 | $file->SubsiteID = $subsite1->ID; |
||
| 123 | $file->write(); |
||
| 124 | |||
| 125 | $page = new Page(); |
||
| 126 | $page->Title = 'My Page'; |
||
| 127 | $page->SubsiteID = $subsite1->ID; |
||
| 128 | $page->write(); |
||
| 129 | |||
| 130 | $doc1 = new Apache_Solr_Document([ |
||
|
0 ignored issues
–
show
|
|||
| 131 | '_documentid' => $this->getExpectedDocumentId($page, $subsite1->ID, 'Stage'), |
||
| 132 | 'ClassName' => 'Page', |
||
| 133 | 'SiteTree_Title' => 'My Page', |
||
| 134 | '_versionedstage' => 'Stage', |
||
| 135 | '_subsite' => $subsite1->ID, |
||
| 136 | ]); |
||
| 137 | |||
| 138 | $doc2 = new Apache_Solr_Document([ |
||
| 139 | '_documentid' => $this->getExpectedDocumentId($file, $subsite1->ID), |
||
| 140 | 'ClassName' => File::class, |
||
| 141 | 'File_Title' => 'My File', |
||
| 142 | '_subsite' => $subsite1->ID, |
||
| 143 | ]); |
||
| 144 | |||
| 145 | $serviceMock |
||
| 146 | ->expects($this->exactly(2)) |
||
| 147 | ->method('addDocument') |
||
| 148 | ->withConsecutive($doc1, $doc2); |
||
| 149 | |||
| 150 | SearchUpdater::flush_dirty_indexes(); |
||
| 151 | } |
||
| 152 | |||
| 153 | public function testCorrectSubsiteIDOnPageWrite() |
||
| 154 | { |
||
| 155 | $mockWrites = [ |
||
| 156 | '3367:SiteTree:a:1:{s:22:"SearchVariantVersioned";s:4:"Live";}' => [ |
||
| 157 | 'base' => 'SilverStripe\\CMS\\Model\\SiteTree', |
||
| 158 | 'class' => 'Page', |
||
| 159 | 'id' => 3367, |
||
| 160 | 'statefulids' => [ |
||
| 161 | [ |
||
| 162 | 'id' => 3367, |
||
| 163 | 'state' => [ |
||
| 164 | 'SearchVariantVersioned' => 'Live', |
||
| 165 | ], |
||
| 166 | ], |
||
| 167 | ], |
||
| 168 | 'fields' => [ |
||
| 169 | 'SilverStripe\\CMS\\Model\\SiteTree:ClassName' => 'Page', |
||
| 170 | 'SilverStripe\\CMS\\Model\\SiteTree:LastEdited' => '2016-12-08 23:55:30', |
||
| 171 | 'SilverStripe\\CMS\\Model\\SiteTree:Created' => '2016-11-30 05:23:58', |
||
| 172 | 'SilverStripe\\CMS\\Model\\SiteTree:URLSegment' => 'test', |
||
| 173 | 'SilverStripe\\CMS\\Model\\SiteTree:Title' => 'Test Title', |
||
| 174 | 'SilverStripe\\CMS\\Model\\SiteTree:Content' => '<p>test content</p>', |
||
| 175 | 'SilverStripe\\CMS\\Model\\SiteTree:MetaDescription' => 'a solr test', |
||
| 176 | 'SilverStripe\\CMS\\Model\\SiteTree:ShowInMenus' => 1, |
||
| 177 | 'SilverStripe\\CMS\\Model\\SiteTree:ShowInSearch' => 1, |
||
| 178 | 'SilverStripe\\CMS\\Model\\SiteTree:Sort' => 77, |
||
| 179 | 'SilverStripe\\CMS\\Model\\SiteTree:HasBrokenFile' => 0, |
||
| 180 | 'SilverStripe\\CMS\\Model\\SiteTree:HasBrokenLink' => 0, |
||
| 181 | 'SilverStripe\\CMS\\Model\\SiteTree:CanViewType' => 'Inherit', |
||
| 182 | 'SilverStripe\\CMS\\Model\\SiteTree:CanEditType' => 'Inherit', |
||
| 183 | 'SilverStripe\\CMS\\Model\\SiteTree:Locale' => 'en_NZ', |
||
| 184 | 'SilverStripe\\CMS\\Model\\SiteTree:SubsiteID' => 0, |
||
| 185 | 'Page:ID' => 3367, |
||
| 186 | 'Page:MetaKeywords' => null, |
||
| 187 | ], |
||
| 188 | ], |
||
| 189 | ]; |
||
| 190 | $variant = new SearchVariantSubsites(); |
||
| 191 | $tmpMockWrites = $mockWrites; |
||
| 192 | $variant->extractManipulationWriteState($tmpMockWrites); |
||
| 193 | |||
| 194 | foreach ($tmpMockWrites as $mockWrite) { |
||
| 195 | $this->assertCount(1, $mockWrite['statefulids']); |
||
| 196 | $statefulIDs = array_shift($mockWrite['statefulids']); |
||
| 197 | |||
| 198 | $this->assertArrayHasKey(SearchVariantSubsites::class, $statefulIDs['state']); |
||
| 199 | $this->assertEquals(0, $statefulIDs['state'][SearchVariantSubsites::class]); |
||
| 200 | } |
||
| 201 | |||
| 202 | $subsite = $this->objFromFixture(Subsite::class, 'subsite1'); |
||
| 203 | $tmpMockWrites = $mockWrites; |
||
| 204 | $tmpMockWrites['3367:SiteTree:a:1:{s:22:"SearchVariantVersioned";s:4:"Live";}']['fields'][SiteTree::class . ':SubsiteID'] = $subsite->ID; |
||
| 205 | |||
| 206 | $variant->extractManipulationWriteState($tmpMockWrites); |
||
| 207 | foreach ($tmpMockWrites as $mockWrite) { |
||
| 208 | $this->assertCount(1, $mockWrite['statefulids']); |
||
| 209 | $statefulIDs = array_shift($mockWrite['statefulids']); |
||
| 210 | |||
| 211 | $this->assertArrayHasKey(SearchVariantSubsites::class, $statefulIDs['state']); |
||
| 212 | $this->assertEquals($subsite->ID, $statefulIDs['state'][SearchVariantSubsites::class]); |
||
| 213 | } |
||
| 214 | } |
||
| 215 | |||
| 216 | public function testCorrectSubsiteIDOnFileWrite() |
||
| 217 | { |
||
| 218 | $subsiteIDs = ['0'] + $this->allFixtureIDs(Subsite::class); |
||
| 219 | $mockWrites = [ |
||
| 220 | '35910:File:a:0:{}' => [ |
||
| 221 | 'base' => File::class, |
||
| 222 | 'class' => File::class, |
||
| 223 | 'id' => 35910, |
||
| 224 | 'statefulids' => [ |
||
| 225 | [ |
||
| 226 | 'id' => 35910, |
||
| 227 | 'state' => [], |
||
| 228 | ], |
||
| 229 | ], |
||
| 230 | 'fields' => [ |
||
| 231 | File::class . ':ClassName' => Image::class, |
||
| 232 | File::class . ':ShowInSearch' => 1, |
||
| 233 | File::class . ':ParentID' => 26470, |
||
| 234 | File::class . ':Filename' => 'assets/Uploads/pic.jpg', |
||
| 235 | File::class . ':Name' => 'pic.jpg', |
||
| 236 | File::class . ':Title' => 'pic', |
||
| 237 | File::class . ':SubsiteID' => 0, |
||
| 238 | File::class . ':OwnerID' => 661, |
||
| 239 | File::class . ':CurrentVersionID' => 22038, |
||
| 240 | File::class . ':LastEdited' => '2016-12-09 00:35:13', |
||
| 241 | ], |
||
| 242 | ], |
||
| 243 | ]; |
||
| 244 | $variant = new SearchVariantSubsites(); |
||
| 245 | $tmpMockWrites = $mockWrites; |
||
| 246 | $variant->extractManipulationWriteState($tmpMockWrites); |
||
| 247 | foreach ($tmpMockWrites as $mockWrite) { |
||
| 248 | $this->assertCount(count($subsiteIDs), $mockWrite['statefulids']); |
||
| 249 | foreach ($mockWrite['statefulids'] as $statefulIDs) { |
||
| 250 | $this->assertContains( |
||
| 251 | $statefulIDs['state'][SearchVariantSubsites::class], |
||
| 252 | $subsiteIDs, |
||
| 253 | sprintf( |
||
| 254 | 'Failed to assert that %s is in list of valid subsites: %s', |
||
| 255 | $statefulIDs['state'][SearchVariantSubsites::class], |
||
| 256 | implode(', ', $subsiteIDs) |
||
| 257 | ) |
||
| 258 | ); |
||
| 259 | } |
||
| 260 | } |
||
| 261 | |||
| 262 | $subsite = $this->objFromFixture(Subsite::class, 'subsite1'); |
||
| 263 | $tmpMockWrites = $mockWrites; |
||
| 264 | $tmpMockWrites['35910:File:a:0:{}']['fields'][File::class . ':SubsiteID'] = $subsite->ID; |
||
| 265 | |||
| 266 | $variant->extractManipulationWriteState($tmpMockWrites); |
||
| 267 | foreach ($tmpMockWrites as $mockWrite) { |
||
| 268 | $this->assertCount(1, $mockWrite['statefulids']); |
||
| 269 | $statefulIDs = array_shift($mockWrite['statefulids']); |
||
| 270 | $this->assertEquals($subsite->ID, $statefulIDs['state'][SearchVariantSubsites::class]); |
||
| 271 | } |
||
| 272 | } |
||
| 273 | } |
||
| 274 |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.