diff --git a/.travis.yml b/.travis.yml index 29a5d37..bdce2be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,24 +7,38 @@ sudo: false php: - 5.5 - 5.6 + - 7.0 + - 7.1 env: - - DB=MYSQL CORE_RELEASE=3.2 + - DB=MYSQL CORE_RELEASE=4 matrix: include: - php: 5.6 - env: DB=MYSQL CORE_RELEASE=3.2 + env: DB=MYSQL CORE_RELEASE=4 - php: 5.6 - env: DB=MYSQL CORE_RELEASE=3.3 SUBSITES=1 + # env: DB=MYSQL CORE_RELEASE=4 SUBSITES=1 - php: 5.6 - env: DB=MYSQL CORE_RELEASE=3.3 QUEUEDJOBS=1 + env: DB=MYSQL CORE_RELEASE=4 QUEUEDJOBS=1 + - php: 7.0 + env: DB=MYSQL CORE_RELEASE=4 + - php: 7.0 + # env: DB=MYSQL CORE_RELEASE=4 SUBSITES=1 + - php: 7.0 + env: DB=MYSQL CORE_RELEASE=4 QUEUEDJOBS=1 + - php: 7.1 + env: DB=MYSQL CORE_RELEASE=4 + - php: 7.1 + # env: DB=MYSQL CORE_RELEASE=4 SUBSITES=1 + - php: 7.1 + env: DB=MYSQL CORE_RELEASE=4 QUEUEDJOBS=1 before_script: - composer self-update || true - git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support - "if [ \"$SUBSITES\" = \"\" -a \"$QUEUEDJOBS\" = \"\" ]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss; fi" - - "if [ \"$SUBSITES\" = \"1\" ]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require silverstripe/subsites; fi" +# - "if [ \"$SUBSITES\" = \"1\" ]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require silverstripe/subsites; fi" - "if [ \"$QUEUEDJOBS\" = \"1\" ]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require silverstripe/queuedjobs; fi" - cd ~/builds/ss diff --git a/_config/binding.yml b/_config/binding.yml index 14702a3..d179d1e 100644 --- a/_config/binding.yml +++ b/_config/binding.yml @@ -1,5 +1,5 @@ SilverStripe\Core\Injector\Injector: - RequestProcessor: + SilverStripe\Control\RequestProcessor: properties: filters: - - '%$SearchUpdater_BindManipulationCaptureFilter' + - '%$SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater_BindManipulationCaptureFilter' diff --git a/_config/config.yml b/_config/config.yml index 86f8423..18f6a6e 100644 --- a/_config/config.yml +++ b/_config/config.yml @@ -1,3 +1,3 @@ -SilverStripe\ORM\DataObject\DataObject: +SilverStripe\ORM\DataObject: extensions: - 'SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater_ObjectHandler' diff --git a/_config/processor.yml b/_config/processor.yml index fbd4b3e..ca5cb03 100644 --- a/_config/processor.yml +++ b/_config/processor.yml @@ -7,23 +7,11 @@ SilverStripe\Core\Injector\Injector: SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler: class: SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexImmediateHandler SilverStripe\FullTextSearch\Utils\Logging\SearchLogFactory: - class: 'SilverStripe\FullTextSearch\Utils\Logging\MonologFactory' ---- -Name: messagequeueprocessor -Only: - ModuleExists: messagequeue -Except: - Environment: 'dev' ---- -SilverStripe\Core\Injector\Injector: - SilverStripe\FullTextSearch\Search\Processors\SearchUpdateProcessor: - class: SilverStripe\FullTextSearch\Search\Processors\SearchUpdateMessageQueueProcessor - SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler: - class: SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexMessageHandler + class: SilverStripe\FullTextSearch\Utils\Logging\MonologFactory --- Name: queuedjobprocessor Only: - ModuleExists: queuedjobs + ModuleExists: silverstripe/queuedjobs Except: Environment: 'dev' --- diff --git a/code/search/FullTextSearch.php b/code/search/FullTextSearch.php index 42cb3a2..142f43a 100644 --- a/code/search/FullTextSearch.php +++ b/code/search/FullTextSearch.php @@ -1,11 +1,12 @@ $class) { diff --git a/code/search/captures/SearchManipulateCapture_MySQLDatabase.php b/code/search/captures/SearchManipulateCapture_MySQLDatabase.php new file mode 100644 index 0000000..f1b9296 --- /dev/null +++ b/code/search/captures/SearchManipulateCapture_MySQLDatabase.php @@ -0,0 +1,17 @@ +getClasses(); foreach ($sources as $source => $options) { - $sources[$source]['base'] = ClassInfo::baseDataClass($source); + $sources[$source]['base'] = DataObject::getSchema()->baseDataClass($source); $sources[$source]['lookup_chain'] = array(); } @@ -94,22 +96,24 @@ abstract class SearchIndex extends ViewableData foreach (SearchIntrospection::hierarchy($source, $options['include_children']) as $dataclass) { $singleton = singleton($dataclass); + $schema = DataObject::getSchema(); + $className = $singleton->getClassName(); - if ($hasOne = $singleton->hasOne($lookup)) { + if ($hasOne = $schema->hasOneComponent($className, $lookup)) { $class = $hasOne; $options['lookup_chain'][] = array( 'call' => 'method', 'method' => $lookup, 'through' => 'has_one', 'class' => $dataclass, 'otherclass' => $class, 'foreignkey' => "{$lookup}ID" ); - } elseif ($hasMany = $singleton->hasMany($lookup)) { + } elseif ($hasMany = $schema->hasManyComponent($className, $lookup)) { $class = $hasMany; $options['multi_valued'] = true; $options['lookup_chain'][] = array( 'call' => 'method', 'method' => $lookup, - 'through' => 'has_many', 'class' => $dataclass, 'otherclass' => $class, 'foreignkey' => $singleton->getRemoteJoinField($lookup, 'has_many') + 'through' => 'has_many', 'class' => $dataclass, 'otherclass' => $class, 'foreignkey' => $schema->getRemoteJoinField($className, $lookup, 'has_many') ); - } elseif ($manyMany = $singleton->manyMany($lookup)) { - $class = $manyMany[1]; + } elseif ($manyMany = $schema->manyManyComponent($className, $lookup)) { + $class = $manyMany[2]; $options['multi_valued'] = true; $options['lookup_chain'][] = array( 'call' => 'method', 'method' => $lookup, @@ -222,7 +226,7 @@ abstract class SearchIndex extends ViewableData } if (!DataObject::getSchema()->classHasTable($class)) { - throw new InvalidArgumentException('Can\'t add classes which don\'t have data tables (no $db or $has_one set on the class)'); + throw new \InvalidArgumentException('Can\'t add classes which don\'t have data tables (no $db or $has_one set on the class)'); } $options = array_merge(array( @@ -299,13 +303,16 @@ abstract class SearchIndex extends ViewableData foreach ($this->getClasses() as $class => $options) { foreach (SearchIntrospection::hierarchy($class, $includeSubclasses, true) as $dataclass) { $fields = DataObject::getSchema()->databaseFields($class); - foreach ($fields as $field => $type) { if (preg_match('/^(\w+)\(/', $type, $match)) { $type = $match[1]; } list($type, $args) = Object::parse_class_spec($type); - if (is_subclass_of($type, 'SilverStripe\ORM\FieldType\DBString')) { + + // Get class from shortName + $object = Injector::inst()->get($type, false, ['Name' => 'test']); + + if (is_subclass_of(get_class($object), 'SilverStripe\ORM\FieldType\DBString')) { $this->addFulltextField($field); } } @@ -470,9 +477,8 @@ abstract class SearchIndex extends ViewableData } $object = $next; - } - // Otherwise, just call - else { + } else { + // Otherwise, just call if ($step['call'] == 'method') { $method = $step['method']; $object = $object->$method(); @@ -502,9 +508,10 @@ abstract class SearchIndex extends ViewableData * @param Exception $e * @throws Exception */ - public static function warn($e) { + public static function warn($e) + { // Noisy errors during testing - if(class_exists('SapphireTest', false) && SapphireTest::is_running_test()) { + if (class_exists('SapphireTest', false) && SapphireTest::is_running_test()) { throw $e; } SS_Log::log($e, SS_Log::WARN); @@ -529,7 +536,7 @@ abstract class SearchIndex extends ViewableData // First, if this object is directly contained in the index, add it foreach ($this->classes as $searchclass => $options) { if ($searchclass == $class || ($options['include_children'] && is_subclass_of($class, $searchclass))) { - $base = ClassInfo::baseDataClass($searchclass); + $base = DataObject::getSchema()->baseDataClass($searchclass); $dirty[$base] = array(); foreach ($statefulids as $statefulid) { $key = serialize($statefulid); @@ -557,19 +564,25 @@ abstract class SearchIndex extends ViewableData $ids = array($id); foreach ($derivation['chain'] as $step) { + // Use TableName for queries + $tableName = DataObject::getSchema()->tableName($step['class']); + if ($step['through'] == 'has_one') { - $sql = new SQLQuery('"ID"', '"'.$step['class'].'"', '"'.$step['foreignkey'].'" IN ('.implode(',', $ids).')'); + $sql = new SQLSelect('"ID"', '"'.$tableName.'"', '"'.$step['foreignkey'].'" IN ('.implode(',', $ids).')'); singleton($step['class'])->extend('augmentSQL', $sql); $ids = $sql->execute()->column(); } elseif ($step['through'] == 'has_many') { - $sql = new SQLQuery('"'.$step['class'].'"."ID"', '"'.$step['class'].'"', '"'.$step['otherclass'].'"."ID" IN ('.implode(',', $ids).')'); - $sql->addInnerJoin($step['otherclass'], '"'.$step['class'].'"."ID" = "'.$step['otherclass'].'"."'.$step['foreignkey'].'"'); + // Use TableName for queries + $otherTableName = DataObject::getSchema()->tableName($step['otherclass']); + + $sql = new SQLSelect('"'.$tableName.'"."ID"', '"'.$tableName.'"', '"'.$otherTableName.'"."ID" IN ('.implode(',', $ids).')'); + $sql->addInnerJoin($otherTableName, '"'.$tableName.'"."ID" = "'.$otherTableName.'"."'.$step['foreignkey'].'"'); singleton($step['class'])->extend('augmentSQL', $sql); $ids = $sql->execute()->column(); } - + if (empty($ids)) { break; } @@ -597,8 +610,8 @@ abstract class SearchIndex extends ViewableData /** !! These should be implemented by the full text search engine */ - abstract public function add($object) ; - abstract public function delete($base, $id, $state) ; + abstract public function add($object); + abstract public function delete($base, $id, $state); abstract public function commit(); diff --git a/code/search/indexes/SearchIndex_Null.php b/code/search/indexes/SearchIndex_Null.php index b2a2896..6b92e5d 100644 --- a/code/search/indexes/SearchIndex_Null.php +++ b/code/search/indexes/SearchIndex_Null.php @@ -2,8 +2,6 @@ namespace SilverStripe\FullTextSearch\Search\Indexes; -use SilverStripe\FullTextSearch\Search\Indexes\SearchIndex; - /** * A search index that does nothing. Useful for testing */ diff --git a/code/search/processors/SearchUpdateBatchedProcessor.php b/code/search/processors/SearchUpdateBatchedProcessor.php index eaf2fd4..78166da 100644 --- a/code/search/processors/SearchUpdateBatchedProcessor.php +++ b/code/search/processors/SearchUpdateBatchedProcessor.php @@ -1,5 +1,9 @@ create(__CLASS__); - $id = singleton('QueuedJobService')->queueJob($commit, $startAfter); + $id = singleton(QueuedJobService::class)->queueJob($commit, $startAfter); if ($dirty) { $indexes = FullTextSearch::get_indexes(); @@ -159,7 +172,7 @@ class SearchUpdateCommitJobProcessor implements QueuedJob // This could occur if we completed a searchupdate job in a prior request, as well as in // the current request $cooldown = Config::inst()->get(__CLASS__, 'cooldown'); - $now = new DateTime(SS_Datetime::now()->getValue()); + $now = new DateTime(DBDatetime::now()->getValue()); $now->add(new DateInterval('PT'.$cooldown.'S')); $runat = $now->Format('Y-m-d H:i:s'); diff --git a/code/search/processors/SearchUpdateImmediateProcessor.php b/code/search/processors/SearchUpdateImmediateProcessor.php index b9c0288..66cb6cf 100644 --- a/code/search/processors/SearchUpdateImmediateProcessor.php +++ b/code/search/processors/SearchUpdateImmediateProcessor.php @@ -1,5 +1,7 @@ get('SearchMessageQueueUpdater', 'reindex_queue'), - new MethodInvocationMessage($this, "process") - ); - } -} diff --git a/code/search/processors/SearchUpdateProcessor.php b/code/search/processors/SearchUpdateProcessor.php index ebdc84a..b437f7b 100644 --- a/code/search/processors/SearchUpdateProcessor.php +++ b/code/search/processors/SearchUpdateProcessor.php @@ -1,5 +1,11 @@ baseDataClass($class); $forclass = isset($this->dirty[$base]) ? $this->dirty[$base] : array(); foreach ($statefulids as $statefulid) { diff --git a/code/search/processors/SearchUpdateQueuedJobProcessor.php b/code/search/processors/SearchUpdateQueuedJobProcessor.php index 17dc750..27eedd4 100644 --- a/code/search/processors/SearchUpdateQueuedJobProcessor.php +++ b/code/search/processors/SearchUpdateQueuedJobProcessor.php @@ -1,9 +1,17 @@ queueJob($this); + singleton(QueuedJobService::class)->queueJob($this); } public function getTitle() diff --git a/code/search/queries/SearchQuery.php b/code/search/queries/SearchQuery.php index d40fea4..8fe5f88 100644 --- a/code/search/queries/SearchQuery.php +++ b/code/search/queries/SearchQuery.php @@ -1,11 +1,15 @@ currentDatabase() || @$current->isManipulationCapture) { + $current = DB::get_conn(); + + if (!$current || !$current->getSelectedDatabase() || @$current->isManipulationCapture) { return; } // If not yet set, or its already captured, just return - $type = get_class($current); - $file = TEMP_FOLDER."/.cache.SMC.$type"; + $type = (new ReflectionClass($current))->getShortName(); + $dbClass = 'SilverStripe\FullTextSearch\Captures\SearchManipulateCapture_' . $type; - if (!is_file($file)) { - file_put_contents($file, "setConnector($current->getConnector()); - $captured->setQueryBuilder($current->getQueryBuilder()); - $captured->setSchemaManager($current->getSchemaManager()); - } + $captured->setConnector($current->getConnector()); + $captured->setQueryBuilder($current->getQueryBuilder()); + $captured->setSchemaManager($current->getSchemaManager()); // The connection might have had it's name changed (like if we're currently in a test) - $captured->selectDatabase($current->currentDatabase()); - DB::setConn($captured); + $captured->selectDatabase($current->getSelectedDatabase()); + DB::set_conn($captured); } public static $registered = false; @@ -90,7 +79,9 @@ class SearchUpdater extends Object { // First, extract any state that is in the manipulation itself foreach ($manipulation as $table => $details) { - $manipulation[$table]['class'] = $table; + if (!isset($manipulation[$table]['class'])) { + $manipulation[$table]['class'] = DataObject::getSchema()->tableClass($table); + } $manipulation[$table]['state'] = array(); } @@ -110,7 +101,7 @@ class SearchUpdater extends Object $class = $details['class']; $fields = isset($details['fields']) ? $details['fields'] : array(); - $base = ClassInfo::baseDataClass($class); + $base = DataObject::getSchema()->baseDataClass($class); $key = "$id:$base:".serialize($state); $statefulids = array(array('id' => $id, 'state' => $state)); @@ -171,7 +162,7 @@ class SearchUpdater extends Object foreach ($dirtyids as $dirtyclass => $ids) { if ($ids) { if (!self::$processor) { - self::$processor = Injector::inst()->create('SearchUpdateProcessor'); + self::$processor = Injector::inst()->create(SearchUpdateImmediateProcessor::class); } self::$processor->addDirtyIDs($dirtyclass, $ids, $index); } @@ -184,10 +175,9 @@ class SearchUpdater extends Object // Don't do it if we're testing - there's no database connection outside the test methods, so we'd // just get errors - $runningTests = class_exists('SapphireTest', false) && SapphireTest::is_running_test(); - if (self::$processor && !self::$registered && !$runningTests) { - register_shutdown_function(array("SearchUpdater", "flush_dirty_indexes")); + if (self::$processor && !self::$registered && !SapphireTest::is_running_test()) { + register_shutdown_function(array(SearchUpdater::class, "flush_dirty_indexes")); self::$registered = true; } } @@ -214,6 +204,3 @@ class SearchUpdater extends Object self::$processor = null; } } - - - diff --git a/code/search/updaters/SearchUpdater_ObjectHandler.php b/code/search/updaters/SearchUpdater_ObjectHandler.php index da248ba..f469584 100644 --- a/code/search/updaters/SearchUpdater_ObjectHandler.php +++ b/code/search/updaters/SearchUpdater_ObjectHandler.php @@ -1,7 +1,10 @@ owner->ID; $class = $this->owner->ClassName; $state = SearchVariant::current_state($class); - $base = ClassInfo::baseDataClass($class); + $base = DataObject::getSchema()->baseDataClass($class); $key = "$id:$base:".serialize($state); $statefulids = array(array( @@ -63,4 +66,4 @@ class SearchUpdater_ObjectHandler extends DataExtension SearchUpdater::process_writes($writes); } -} \ No newline at end of file +} diff --git a/code/search/variants/SearchVariant.php b/code/search/variants/SearchVariant.php index 57f6479..153ec17 100644 --- a/code/search/variants/SearchVariant.php +++ b/code/search/variants/SearchVariant.php @@ -1,6 +1,12 @@ '_subsite', 'field' => '_subsite', 'fullfield' => '_subsite', - 'base' => ClassInfo::baseDataClass($class), + 'base' => DataObject::getSchema()->baseDataClass($class), 'origin' => $class, 'type' => 'Int', 'lookup_chain' => array(array('call' => 'variant', 'variant' => $self, 'method' => 'currentState')) @@ -78,7 +85,7 @@ class SearchVariantSiteTreeSubsitesPolyhome extends SearchVariant } if (self::$subsites === null) { - $query = new SQLQuery('ID', 'Subsite'); + $query = new SQLSelect('ID', 'Subsite'); self::$subsites = array_merge(array('0'), $query->execute()->column()); } diff --git a/code/search/variants/SearchVariantSubsites.php b/code/search/variants/SearchVariantSubsites.php index 1f62f71..5102584 100644 --- a/code/search/variants/SearchVariantSubsites.php +++ b/code/search/variants/SearchVariantSubsites.php @@ -1,5 +1,17 @@ '_subsite', 'field' => '_subsite', 'fullfield' => '_subsite', - 'base' => ClassInfo::baseDataClass($class), + 'base' => DataObject::getSchema()->baseDataClass($class), 'origin' => $class, 'type' => 'Int', 'lookup_chain' => array(array('call' => 'variant', 'variant' => $self, 'method' => 'currentState')) @@ -74,7 +86,7 @@ class SearchVariantSubsites extends SearchVariant public function extractManipulationWriteState(&$writes) { $self = get_class($this); - $query = new SQLQuery('"ID"', '"Subsite"'); + $query = new SQLSelect('"ID"', '"Subsite"'); $subsites = array_merge(array('0'), $query->execute()->column()); foreach ($writes as $key => $write) { diff --git a/code/search/variants/SearchVariantVersioned.php b/code/search/variants/SearchVariantVersioned.php index 767bdec..6c73b77 100644 --- a/code/search/variants/SearchVariantVersioned.php +++ b/code/search/variants/SearchVariantVersioned.php @@ -1,21 +1,23 @@ '_versionedstage', 'field' => '_versionedstage', 'fullfield' => '_versionedstage', - 'base' => ClassInfo::baseDataClass($class), + 'base' => DataObject::getSchema()->baseDataClass($class), 'origin' => $class, 'type' => 'String', 'lookup_chain' => array(array('call' => 'variant', 'variant' => $self, 'method' => 'currentState')) @@ -43,7 +45,7 @@ class SearchVariantVersioned extends SearchVariant public function alterQuery($query, $index) { - $stage = Versioned::current_stage(); + $stage = $this->currentState(); $query->filter('_versionedstage', array($stage, SearchQuery::$missing)); } @@ -56,7 +58,7 @@ class SearchVariantVersioned extends SearchVariant $stage = 'Stage'; if (preg_match('/^(.*)_Live$/', $table, $matches)) { - $class = $matches[1]; + $class = DataObject::getSchema()->tableClass($matches[1]); $stage = 'Live'; } diff --git a/code/search/variants/SearchVariant_Caller.php b/code/search/variants/SearchVariant_Caller.php index c95c648..b037129 100644 --- a/code/search/variants/SearchVariant_Caller.php +++ b/code/search/variants/SearchVariant_Caller.php @@ -1,10 +1,4 @@ =')) { $versionDefaults = array( - 'service' => 'Solr4Service', + 'service' => Solr4Service::class, 'extraspath' => Director::baseFolder().'/fulltextsearch/conf/solr/4/extras/', 'templatespath' => Director::baseFolder().'/fulltextsearch/conf/solr/4/templates/', ); } else { $versionDefaults = array( - 'service' => 'Solr3Service', + 'service' => Solr3Service::class, 'extraspath' => Director::baseFolder().'/fulltextsearch/conf/solr/3/extras/', 'templatespath' => Director::baseFolder().'/fulltextsearch/conf/solr/3/templates/', ); diff --git a/code/solr/SolrIndex.php b/code/solr/SolrIndex.php index bac125b..68ca165 100644 --- a/code/solr/SolrIndex.php +++ b/code/solr/SolrIndex.php @@ -1,9 +1,20 @@ fulltextFields[$field])) { - throw new InvalidArgumentException("No fulltext field $field exists on ".$this->getIndexName()); + throw new \InvalidArgumentException("No fulltext field $field exists on ".$this->getIndexName()); } if ($level === null) { unset($this->boostedFields[$field]); @@ -538,7 +549,10 @@ abstract class SolrIndex extends SearchIndex return; } - $doc->setField($field['name'], $value); + // Only index fields that are not null + if ($value !== null) { + $doc->setField($field['name'], $value); + } } } @@ -546,7 +560,7 @@ abstract class SolrIndex extends SearchIndex { $includeSubs = $options['include_children']; - $doc = new Apache_Solr_Document(); + $doc = new \Apache_Solr_Document(); // Always present fields @@ -583,7 +597,7 @@ abstract class SolrIndex extends SearchIndex foreach ($this->getClasses() as $searchclass => $options) { if ($searchclass == $class || ($options['include_children'] && is_subclass_of($class, $searchclass))) { - $base = ClassInfo::baseDataClass($searchclass); + $base = DataObject::getSchema()->baseDataClass($searchclass); $docs[] = $this->_addAs($object, $base, $options); } } @@ -748,7 +762,7 @@ abstract class SolrIndex extends SearchIndex $offset, $limit, $params, - Apache_Solr_Service::METHOD_POST + \Apache_Solr_Service::METHOD_POST ); $results = new ArrayList(); diff --git a/code/solr/reindex/handlers/SolrReindexBase.php b/code/solr/reindex/handlers/SolrReindexBase.php index 0afea23..50822ac 100644 --- a/code/solr/reindex/handlers/SolrReindexBase.php +++ b/code/solr/reindex/handlers/SolrReindexBase.php @@ -3,9 +3,13 @@ namespace SilverStripe\FullTextSearch\Solr\Reindex\Handlers; use Psr\Log\LoggerInterface; -use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; use SilverStripe\FullTextSearch\Solr\Solr; use SilverStripe\FullTextSearch\Solr\SolrIndex; +use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; +use SilverStripe\FullTextSearch\Search\Queries\SearchQuery; +use SilverStripe\ORM\DataObject; +use SilverStripe\ORM\DataList; +use SilverStripe\ORM\DB; /** * Base class for re-indexing of solr content @@ -18,7 +22,7 @@ abstract class SolrReindexBase implements SolrReindexHandler $this->processIndex($logger, $indexInstance, $batchSize, $taskName, $classes); } } - + /** * Process index for a single SolrIndex instance * @@ -164,7 +168,7 @@ abstract class SolrReindexBase implements SolrReindexHandler // This will slow down things a tiny bit, but it is done so that we don't timeout to the database during a reindex DB::query('SELECT 1'); - + $logger->info("Done"); } @@ -182,11 +186,11 @@ abstract class SolrReindexBase implements SolrReindexHandler protected function getRecordsInGroup(SolrIndex $indexInstance, $class, $groups, $group) { // Generate filtered list of local records - $baseClass = ClassInfo::baseDataClass($class); + $baseClass = DataObject::getSchema()->baseDataClass($class); $items = DataList::create($class) ->where(sprintf( '"%s"."ID" %% \'%d\' = \'%d\'', - $baseClass, + DataObject::getSchema()->tableName($baseClass), intval($groups), intval($group) )) diff --git a/code/solr/reindex/handlers/SolrReindexMessageHandler.php b/code/solr/reindex/handlers/SolrReindexMessageHandler.php deleted file mode 100644 index 71e6fba..0000000 --- a/code/solr/reindex/handlers/SolrReindexMessageHandler.php +++ /dev/null @@ -1,44 +0,0 @@ -get(__CLASS__, 'reindex_queue'); - - $logger->info('Queuing message'); - MessageQueue::send( - $queue, - new MethodInvocationMessage('SolrReindexMessageHandler', 'run_reindex', $batchSize, $taskName, $classes) - ); - } - - /** - * Entry point for message queue - * - * @param int $batchSize - * @param string $taskName - * @param array|string|null $classes - */ - public static function run_reindex($batchSize, $taskName, $classes = null) - { - // @todo Logger for message queue? - $logger = Injector::inst()->createWithArgs('Monolog\Logger', array(strtolower(get_class()))); - - $inst = Injector::inst()->get(get_class()); - $inst->runReindex($logger, $batchSize, $taskName, $classes); - } -} diff --git a/code/solr/reindex/handlers/SolrReindexQueuedHandler.php b/code/solr/reindex/handlers/SolrReindexQueuedHandler.php index 504f328..bda7024 100644 --- a/code/solr/reindex/handlers/SolrReindexQueuedHandler.php +++ b/code/solr/reindex/handlers/SolrReindexQueuedHandler.php @@ -4,11 +4,22 @@ namespace SilverStripe\FullTextSearch\Solr\Reindex\Handlers; use Psr\Log\LoggerInterface; use SilverStripe\FullTextSearch\Solr\SolrIndex; +use SilverStripe\ORM\DataObject; +use SilverStripe\ORM\DB; +use SilverStripe\Core\Convert; +use SilverStripe\Core\Injector\Injector; +use SilverStripe\FullTextSearch\Solr\Reindex\Jobs\SolrReindexQueuedJob; +use SilverStripe\FullTextSearch\Solr\Reindex\Jobs\SolrReindexGroupQueuedJob; +use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateCommitJobProcessor; -if (!interface_exists('QueuedJob')) { +if (!interface_exists('SilverStripe\QueuedJobs\Services\QueuedJob')) { return; } +use SilverStripe\QueuedJobs\Services\QueuedJob; +use SilverStripe\QueuedJobs\Services\QueuedJobService; +use SilverStripe\QueuedJobs\DataObjects\QueuedJobDescriptor; + /** * Represents a queued task to start the reindex job */ @@ -19,7 +30,7 @@ class SolrReindexQueuedHandler extends SolrReindexBase */ protected function getQueuedJobService() { - return singleton('QueuedJobService'); + return singleton(QueuedJobService::class); } /** @@ -33,7 +44,7 @@ class SolrReindexQueuedHandler extends SolrReindexBase $clearable = array( // Paused jobs need to be discarded QueuedJob::STATUS_PAUSED, - + // These types would be automatically started QueuedJob::STATUS_NEW, QueuedJob::STATUS_WAIT, @@ -43,27 +54,28 @@ class SolrReindexQueuedHandler extends SolrReindexBase QueuedJob::STATUS_RUN ); DB::query(sprintf( - 'UPDATE "QueuedJobDescriptor" ' + 'UPDATE "%s" ' . ' SET "JobStatus" = \'%s\'' . ' WHERE "JobStatus" IN (\'%s\')' . ' AND "Implementation" = \'%s\'', + Convert::raw2sql(DataObject::getSchema()->tableName(QueuedJobDescriptor::class)), Convert::raw2sql(QueuedJob::STATUS_CANCELLED), implode("','", Convert::raw2sql($clearable)), Convert::raw2sql($type) )); - return DB::affectedRows(); + return DB::affected_rows(); } public function triggerReindex(LoggerInterface $logger, $batchSize, $taskName, $classes = null) { // Cancel existing jobs - $queues = $this->cancelExistingJobs('SolrReindexQueuedJob'); - $groups = $this->cancelExistingJobs('SolrReindexGroupQueuedJob'); + $queues = $this->cancelExistingJobs(SolrReindexQueuedJob::class); + $groups = $this->cancelExistingJobs(SolrReindexGroupQueuedJob::class); $logger->info("Cancelled {$queues} re-index tasks and {$groups} re-index groups"); // Although this class is used as a service (singleton) it may also be instantiated // as a queuedjob - $job = Injector::inst()->create('SolrReindexQueuedJob', $batchSize, $taskName, $classes); + $job = Injector::inst()->create(SolrReindexQueuedJob::class, $batchSize, $taskName, $classes); $this ->getQueuedJobService() ->queueJob($job); @@ -77,13 +89,13 @@ class SolrReindexQueuedHandler extends SolrReindexBase ) { // Trigger another job for this group $job = Injector::inst()->create( - 'SolrReindexGroupQueuedJob', + SolrReindexGroupQueuedJob::class, get_class($indexInstance), $state, $class, $groups, $group ); $this ->getQueuedJobService() ->queueJob($job); - + $title = $job->getTitle(); $logger->info("Queued {$title}"); } diff --git a/code/solr/reindex/jobs/SolrReindexGroupQueuedJob.php b/code/solr/reindex/jobs/SolrReindexGroupQueuedJob.php index 5f32355..0425eee 100644 --- a/code/solr/reindex/jobs/SolrReindexGroupQueuedJob.php +++ b/code/solr/reindex/jobs/SolrReindexGroupQueuedJob.php @@ -1,6 +1,8 @@ $instancedir); if ($config) { diff --git a/code/solr/services/SolrService_Core.php b/code/solr/services/SolrService_Core.php index 7a73764..4f29112 100644 --- a/code/solr/services/SolrService_Core.php +++ b/code/solr/services/SolrService_Core.php @@ -1,10 +1,4 @@ remote ? "{$this->remote}/$index" : $index; } -} \ No newline at end of file +} diff --git a/code/solr/tasks/Solr_BuildTask.php b/code/solr/tasks/Solr_BuildTask.php index 9e4e3c9..7107137 100644 --- a/code/solr/tasks/Solr_BuildTask.php +++ b/code/solr/tasks/Solr_BuildTask.php @@ -25,6 +25,8 @@ class Solr_BuildTask extends BuildTask */ public function getLogger() { + //@todo left commented after a confusing merge conflict. Revisit if further testing is required + //return Injector::inst()->get('Logger'); return Injector::inst()->get(LoggerInterface::class); } @@ -43,6 +45,8 @@ class Solr_BuildTask extends BuildTask */ protected function getLoggerFactory() { + //@todo left commented after a confusing merge conflict. Revisit if further testing is required + //return Injector::inst()->get('SearchLogFactory'); return Injector::inst()->get(SearchLogFactory::class); } diff --git a/code/solr/tasks/Solr_Configure.php b/code/solr/tasks/Solr_Configure.php index 5a363d2..3973bb5 100644 --- a/code/solr/tasks/Solr_Configure.php +++ b/code/solr/tasks/Solr_Configure.php @@ -9,6 +9,7 @@ use SilverStripe\FullTextSearch\Solr\Stores\SolrConfigStore; class Solr_Configure extends Solr_BuildTask { + private static $segment = 'Solr_Configure'; protected $enabled = true; public function run($request) @@ -79,6 +80,8 @@ class Solr_Configure extends Solr_BuildTask return new SolrConfigStore_File($indexstore); } elseif ($mode == 'webdav') { return new SolrConfigStore_WebDAV($indexstore); + //@todo left commented after confusing merge conflict. Revisit if further testing is required + //} elseif (ClassInfo::exists($mode) && ClassInfo::classImplements($mode, 'SolrConfigStore')) { } elseif (ClassInfo::exists($mode) && ClassInfo::classImplements($mode, SolrConfigStore::class)) { return new $mode($indexstore); } else { @@ -86,3 +89,4 @@ class Solr_Configure extends Solr_BuildTask } } } + diff --git a/code/solr/tasks/Solr_Reindex.php b/code/solr/tasks/Solr_Reindex.php index 6671777..81af67d 100644 --- a/code/solr/tasks/Solr_Reindex.php +++ b/code/solr/tasks/Solr_Reindex.php @@ -1,6 +1,5 @@ get('SolrReindexImmediateHandler'); return Injector::inst()->get(SolrReindexHandler::class); } diff --git a/code/utils/CombinationsArrayIterator.php b/code/utils/CombinationsArrayIterator.php index 0e873a8..25c0531 100644 --- a/code/utils/CombinationsArrayIterator.php +++ b/code/utils/CombinationsArrayIterator.php @@ -1,6 +1,9 @@ createWithArgs( - 'QueuedJobLogHandler', + 'SilverStripe\FullTextSearch\Utils\Logging\QueuedJobLogHandler', array($job, Logger::INFO) ); } diff --git a/code/utils/logging/QueuedJobLogHandler.php b/code/utils/logging/QueuedJobLogHandler.php index 1d4337c..bc54bf0 100644 --- a/code/utils/logging/QueuedJobLogHandler.php +++ b/code/utils/logging/QueuedJobLogHandler.php @@ -1,12 +1,16 @@ illegalExtensions = array(); } parent::setUpOnce(); @@ -36,7 +49,7 @@ class BatchedProcessorTest extends SapphireTest { parent::setUp(); - if (!interface_exists('QueuedJob')) { + if (!interface_exists('SilverStripe\QueuedJobs\Services\QueuedJob')) { $this->skipTest = true; $this->markTestSkipped("These tests need the QueuedJobs module installed to run"); } @@ -46,17 +59,17 @@ class BatchedProcessorTest extends SapphireTest $this->markTestSkipped(get_class() . ' skipped when running with subsites'); } - SS_Datetime::set_mock_now('2015-05-07 06:00:00'); + DBDatetime::set_mock_now('2015-05-07 06:00:00'); - Config::inst()->update('SearchUpdateBatchedProcessor', 'batch_size', 5); - Config::inst()->update('SearchUpdateBatchedProcessor', 'batch_soft_cap', 0); - Config::inst()->update('SearchUpdateCommitJobProcessor', 'cooldown', 600); + Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_size', 5); + Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_soft_cap', 0); + Config::modify()->set(SearchUpdateCommitJobProcessor::class, 'cooldown', 600); - Versioned::reading_stage("Stage"); + Versioned::set_stage("Stage"); - Injector::inst()->registerService(new BatchedProcessor_QueuedJobService(), 'QueuedJobService'); + Injector::inst()->registerService(new BatchedProcessor_QueuedJobService(), QueuedJobService::class); - FullTextSearch::force_index_list('BatchedProcessorTest_Index'); + FullTextSearch::force_index_list(BatchedProcessorTest_Index::class); SearchUpdateCommitJobProcessor::$dirty_indexes = array(); SearchUpdateCommitJobProcessor::$has_run = false; @@ -87,12 +100,12 @@ class BatchedProcessorTest extends SapphireTest $object->write(); // Add to index manually $processor->addDirtyIDs( - 'BatchedProcessorTest_Object', + BatchedProcessorTest_Object::class, array(array( 'id' => $id, - 'state' => array('SearchVariantVersioned' => 'Stage') + 'state' => array(SearchVariantVersioned::class => 'Stage') )), - 'BatchedProcessorTest_Index' + BatchedProcessorTest_Index::class ); } $processor->batchData(); @@ -104,7 +117,7 @@ class BatchedProcessorTest extends SapphireTest */ public function testBatching() { - $index = singleton('BatchedProcessorTest_Index'); + $index = singleton(BatchedProcessorTest_Index::class); $index->reset(); $processor = $this->generateDirtyIds(); @@ -132,10 +145,10 @@ class BatchedProcessorTest extends SapphireTest // Check any additional queued jobs $processor->afterComplete(); - $service = singleton('QueuedJobService'); + $service = singleton(QueuedJobService::class); $jobs = $service->getJobs(); $this->assertEquals(1, count($jobs)); - $this->assertInstanceOf('SearchUpdateCommitJobProcessor', $jobs[0]['job']); + $this->assertInstanceOf(SearchUpdateCommitJobProcessor::class, $jobs[0]['job']); } /** @@ -143,7 +156,7 @@ class BatchedProcessorTest extends SapphireTest */ public function testMultipleCommits() { - $index = singleton('BatchedProcessorTest_Index'); + $index = singleton(BatchedProcessorTest_Index::class); $index->reset(); // Test that running a commit immediately after submitting to the indexes @@ -190,25 +203,25 @@ class BatchedProcessorTest extends SapphireTest */ public function testSoftCap() { - $index = singleton('BatchedProcessorTest_Index'); + $index = singleton(BatchedProcessorTest_Index::class); $index->reset(); $processor = $this->generateDirtyIds(); // Test that increasing the soft cap to 2 will reduce the number of batches - Config::inst()->update('SearchUpdateBatchedProcessor', 'batch_soft_cap', 2); + Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_soft_cap', 2); $processor->batchData(); $data = $processor->getJobData(); //Debug::dump($data);die; $this->assertEquals(8, $data->totalSteps); // A soft cap of 1 should not fit in the hanging two items - Config::inst()->update('SearchUpdateBatchedProcessor', 'batch_soft_cap', 1); + Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_soft_cap', 1); $processor->batchData(); $data = $processor->getJobData(); $this->assertEquals(9, $data->totalSteps); // Extra large soft cap should fit both items - Config::inst()->update('SearchUpdateBatchedProcessor', 'batch_soft_cap', 4); + Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_soft_cap', 4); $processor->batchData(); $data = $processor->getJobData(); $this->assertEquals(8, $data->totalSteps); diff --git a/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php b/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php index 7116af1..c22ebf1 100644 --- a/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php +++ b/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php @@ -9,7 +9,7 @@ class BatchedProcessorTest_Index extends SearchIndex_Recording implements TestOn { public function init() { - $this->addClass('BatchedProcessorTest_Object'); + $this->addClass(BatchedProcessorTest_Object::class); $this->addFilterField('TestText'); } } diff --git a/tests/BatchedProcessorTest/BatchedProcessorTest_Object.php b/tests/BatchedProcessorTest/BatchedProcessorTest_Object.php index b596a3a..3683208 100644 --- a/tests/BatchedProcessorTest/BatchedProcessorTest_Object.php +++ b/tests/BatchedProcessorTest/BatchedProcessorTest_Object.php @@ -7,6 +7,8 @@ use SilverStripe\Dev\TestOnly; class BatchedProcessorTest_Object extends SiteTree implements TestOnly { + private static $table_name = 'BatchedProcessorTest_Object'; + private static $db = array( 'TestText' => 'Varchar' ); diff --git a/tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php b/tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php index 1cf5253..572347c 100644 --- a/tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php +++ b/tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php @@ -2,6 +2,8 @@ namespace SilverStripe\FullTextSearch\Tests\BatchedProcessorTest; +use SilverStripe\QueuedJobs\Services\QueuedJob; + class BatchedProcessor_QueuedJobService { protected $jobs = array(); diff --git a/tests/SearchUpdaterTest.php b/tests/SearchUpdaterTest.php index ee2df21..d62f33a 100644 --- a/tests/SearchUpdaterTest.php +++ b/tests/SearchUpdaterTest.php @@ -1,78 +1,16 @@ 'Varchar', - 'Field2' => 'Varchar', - 'MyDate' => 'Date', - ); - - private static $has_one = array( - 'HasOneObject' => 'SearchUpdaterTest_HasOne' - ); - - private static $has_many = array( - 'HasManyObjects' => 'SearchUpdaterTest_HasMany' - ); - - private static $many_many = array( - 'ManyManyObjects' => 'SearchUpdaterTest_ManyMany' - ); -} - -class SearchUpdaterTest_HasOne extends DataObject -{ - private static $db = array( - 'Field1' => 'Varchar', - 'Field2' => 'Varchar' - ); - - private static $has_many = array( - 'HasManyContainers' => 'SearchUpdaterTest_Container' - ); -} - -class SearchUpdaterTest_HasMany extends DataObject -{ - private static $db = array( - 'Field1' => 'Varchar', - 'Field2' => 'Varchar' - ); - - private static $has_one = array( - 'HasManyContainer' => 'SearchUpdaterTest_Container' - ); -} - -class SearchUpdaterTest_ManyMany extends DataObject -{ - private static $db = array( - 'Field1' => 'Varchar', - 'Field2' => 'Varchar' - ); - - private static $belongs_many_many = array( - 'ManyManyContainer' => 'SearchUpdaterTest_Container' - ); -} - -class SearchUpdaterTest_Index extends SearchIndex_Recording -{ - public function init() - { - $this->addClass('SearchUpdaterTest_Container'); - - $this->addFilterField('Field1'); - $this->addFilterField('HasOneObject.Field1'); - $this->addFilterField('HasManyObjects.Field1'); - } -} +use SilverStripe\Core\Config\Config; +use SilverStripe\Core\Injector\Injector; +use SilverStripe\FullTextSearch\Search\FullTextSearch; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasOne; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasMany; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Index; +use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateProcessor; +use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateImmediateProcessor; class SearchUpdaterTest extends SapphireTest { @@ -85,15 +23,15 @@ class SearchUpdaterTest extends SapphireTest parent::setUp(); if (self::$index === null) { - self::$index = singleton(get_class($this).'_Index'); + self::$index = SearchUpdaterTest_Index::singleton(); } else { self::$index->reset(); } SearchUpdater::bind_manipulation_capture(); - Config::inst()->update('Injector', 'SearchUpdateProcessor', array( - 'class' => 'SearchUpdateImmediateProcessor' + Config::modify()->set(Injector::class, SearchUpdateProcessor::class, array( + 'class' => SearchUpdateImmediateProcessor::class )); FullTextSearch::force_index_list(self::$index); @@ -132,7 +70,6 @@ class SearchUpdaterTest extends SapphireTest // Check the default "writing a document updates the document" SearchUpdater::flush_dirty_indexes(); - $added = self::$index->getAdded(array('ID')); // Some databases don't output $added in a consistent order; that's okay usort($added, function ($a, $b) {return $a['ID']-$b['ID']; }); @@ -152,6 +89,7 @@ class SearchUpdaterTest extends SapphireTest SearchUpdater::flush_dirty_indexes(); $added = self::$index->getAdded(array('ID')); + // Some databases don't output $added in a consistent order; that's okay usort($added, function ($a, $b) {return $a['ID']-$b['ID']; }); diff --git a/tests/SearchUpdaterTest/SearchUpdaterTest_Container.php b/tests/SearchUpdaterTest/SearchUpdaterTest_Container.php new file mode 100644 index 0000000..a374a0a --- /dev/null +++ b/tests/SearchUpdaterTest/SearchUpdaterTest_Container.php @@ -0,0 +1,31 @@ + 'Varchar', + 'Field2' => 'Varchar', + 'MyDate' => 'Date', + ); + + private static $table_name = 'SearchUpdaterTest_Container'; + + private static $has_one = array( + 'HasOneObject' => SearchUpdaterTest_HasOne::class + ); + + private static $has_many = array( + 'HasManyObjects' => SearchUpdaterTest_HasMany::class + ); + + private static $many_many = array( + 'ManyManyObjects' => SearchUpdaterTest_ManyMany::class + ); +} diff --git a/tests/SearchUpdaterTest/SearchUpdaterTest_HasMany.php b/tests/SearchUpdaterTest/SearchUpdaterTest_HasMany.php new file mode 100644 index 0000000..f008582 --- /dev/null +++ b/tests/SearchUpdaterTest/SearchUpdaterTest_HasMany.php @@ -0,0 +1,20 @@ + 'Varchar', + 'Field2' => 'Varchar' + ); + + private static $table_name = 'SearchUpdaterTest_HasMany'; + + private static $has_one = array( + 'HasManyContainer' => SearchUpdaterTest_Container::class + ); +} diff --git a/tests/SearchUpdaterTest/SearchUpdaterTest_HasOne.php b/tests/SearchUpdaterTest/SearchUpdaterTest_HasOne.php new file mode 100644 index 0000000..cc81587 --- /dev/null +++ b/tests/SearchUpdaterTest/SearchUpdaterTest_HasOne.php @@ -0,0 +1,20 @@ + 'Varchar', + 'Field2' => 'Varchar' + ); + + private static $table_name = 'SearchUpdaterTest_HasOne'; + + private static $has_many = array( + 'HasManyContainers' => SearchUpdaterTest_Container::class + ); +} diff --git a/tests/SearchUpdaterTest/SearchUpdaterTest_Index.php b/tests/SearchUpdaterTest/SearchUpdaterTest_Index.php new file mode 100644 index 0000000..5a027c5 --- /dev/null +++ b/tests/SearchUpdaterTest/SearchUpdaterTest_Index.php @@ -0,0 +1,17 @@ +addClass(SearchUpdaterTest_Container::class); + + $this->addFilterField('Field1'); + $this->addFilterField('HasOneObject.Field1'); + $this->addFilterField('HasManyObjects.Field1'); + } +} diff --git a/tests/SearchUpdaterTest/SearchUpdaterTest_ManyMany.php b/tests/SearchUpdaterTest/SearchUpdaterTest_ManyMany.php new file mode 100644 index 0000000..191fe6f --- /dev/null +++ b/tests/SearchUpdaterTest/SearchUpdaterTest_ManyMany.php @@ -0,0 +1,20 @@ + 'Varchar', + 'Field2' => 'Varchar' + ); + + private static $table_name = 'SearchUpdaterTest_ManyMany'; + + private static $belongs_many_many = array( + 'ManyManyContainer' => SearchUpdaterTest_Container::class + ); +} diff --git a/tests/SearchVariantSiteTreeSubsitesPolyhomeTest.php b/tests/SearchVariantSiteTreeSubsitesPolyhomeTest.php index 38b5753..892619f 100644 --- a/tests/SearchVariantSiteTreeSubsitesPolyhomeTest.php +++ b/tests/SearchVariantSiteTreeSubsitesPolyhomeTest.php @@ -3,23 +3,10 @@ use SilverStripe\CMS\Model\SiteTree; use SilverStripe\FullTextSearch\Search\Indexes\SearchIndex_Recording; use SilverStripe\Dev\SapphireTest; +use SilverStripe\FullTextSearch\Tests\SearchVariantSiteTreeSubsitesPolyhomeTest\SearchVariantSiteTreeSubsitesPolyhomeTest_Index; +use SilverStripe\FullTextSearch\Tests\SearchVariantSiteTreeSubsitesPolyhomeTest\SearchVariantSiteTreeSubsitesPolyhomeTest_Item; -class SearchVariantSiteTreeSubsitesPolyhomeTest_Item extends SiteTree -{ - // TODO: Currently theres a failure if you addClass a non-table class - private static $db = array( - 'TestText' => 'Varchar' - ); -} -class SearchVariantSiteTreeSubsitesPolyhomeTest_Index extends SearchIndex_Recording -{ - public function init() - { - $this->addClass('SearchVariantSiteTreeSubsitesPolyhomeTest_Item'); - $this->addFilterField('TestText'); - } -} class SearchVariantSiteTreeSubsitesPolyhomeTest extends SapphireTest { diff --git a/tests/SearchVariantSiteTreeSubsitesPolyhomeTest/SearchVariantSiteTreeSubsitesPolyhomeTest_Index.php b/tests/SearchVariantSiteTreeSubsitesPolyhomeTest/SearchVariantSiteTreeSubsitesPolyhomeTest_Index.php new file mode 100644 index 0000000..4991e6c --- /dev/null +++ b/tests/SearchVariantSiteTreeSubsitesPolyhomeTest/SearchVariantSiteTreeSubsitesPolyhomeTest_Index.php @@ -0,0 +1,14 @@ +addClass(SearchVariantSiteTreeSubsitesPolyhomeTest_Item::class); + $this->addFilterField('TestText'); + } +} diff --git a/tests/SearchVariantSiteTreeSubsitesPolyhomeTest/SearchVariantSiteTreeSubsitesPolyhomeTest_Item.php b/tests/SearchVariantSiteTreeSubsitesPolyhomeTest/SearchVariantSiteTreeSubsitesPolyhomeTest_Item.php new file mode 100644 index 0000000..f037d77 --- /dev/null +++ b/tests/SearchVariantSiteTreeSubsitesPolyhomeTest/SearchVariantSiteTreeSubsitesPolyhomeTest_Item.php @@ -0,0 +1,15 @@ + 'Varchar' + ); +} diff --git a/tests/SearchVariantVersionedTest.php b/tests/SearchVariantVersionedTest.php index 1b73373..7ef3a1d 100644 --- a/tests/SearchVariantVersionedTest.php +++ b/tests/SearchVariantVersionedTest.php @@ -1,9 +1,15 @@ markTestSkipped('The versioned decorator is not installed'); - } - if (self::$index === null) { - self::$index = singleton('SearchVariantVersionedTest_Index'); + self::$index = singleton(SearchVariantVersionedTest_Index::class); } SearchUpdater::bind_manipulation_capture(); - Config::inst()->update('Injector', 'SearchUpdateProcessor', array( - 'class' => 'SearchUpdateImmediateProcessor' + Config::modify()->set('Injector', SearchUpdateProcessor::class, array( + 'class' => SearchUpdateImmediateProcessor::class )); FullTextSearch::force_index_list(self::$index); @@ -47,20 +48,21 @@ class SearchVariantVersionedTest extends SapphireTest $item->write(); SearchUpdater::flush_dirty_indexes(); - $this->assertEquals(self::$index->getAdded(array('ID', '_versionedstage')), array( + $this->assertEquals(array( array('ID' => $item->ID, '_versionedstage' => 'Stage') - )); + ), self::$index->getAdded(array('ID', '_versionedstage'))); // Check that publish updates Live self::$index->reset(); - $item->publish("Stage", "Live"); + $item->copyVersionToStage('Stage', 'Live'); SearchUpdater::flush_dirty_indexes(); - $this->assertEquals(self::$index->getAdded(array('ID', '_versionedstage')), array( + $this->assertEquals(array( + array('ID' => $item->ID, '_versionedstage' => 'Stage'), array('ID' => $item->ID, '_versionedstage' => 'Live') - )); + ), self::$index->getAdded(array('ID', '_versionedstage'))); // Just update a SiteTree field, and check it updates Stage @@ -81,48 +83,23 @@ class SearchVariantVersionedTest extends SapphireTest public function testExcludeVariantState() { - $index = singleton('SearchVariantVersionedTest_IndexNoStage'); + $index = singleton(SearchVariantVersionedTest_IndexNoStage::class); FullTextSearch::force_index_list($index); // Check that write doesn't update stage $item = new SearchVariantVersionedTest_Item(array('TestText' => 'Foo')); $item->write(); SearchUpdater::flush_dirty_indexes(); - $this->assertEquals($index->getAdded(array('ID', '_versionedstage')), array()); + $this->assertEquals(array(), $index->getAdded(array('ID', '_versionedstage'))); // Check that publish updates Live $index->reset(); - $item->publish("Stage", "Live"); + + $item->copyVersionToStage('Stage', 'Live'); + SearchUpdater::flush_dirty_indexes(); - $this->assertEquals($index->getAdded(array('ID', '_versionedstage')), array( + $this->assertEquals(array( array('ID' => $item->ID, '_versionedstage' => 'Live') - )); - } -} - -class SearchVariantVersionedTest_Item extends SiteTree implements TestOnly -{ - // TODO: Currently theres a failure if you addClass a non-table class - private static $db = array( - 'TestText' => 'Varchar' - ); -} - -class SearchVariantVersionedTest_Index extends SearchIndex_Recording -{ - public function init() - { - $this->addClass('SearchVariantVersionedTest_Item'); - $this->addFilterField('TestText'); - } -} - -class SearchVariantVersionedTest_IndexNoStage extends SearchIndex_Recording -{ - public function init() - { - $this->addClass('SearchVariantVersionedTest_Item'); - $this->addFilterField('TestText'); - $this->excludeVariantState(array('SearchVariantVersioned' => 'Stage')); + ), $index->getAdded(array('ID', '_versionedstage'))); } } diff --git a/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_Index.php b/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_Index.php new file mode 100644 index 0000000..eba01ec --- /dev/null +++ b/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_Index.php @@ -0,0 +1,14 @@ +addClass(SearchVariantVersionedTest_Item::class); + $this->addFilterField('TestText'); + } +} diff --git a/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_IndexNoStage.php b/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_IndexNoStage.php new file mode 100644 index 0000000..8b66288 --- /dev/null +++ b/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_IndexNoStage.php @@ -0,0 +1,16 @@ +addClass(SearchVariantVersionedTest_Item::class); + $this->addFilterField('TestText'); + $this->excludeVariantState(array(SearchVariantVersioned::class => 'Stage')); + } +} diff --git a/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_Item.php b/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_Item.php new file mode 100644 index 0000000..d6538de --- /dev/null +++ b/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_Item.php @@ -0,0 +1,16 @@ + 'Varchar' + ); +} diff --git a/tests/SolrIndexSubsitesTest.php b/tests/SolrIndexSubsitesTest.php index 3534104..9bd7bd1 100644 --- a/tests/SolrIndexSubsitesTest.php +++ b/tests/SolrIndexSubsitesTest.php @@ -3,8 +3,8 @@ use SilverStripe\Dev\SapphireTest; use SilverStripe\FullTextSearch\Tests\SolrIndexSubsitesTest\SolrIndexSubsitesTest_Index; -if (class_exists('Phockito')) { - Phockito::include_hamcrest(false); +if (class_exists('\Phockito')) { + \Phockito::include_hamcrest(false); } /** @@ -26,15 +26,16 @@ class SolrIndexSubsitesTest extends SapphireTest { // Prevent parent::setUp() crashing on db build if (!class_exists('Subsite')) { $this->skipTest = true; + $this->markTestSkipped("These tests need the Subsite module installed to run"); } parent::setUp(); $this->server = $_SERVER; - if (!class_exists('Phockito')) { + if (!class_exists('\Phockito')) { $this->skipTest = true; - $this->markTestSkipped("These tests need the Phockito module installed to run"); + $this->markTestSkipped("These tests need the \Phockito module installed to run"); return; } @@ -51,7 +52,7 @@ class SolrIndexSubsitesTest extends SapphireTest { SearchUpdater::bind_manipulation_capture(); - Config::inst()->update('Injector', 'SearchUpdateProcessor', array( + Config::modify()->set('Injector', 'SearchUpdateProcessor', array( 'class' => 'SearchUpdateImmediateProcessor' )); @@ -70,7 +71,7 @@ class SolrIndexSubsitesTest extends SapphireTest { protected function getServiceMock() { - return Phockito::mock('Solr4Service'); + return \Phockito::mock('Solr4Service'); } /** @@ -82,11 +83,11 @@ class SolrIndexSubsitesTest extends SapphireTest { protected function getExpectedDocumentId($object, $subsiteID, $stage = null) { $id = $object->ID; - $class = ClassInfo::baseDataClass($object); + $class = DataObject::getSchema()->baseDataClass($object); $variants = array(); // Check subsite - if(class_exists('Subsite') && $object->hasOne('Subsite')) { + if(class_exists('Subsite') && DataObject::getSchema()->hasOneComponent($object->getClassName(), 'Subsite')) { $variants[] = '"SearchVariantSubsites":"' . $subsiteID. '"'; } @@ -108,7 +109,7 @@ class SolrIndexSubsitesTest extends SapphireTest { // Add records to first subsite Versioned::reading_stage('Stage'); $_SERVER['HTTP_HOST'] = 'www.subsite1.com'; - Phockito::reset($serviceMock); + \Phockito::reset($serviceMock); $file = new File(); $file->Title = 'My File'; $file->SubsiteID = $subsite1->ID; @@ -131,8 +132,8 @@ class SolrIndexSubsitesTest extends SapphireTest { 'File_Title' => 'My File', '_subsite' => $subsite1->ID )); - Phockito::verify($serviceMock)->addDocument($doc1); - Phockito::verify($serviceMock)->addDocument($doc2); + \Phockito::verify($serviceMock)->addDocument($doc1); + \Phockito::verify($serviceMock)->addDocument($doc2); } diff --git a/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php b/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php index 97e9dfb..620f632 100644 --- a/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php +++ b/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php @@ -3,13 +3,15 @@ namespace SilverStripe\FullTextSearch\Tests\SolrIndexSubsitesTest; use SilverStripe\FullTextSearch\Solr\SolrIndex; +use SilverStripe\Assets\File; +use SilverStripe\CMS\Model\SiteTree; class SolrIndexSubsitesTest_Index extends SolrIndex { public function init() { - $this->addClass('File'); - $this->addClass('SiteTree'); + $this->addClass(File::class); + $this->addClass(SiteTree::class); $this->addAllFulltextFields(); } } diff --git a/tests/SolrIndexTest.php b/tests/SolrIndexTest.php index 0a6b82f..b0ee54e 100644 --- a/tests/SolrIndexTest.php +++ b/tests/SolrIndexTest.php @@ -4,60 +4,50 @@ use SilverStripe\Dev\SapphireTest; use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_FakeIndex; use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_FakeIndex2; use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_BoostedIndex; +use SilverStripe\FullTextSearch\Solr\Services\Solr3Service; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasOne; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasMany; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_ManyMany; +use SilverStripe\Core\Config\Config; +use SilverStripe\Control\Director; +use SilverStripe\FullTextSearch\Search\Queries\SearchQuery; class SolrIndexTest extends SapphireTest { - public function setUpOnce() - { - parent::setUpOnce(); - - if (class_exists('Phockito')) { - Phockito::include_hamcrest(false); - } - } - - public function setUp() - { - parent::setUp(); - - if (!class_exists('Phockito')) { - $this->markTestSkipped("These tests need the Phockito module installed to run"); - $this->skipTest = true; - } - } - public function testFieldDataHasOne() { $index = new SolrIndexTest_FakeIndex(); $data = $index->fieldData('HasOneObject.Field1'); - $data = $data['SearchUpdaterTest_Container_HasOneObject_Field1']; - $this->assertEquals('SearchUpdaterTest_Container', $data['origin']); - $this->assertEquals('SearchUpdaterTest_Container', $data['base']); - $this->assertEquals('SearchUpdaterTest_HasOne', $data['class']); + $data = $data[SearchUpdaterTest_Container::class . '_HasOneObject_Field1']; + + $this->assertEquals(SearchUpdaterTest_Container::class, $data['origin']); + $this->assertEquals(SearchUpdaterTest_Container::class, $data['base']); + $this->assertEquals(SearchUpdaterTest_HasOne::class, $data['class']); } public function testFieldDataHasMany() { $index = new SolrIndexTest_FakeIndex(); $data = $index->fieldData('HasManyObjects.Field1'); - $data = $data['SearchUpdaterTest_Container_HasManyObjects_Field1']; + $data = $data[SearchUpdaterTest_Container::class . '_HasManyObjects_Field1']; - $this->assertEquals('SearchUpdaterTest_Container', $data['origin']); - $this->assertEquals('SearchUpdaterTest_Container', $data['base']); - $this->assertEquals('SearchUpdaterTest_HasMany', $data['class']); + $this->assertEquals(SearchUpdaterTest_Container::class, $data['origin']); + $this->assertEquals(SearchUpdaterTest_Container::class, $data['base']); + $this->assertEquals(SearchUpdaterTest_HasMany::class, $data['class']); } public function testFieldDataManyMany() { $index = new SolrIndexTest_FakeIndex(); $data = $index->fieldData('ManyManyObjects.Field1'); - $data = $data['SearchUpdaterTest_Container_ManyManyObjects_Field1']; + $data = $data[SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1']; - $this->assertEquals('SearchUpdaterTest_Container', $data['origin']); - $this->assertEquals('SearchUpdaterTest_Container', $data['base']); - $this->assertEquals('SearchUpdaterTest_ManyMany', $data['class']); + $this->assertEquals(SearchUpdaterTest_Container::class, $data['origin']); + $this->assertEquals(SearchUpdaterTest_Container::class, $data['base']); + $this->assertEquals(SearchUpdaterTest_ManyMany::class, $data['class']); } /** @@ -65,15 +55,19 @@ class SolrIndexTest extends SapphireTest */ public function testBoostedQuery() { - $serviceMock = $this->getServiceMock(); - Phockito::when($serviceMock) - ->search( - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything() - )->return($this->getFakeRawSolrResponse()); + /** @var Solr3Service|PHPUnit_Framework_MockObject_MockObject $serviceMock */ + $serviceMock = $this->getMockBuilder(Solr3Service::class) + ->setMethods(['search']) + ->getMock(); + + $serviceMock->expects($this->once()) + ->method('search') + ->with($this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'), + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything() + )->willReturn($this->getFakeRawSolrResponse()); $index = new SolrIndexTest_FakeIndex(); $index->setService($serviceMock); @@ -85,15 +79,6 @@ class SolrIndexTest extends SapphireTest array('Field1' => 1.5, 'HasOneObject_Field1' => 3) ); $index->search($query); - - Phockito::verify($serviceMock) - ->search( - '+(Field1:term^1.5 OR HasOneObject_Field1:term^3)', - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything() - ); } /** @@ -101,15 +86,20 @@ class SolrIndexTest extends SapphireTest */ public function testBoostedField() { - $serviceMock = $this->getServiceMock(); - Phockito::when($serviceMock) - ->search( - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything() - )->return($this->getFakeRawSolrResponse()); + /** @var Solr3Service|PHPUnit_Framework_MockObject_MockObject $serviceMock */ + $serviceMock = $this->getMockBuilder(Solr3Service::class) + ->setMethods(['search']) + ->getMock(); + + $serviceMock->expects($this->once()) + ->method('search') + ->with($this->equalTo('+term'), + $this->anything(), + $this->anything(), + $this->equalTo(['qf' => SearchUpdaterTest_Container::class . '_Field1^1.5 ' . SearchUpdaterTest_Container::class . '_Field2^2.1 _text', + 'fq' => '+(_versionedstage:"" (*:* -_versionedstage:[* TO *]))']), + $this->anything() + )->willReturn($this->getFakeRawSolrResponse()); $index = new SolrIndexTest_BoostedIndex(); $index->setService($serviceMock); @@ -117,32 +107,34 @@ class SolrIndexTest extends SapphireTest $query = new SearchQuery(); $query->search('term'); $index->search($query); - - // Ensure matcher contains correct boost in 'qf' parameter - $matcher = new Hamcrest_Array_IsArrayContainingKeyValuePair( - new Hamcrest_Core_IsEqual('qf'), - new Hamcrest_Core_IsEqual('SearchUpdaterTest_Container_Field1^1.5 SearchUpdaterTest_Container_Field2^2.1 _text') - ); - Phockito::verify($serviceMock) - ->search( - '+term', - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - $matcher, - \Hamcrest_Matchers::anything() - ); } public function testHighlightQueryOnBoost() { - $serviceMock = $this->getServiceMock(); - Phockito::when($serviceMock)->search( - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything() - )->return($this->getFakeRawSolrResponse()); + /** @var SilverStripe\FullTextSearch\Solr\Services\Solr3Service|ObjectProphecy $serviceMock */ + $serviceMock = $this->getMockBuilder(Solr3Service::class) + ->setMethods(['search']) + ->getMock(); + + $serviceMock->expects($this->exactly(2)) + ->method('search') + ->withConsecutive([ + $this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'), + $this->anything(), + $this->anything(), + $this->logicalNot( + $this->arrayHasKey('hl.q') + ), + $this->anything() + ], + [ + $this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'), + $this->anything(), + $this->anything(), + $this->arrayHasKey('hl.q'), + $this->anything() + ] + )->willReturn($this->getFakeRawSolrResponse()); $index = new SolrIndexTest_FakeIndex(); $index->setService($serviceMock); @@ -155,14 +147,6 @@ class SolrIndexTest extends SapphireTest array('Field1' => 1.5, 'HasOneObject_Field1' => 3) ); $index->search($query); - Phockito::verify( - $serviceMock)->search( - '+(Field1:term^1.5 OR HasOneObject_Field1:term^3)', - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::not(\Hamcrest_Matchers::hasKeyInArray('hl.q')), - \Hamcrest_Matchers::anything() - ); // Search with highlighting $query = new SearchQuery(); @@ -172,19 +156,12 @@ class SolrIndexTest extends SapphireTest array('Field1' => 1.5, 'HasOneObject_Field1' => 3) ); $index->search($query, -1, -1, array('hl' => true)); - Phockito::verify( - $serviceMock)->search( - '+(Field1:term^1.5 OR HasOneObject_Field1:term^3)', - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::hasKeyInArray('hl.q'), - \Hamcrest_Matchers::anything() - ); } public function testIndexExcludesNullValues() { - $serviceMock = $this->getServiceMock(); + /** @var Solr3Service|ObjectProphecy $serviceMock */ + $serviceMock = $this->createMock(Solr3Service::class); $index = new SolrIndexTest_FakeIndex(); $index->setService($serviceMock); $obj = new SearchUpdaterTest_Container(); @@ -193,36 +170,36 @@ class SolrIndexTest extends SapphireTest $obj->Field2 = null; $obj->MyDate = null; $docs = $index->add($obj); - $value = $docs[0]->getField('SearchUpdaterTest_Container_Field1'); + $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_Field1'); $this->assertEquals('Field1 val', $value['value'], 'Writes non-NULL string fields'); - $value = $docs[0]->getField('SearchUpdaterTest_Container_Field2'); + $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_Field2'); $this->assertFalse($value, 'Ignores string fields if they are NULL'); - $value = $docs[0]->getField('SearchUpdaterTest_Container_MyDate'); + $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_MyDate'); $this->assertFalse($value, 'Ignores date fields if they are NULL'); $obj->MyDate = '2010-12-30'; $docs = $index->add($obj); - $value = $docs[0]->getField('SearchUpdaterTest_Container_MyDate'); + $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_MyDate'); $this->assertEquals('2010-12-30T00:00:00Z', $value['value'], 'Writes non-NULL dates'); } public function testAddFieldExtraOptions() { - Config::inst()->nest(); - Config::inst()->update('Director', 'environment_type', 'live'); // dev mode sets stored=true for everything + Config::nest(); + Director::set_environment_type('live'); $index = new SolrIndexTest_FakeIndex(); $defs = simplexml_load_string('' . $index->getFieldDefinitions() . ''); - $defField1 = $defs->xpath('field[@name="SearchUpdaterTest_Container_Field1"]'); + $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]'); $this->assertEquals((string)$defField1[0]['stored'], 'false'); $index->addFilterField('Field1', null, array('stored' => 'true')); $defs = simplexml_load_string('' . $index->getFieldDefinitions() . ''); - $defField1 = $defs->xpath('field[@name="SearchUpdaterTest_Container_Field1"]'); + $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]'); $this->assertEquals((string)$defField1[0]['stored'], 'true'); - Config::inst()->unnest(); + Config::unnest(); } public function testAddAnalyzer() @@ -230,13 +207,13 @@ class SolrIndexTest extends SapphireTest $index = new SolrIndexTest_FakeIndex(); $defs = simplexml_load_string('' . $index->getFieldDefinitions() . ''); - $defField1 = $defs->xpath('field[@name="SearchUpdaterTest_Container_Field1"]'); + $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]'); $analyzers = $defField1[0]->analyzer; $this->assertFalse((bool)$analyzers); $index->addAnalyzer('Field1', 'charFilter', array('class' => 'solr.HTMLStripCharFilterFactory')); $defs = simplexml_load_string('' . $index->getFieldDefinitions() . ''); - $defField1 = $defs->xpath('field[@name="SearchUpdaterTest_Container_Field1"]'); + $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]'); $analyzers = $defField1[0]->analyzer; $this->assertTrue((bool)$analyzers); $this->assertEquals('solr.HTMLStripCharFilterFactory', $analyzers[0]->charFilter[0]['class']); @@ -265,11 +242,11 @@ class SolrIndexTest extends SapphireTest $index->addFulltextField('Field2'); $schema = $index->getFieldDefinitions(); $this->assertContains( - "assertContains( - "addStoredField('Field2'); $schema2 = $index2->getFieldDefinitions(); $this->assertContains( - "assertContains( - "_sendRawPost()->return($this->getFakeRawSolrResponse()); - - return $serviceSpy; - } - protected function getFakeRawSolrResponse() { - return new Apache_Solr_Response( - new Apache_Solr_HttpTransport_Response( + return new \Apache_Solr_Response( + new \Apache_Solr_HttpTransport_Response( null, null, '{}' diff --git a/tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php b/tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php index 65dae12..79027e7 100644 --- a/tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php +++ b/tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php @@ -3,6 +3,7 @@ namespace SilverStripe\FullTextSearch\Tests\SolrIndexTest; use SilverStripe\FullTextSearch\Solr\SolrIndex; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container; class SolrIndexTest_BoostedIndex extends SolrIndex { @@ -14,9 +15,9 @@ class SolrIndexTest_BoostedIndex extends SolrIndex public function init() { - $this->addClass('SearchUpdaterTest_Container'); + $this->addClass(SearchUpdaterTest_Container::class); $this->addAllFulltextFields(); - $this->setFieldBoosting('SearchUpdaterTest_Container_Field1', 1.5); + $this->setFieldBoosting(SearchUpdaterTest_Container::class . '_Field1', 1.5); $this->addBoostedField('Field2', null, array(), 2.1); } } diff --git a/tests/SolrIndexTest/SolrIndexTest_FakeIndex.php b/tests/SolrIndexTest/SolrIndexTest_FakeIndex.php index b04e6ce..b3da07f 100644 --- a/tests/SolrIndexTest/SolrIndexTest_FakeIndex.php +++ b/tests/SolrIndexTest/SolrIndexTest_FakeIndex.php @@ -3,12 +3,13 @@ namespace SilverStripe\FullTextSearch\Tests\SolrIndexTest; use SilverStripe\FullTextSearch\Solr\SolrIndex; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container; class SolrIndexTest_FakeIndex extends SolrIndex { public function init() { - $this->addClass('SearchUpdaterTest_Container'); + $this->addClass(SearchUpdaterTest_Container::class); $this->addFilterField('Field1'); $this->addFilterField('MyDate', 'Date'); diff --git a/tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php b/tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php index a9b58ac..c209739 100644 --- a/tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php +++ b/tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php @@ -3,6 +3,7 @@ namespace SilverStripe\FullTextSearch\Tests\SolrIndexTest; use SilverStripe\FullTextSearch\Solr\SolrIndex; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container; class SolrIndexTest_FakeIndex2 extends SolrIndex { @@ -14,7 +15,7 @@ class SolrIndexTest_FakeIndex2 extends SolrIndex public function init() { - $this->addClass('SearchUpdaterTest_Container'); + $this->addClass(SearchUpdaterTest_Container::class); $this->addFilterField('MyDate', 'Date'); $this->addFilterField('HasOneObject.Field1'); $this->addFilterField('HasManyObjects.Field1'); diff --git a/tests/SolrIndexVersionedTest.php b/tests/SolrIndexVersionedTest.php index 4533576..70b83a7 100644 --- a/tests/SolrIndexVersionedTest.php +++ b/tests/SolrIndexVersionedTest.php @@ -1,58 +1,51 @@ skipTest = true; - $this->markTestSkipped("These tests need the Phockito module installed to run"); - return; - } - - // Check versioned available - if (!class_exists('Versioned')) { - $this->skipTest = true; - $this->markTestSkipped('The versioned decorator is not installed'); - return; - } - if (self::$index === null) { - self::$index = singleton('SolrVersionedTest_Index'); + self::$index = singleton(SolrVersionedTest_Index::class); } SearchUpdater::bind_manipulation_capture(); - Config::inst()->update('Injector', 'SearchUpdateProcessor', array( - 'class' => 'SearchUpdateImmediateProcessor' + Config::modify()->set('Injector', SearchUpdateProcessor::class, array( + 'class' => SearchUpdateImmediateProcessor::class )); FullTextSearch::force_index_list(self::$index); SearchUpdater::clear_dirty_indexes(); $this->oldMode = Versioned::get_reading_mode(); - Versioned::reading_stage('Stage'); + Versioned::set_stage('Stage'); } public function tearDown() @@ -61,9 +54,17 @@ class SolrIndexVersionedTest extends SapphireTest parent::tearDown(); } - protected function getServiceMock() + protected function getServiceMock($setMethods = array()) { - return Phockito::mock('Solr3Service'); + // Setup mock + /** @var SilverStripe\FullTextSearch\Solr\Services\Solr3Service|ObjectProphecy $serviceMock */ + $serviceMock = $this->getMockBuilder(Solr3Service::class) + ->setMethods($setMethods) + ->getMock(); + + self::$index->setService($serviceMock); + + return $serviceMock; } /** @@ -74,104 +75,164 @@ class SolrIndexVersionedTest extends SapphireTest protected function getExpectedDocumentId($object, $stage) { $id = $object->ID; - $class = ClassInfo::baseDataClass($object); + $class = DataObject::getSchema()->baseDataClass($object); // Prevent subsites from breaking tests + // TODO: Subsites currently isn't migrated. This needs to be fixed when subsites is fixed. $subsites = ''; - if(class_exists('Subsite') && $object->hasOne('Subsite')) { + if(class_exists('Subsite') && DataObject::getSchema()->hasOneComponent($object->getClassName(), 'Subsite')) { $subsites = '"SearchVariantSubsites":"0",'; } - return $id.'-'.$class.'-{'.$subsites.'"SearchVariantVersioned":"'.$stage.'"}'; + return $id.'-'.$class.'-{'.$subsites. json_encode(SearchVariantVersioned::class) . ':"'.$stage.'"}'; + } + + /** + * @param string $class + * @param DataObject $object Item being added + * @param string $value Value for class + * @param string $stage Stage updated + * @return Apache_Solr_Document + */ + protected function getSolrDocument($class, $object, $value, $stage) + { + $doc = new \Apache_Solr_Document(); + $doc->setField('_documentid', $this->getExpectedDocumentId($object, $stage)); + $doc->setField('ClassName', $class); + $doc->setField(DataObject::getSchema()->baseDataClass($class) . '_TestText', $value); + $doc->setField('_versionedstage', $stage); + $doc->setField('ID', $object->ID); + $doc->setField('ClassHierarchy', SearchIntrospection::hierarchy($class)); + $doc->setFieldBoost('ID', false); + $doc->setFieldBoost('ClassHierarchy', false); + + return $doc; } public function testPublishing() { - - // Setup mocks - $serviceMock = $this->getServiceMock(); - self::$index->setService($serviceMock); - // Check that write updates Stage - Versioned::reading_stage('Stage'); - Phockito::reset($serviceMock); + Versioned::set_stage('Stage'); + $item = new SearchVariantVersionedTest_Item(array('TestText' => 'Foo')); $item->write(); $object = new SolrIndexVersionedTest_Object(array('TestText' => 'Bar')); $object->write(); + + $doc1 = $this->getSolrDocument(SearchVariantVersionedTest_Item::class, $item, 'Foo', 'Stage'); + $doc2 = $this->getSolrDocument(SolrIndexVersionedTest_Object::class, $object, 'Bar', 'Stage'); + + // Ensure correct call is made to Solr + $this->getServiceMock(['addDocument', 'commit']) + ->expects($this->exactly(2)) + ->method('addDocument') + ->withConsecutive( + [ + $this->equalTo($doc1), + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything() + ], + [ + $this->equalTo($doc2), + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything() + ] + ); + SearchUpdater::flush_dirty_indexes(); - $doc1 = new SolrDocumentMatcher(array( - '_documentid' => $this->getExpectedDocumentId($item, 'Stage'), - 'ClassName' => 'SearchVariantVersionedTest_Item', - 'SearchVariantVersionedTest_Item_TestText' => 'Foo', - '_versionedstage' => 'Stage' - )); - $doc2 = new SolrDocumentMatcher(array( - '_documentid' => $this->getExpectedDocumentId($object, 'Stage'), - 'ClassName' => 'SolrIndexVersionedTest_Object', - 'SolrIndexVersionedTest_Object_TestText' => 'Bar', - '_versionedstage' => 'Stage' - )); - Phockito::verify($serviceMock)->addDocument($doc1); - Phockito::verify($serviceMock)->addDocument($doc2); + // Check that write updates Live - Versioned::reading_stage('Stage'); - Phockito::reset($serviceMock); + Versioned::set_stage('Stage'); + $item = new SearchVariantVersionedTest_Item(array('TestText' => 'Foo')); $item->write(); - $item->publish('Stage', 'Live'); + $item->copyVersionToStage('Stage', 'Live'); + $object = new SolrIndexVersionedTest_Object(array('TestText' => 'Bar')); $object->write(); - $object->publish('Stage', 'Live'); + $object->copyVersionToStage('Stage', 'Live'); + + $doc1 = $this->getSolrDocument(SearchVariantVersionedTest_Item::class, $item, 'Foo', 'Stage'); + $doc2 = $this->getSolrDocument(SearchVariantVersionedTest_Item::class, $item, 'Foo', 'Live'); + $doc3 = $this->getSolrDocument(SolrIndexVersionedTest_Object::class, $object, 'Bar', 'Stage'); + $doc4 = $this->getSolrDocument(SolrIndexVersionedTest_Object::class, $object, 'Bar', 'Live'); + + // Ensure correct call is made to Solr + $this->getServiceMock(['addDocument', 'commit']) + ->expects($this->exactly(4)) + ->method('addDocument') + ->withConsecutive( + [ + $this->equalTo($doc1), + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything() + ], + [ + $this->equalTo($doc2), + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything() + ], + [ + $this->equalTo($doc3), + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything() + ], + [ + $this->equalTo($doc4), + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything() + ] + ); + SearchUpdater::flush_dirty_indexes(); - $doc = new SolrDocumentMatcher(array( - '_documentid' => $this->getExpectedDocumentId($item, 'Live'), - 'ClassName' => 'SearchVariantVersionedTest_Item', - 'SearchVariantVersionedTest_Item_TestText' => 'Foo', - '_versionedstage' => 'Live' - )); - $doc2 = new SolrDocumentMatcher(array( - '_documentid' => $this->getExpectedDocumentId($object, 'Live'), - 'ClassName' => 'SolrIndexVersionedTest_Object', - 'SolrIndexVersionedTest_Object_TestText' => 'Bar', - '_versionedstage' => 'Live' - )); - Phockito::verify($serviceMock)->addDocument($doc); - Phockito::verify($serviceMock)->addDocument($doc2); } public function testDelete() { - // Setup mocks - $serviceMock = $this->getServiceMock(); - self::$index->setService($serviceMock); - // Delete the live record (not the stage) - Versioned::reading_stage('Stage'); - Phockito::reset($serviceMock); + Versioned::set_stage('Stage'); + $item = new SearchVariantVersionedTest_Item(array('TestText' => 'Too')); $item->write(); - $item->publish('Stage', 'Live'); - Versioned::reading_stage('Live'); + $item->copyVersionToStage('Stage', 'Live'); + Versioned::set_stage('Live'); $id = clone $item; $item->delete(); + + // Check that only the 'Live' version is deleted + $this->getServiceMock(['addDocument', 'commit', 'deleteById']) + ->expects($this->exactly(1)) + ->method('deleteById') + ->with($this->equalTo($this->getExpectedDocumentId($id, 'Live'))); + SearchUpdater::flush_dirty_indexes(); - Phockito::verify($serviceMock, 1) - ->deleteById($this->getExpectedDocumentId($id, 'Live')); - Phockito::verify($serviceMock, 0) - ->deleteById($this->getExpectedDocumentId($id, 'Stage')); // Delete the stage record - Versioned::reading_stage('Stage'); - Phockito::reset($serviceMock); + Versioned::set_stage('Stage'); + $item = new SearchVariantVersionedTest_Item(array('TestText' => 'Too')); $item->write(); - $item->publish('Stage', 'Live'); + $item->copyVersionToStage('Stage', 'Live'); $id = clone $item; $item->delete(); + + // Check that only the 'Stage' version is deleted + $this->getServiceMock(['addDocument', 'commit', 'deleteById']) + ->expects($this->exactly(1)) + ->method('deleteById') + ->with($this->equalTo($this->getExpectedDocumentId($id, 'Stage'))); + SearchUpdater::flush_dirty_indexes(); - Phockito::verify($serviceMock, 1) - ->deleteById($this->getExpectedDocumentId($id, 'Stage')); - Phockito::verify($serviceMock, 0) - ->deleteById($this->getExpectedDocumentId($id, 'Live')); } } diff --git a/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php b/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php index 5c9298e..f264010 100644 --- a/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php +++ b/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php @@ -1,14 +1,14 @@ appendText('Apache_Solr_Document with properties '.var_export($this->properties, true)); + $description->appendText('\Apache_Solr_Document with properties '.var_export($this->properties, true)); } public function matches($item) { - if (! ($item instanceof Apache_Solr_Document)) { + if (! ($item instanceof \Apache_Solr_Document)) { return false; } diff --git a/tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php b/tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php index 62059b2..dfa0268 100644 --- a/tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php +++ b/tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php @@ -1,6 +1,6 @@ addClass('SearchVariantVersionedTest_Item'); - $this->addClass('SolrIndexVersionedTest_Object'); + $this->addClass(SearchVariantVersionedTest_Item::class); + $this->addClass(SolrIndexVersionedTest_Object::class); $this->addFilterField('TestText'); $this->addFulltextField('Content'); } diff --git a/tests/SolrReindexQueuedTest.php b/tests/SolrReindexQueuedTest.php index 5bd0412..42ce09c 100644 --- a/tests/SolrReindexQueuedTest.php +++ b/tests/SolrReindexQueuedTest.php @@ -1,10 +1,23 @@ skipTest = true; - return $this->markTestSkipped("These tests need the Phockito module installed to run"); - } - - if (!interface_exists('QueuedJob')) { + if (!interface_exists('SilverStripe\QueuedJobs\Services\QueuedJob')) { $this->skipTest = true; return $this->markTestSkipped("These tests need the QueuedJobs module installed to run"); } // Set queued handler for reindex - Config::inst()->update('Injector', 'SolrReindexHandler', array( - 'class' => 'SolrReindexQueuedHandler' + Config::modify()->set(Injector::class, SolrReindexHandler::class, array( + 'class' => SolrReindexQueuedHandler::class )); - Injector::inst()->registerService(new SolrReindexQueuedHandler(), 'SolrReindexHandler'); + Injector::inst()->registerService(new SolrReindexQueuedHandler(), SolrReindexHandler::class); // Set test variant SolrReindexTest_Variant::enable(); // Set index list - $this->service = $this->getServiceMock(); - $this->index = singleton('SolrReindexTest_Index'); + $this->service = $this->serviceMock(); + $this->index = singleton(SolrReindexTest_Index::class); $this->index->setService($this->service); FullTextSearch::force_index_list($this->index); } @@ -69,7 +77,8 @@ class SolrReindexQueuedTest extends SapphireTest protected function createDummyData($number) { // Populate dataobjects. Use truncate to generate predictable IDs - DB::query('TRUNCATE "SolrReindexTest_Item"'); + $tableName = DataObject::getSchema()->tableName(SolrReindexTest_Item::class); + DB::get_conn()->clearTable($tableName); // Note that we don't create any records in variant = 2, to represent a variant // that should be cleared without any re-indexes performed @@ -88,9 +97,15 @@ class SolrReindexQueuedTest extends SapphireTest * * @return SolrService */ - protected function getServiceMock() + protected function serviceMock() { - return Phockito::mock('Solr4Service'); + // Setup mock + /** @var SilverStripe\FullTextSearch\Solr\Services\Solr4Service|ObjectProphecy $serviceMock */ + $serviceMock = $this->getMockBuilder(Solr4Service::class) + ->setMethods(['deleteByQuery', 'addDocument']) + ->getMock(); + + return $serviceMock; } public function tearDown() @@ -115,7 +130,7 @@ class SolrReindexQueuedTest extends SapphireTest */ protected function getQueuedJobService() { - return singleton('SolrReindexQueuedTest_Service'); + return Injector::inst()->get(SolrReindexQueuedTest_Service::class); } /** @@ -126,6 +141,20 @@ class SolrReindexQueuedTest extends SapphireTest { $this->createDummyData(18); + // Deletes are performed in the main task prior to individual groups being processed + // 18 records means 3 groups of 6 in each variant (6 total) + // Ensure correct call is made to Solr + $this->service->expects($this->exactly(2)) + ->method('deleteByQuery') + ->withConsecutive( + [ + $this->equalTo('-(ClassHierarchy:' . SolrReindexTest_Item::class . ')') + ], + [ + $this->equalTo('+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +(_testvariant:"2")') + ] + ); + // Create pre-existing jobs $this->getQueuedJobService()->queueJob(new SolrReindexQueuedJob()); $this->getQueuedJobService()->queueJob(new SolrReindexGroupQueuedJob()); @@ -141,7 +170,7 @@ class SolrReindexQueuedTest extends SapphireTest // Next job should be queue job $job = $this->getQueuedJobService()->getNextJob(); - $this->assertInstanceOf('SolrReindexQueuedJob', $job); + $this->assertInstanceOf(SolrReindexQueuedJob::class, $job); $this->assertEquals(6, $job->getBatchSize()); // Test that necessary items are created @@ -149,28 +178,19 @@ class SolrReindexQueuedTest extends SapphireTest $job->setLogger($logger); $job->process(); - // Deletes are performed in the main task prior to individual groups being processed - // 18 records means 3 groups of 6 in each variant (6 total) - Phockito::verify($this->service, 2) - ->deleteByQuery(\Hamcrest_Matchers::anything()); $this->assertEquals(1, $logger->countMessages('Beginning init of reindex')); $this->assertEquals(6, $logger->countMessages('Queued Solr Reindex Group ')); - $this->assertEquals(3, $logger->countMessages(' of SolrReindexTest_Item in {"SolrReindexTest_Variant":"0"}')); - $this->assertEquals(3, $logger->countMessages(' of SolrReindexTest_Item in {"SolrReindexTest_Variant":"1"}')); + $this->assertEquals(3, $logger->countMessages(' of ' . SolrReindexTest_Item::class . ' in {' . json_encode(SolrReindexTest_Variant::class) . ':"0"}')); + $this->assertEquals(3, $logger->countMessages(' of ' . SolrReindexTest_Item::class . ' in {' . json_encode(SolrReindexTest_Variant::class) . ':"1"}')); $this->assertEquals(1, $logger->countMessages('Completed init of reindex')); - // Test that invalid classes are removed - $this->assertNotEmpty($logger->getMessages('Clearing obsolete classes from SolrReindexTest_Index')); - Phockito::verify($this->service, 1) - ->deleteByQuery('-(ClassHierarchy:SolrReindexTest_Item)'); + $this->assertNotEmpty($logger->getMessages('Clearing obsolete classes from ' . SolrReindexTest_Index::class)); // Test that valid classes in invalid variants are removed $this->assertNotEmpty($logger->getMessages( - 'Clearing all records of type SolrReindexTest_Item in the current state: {"SolrReindexTest_Variant":"2"}' + 'Clearing all records of type ' . SolrReindexTest_Item::class . ' in the current state: {"' . SolrReindexTest_Variant::class . '":"2"}' )); - Phockito::verify($this->service, 1) - ->deleteByQuery('+(ClassHierarchy:SolrReindexTest_Item) +(_testvariant:"2")'); } /** @@ -189,9 +209,9 @@ class SolrReindexQueuedTest extends SapphireTest // Check next job is a group queued job $job = $this->getQueuedJobService()->getNextJob(); - $this->assertInstanceOf('SolrReindexGroupQueuedJob', $job); + $this->assertInstanceOf(SolrReindexGroupQueuedJob::class, $job); $this->assertEquals( - 'Solr Reindex Group (1/3) of SolrReindexTest_Item in {"SolrReindexTest_Variant":"0"}', + 'Solr Reindex Group (1/3) of ' . SolrReindexTest_Item::class . ' in {' . json_encode(SolrReindexTest_Variant::class) . ':"0"}', $job->getTitle() ); @@ -202,7 +222,7 @@ class SolrReindexQueuedTest extends SapphireTest // Check tasks completed (as per non-queuedjob version) $this->assertEquals(1, $logger->countMessages('Beginning reindex group')); - $this->assertEquals(1, $logger->countMessages('Adding SolrReindexTest_Item')); + $this->assertEquals(1, $logger->countMessages('Adding ' . SolrReindexTest_Item::class . '')); $this->assertEquals(1, $logger->countMessages('Queuing commit on all changes')); $this->assertEquals(1, $logger->countMessages('Completed reindex group')); @@ -217,19 +237,3 @@ class SolrReindexQueuedTest extends SapphireTest } } } - -if (!class_exists('QueuedJobService')) { - return; -} - -class SolrReindexQueuedTest_Service extends QueuedJobService implements TestOnly -{ - /** - * @return QueuedJob - */ - public function getNextJob() - { - $job = $this->getNextPendingJob(); - return $this->initialiseJob($job); - } -} diff --git a/tests/SolrReindexQueuedTest/SolrReindexQueuedTest_Service.php b/tests/SolrReindexQueuedTest/SolrReindexQueuedTest_Service.php new file mode 100644 index 0000000..a5c0626 --- /dev/null +++ b/tests/SolrReindexQueuedTest/SolrReindexQueuedTest_Service.php @@ -0,0 +1,27 @@ + '%$QueueHandler' + ]; + + /** + * @return QueuedJob + */ + public function getNextJob() + { + $job = $this->getNextPendingJob(); + return $this->initialiseJob($job); + } +} diff --git a/tests/SolrReindexTest.php b/tests/SolrReindexTest.php index 72226d3..7f2dd85 100644 --- a/tests/SolrReindexTest.php +++ b/tests/SolrReindexTest.php @@ -1,21 +1,27 @@ skipTest = true; - return $this->markTestSkipped("These tests need the Phockito module installed to run"); - } - // Set test handler for reindex - Config::inst()->update('Injector', 'SolrReindexHandler', array( - 'class' => 'SolrReindexTest_TestHandler' + Config::modify()->set('Injector', SolrReindexHandler::class, array( + 'class' => SolrReindexTest_TestHandler::class )); - Injector::inst()->registerService(new SolrReindexTest_TestHandler(), 'SolrReindexHandler'); + Injector::inst()->registerService(new SolrReindexTest_TestHandler(), SolrReindexHandler::class); // Set test variant SolrReindexTest_Variant::enable(); // Set index list $this->service = $this->getServiceMock(); - $this->index = singleton('SolrReindexTest_Index'); + $this->index = singleton(SolrReindexTest_Index::class); $this->index->setService($this->service); FullTextSearch::force_index_list($this->index); } @@ -64,8 +65,7 @@ class SolrReindexTest extends SapphireTest */ protected function createDummyData($number) { - // Populate dataobjects. Use truncate to generate predictable IDs - DB::query('TRUNCATE "SolrReindexTest_Item"'); + self::resetDBSchema(); // Note that we don't create any records in variant = 2, to represent a variant // that should be cleared without any re-indexes performed @@ -86,7 +86,10 @@ class SolrReindexTest extends SapphireTest */ protected function getServiceMock() { - return Phockito::mock('Solr4Service'); + $serviceMock = $this->getMockBuilder(Solr4Service::class) + ->setMethods(['deleteByQuery', 'addDocument']); + + return $serviceMock->getMock(); } public function tearDown() @@ -115,7 +118,7 @@ class SolrReindexTest extends SapphireTest $variant = SearchVariant::current_state(); $this->assertEquals( array( - "SolrReindexTest_Variant" => "0" + SolrReindexTest_Variant::class => "0" ), $variant ); @@ -125,13 +128,13 @@ class SolrReindexTest extends SapphireTest $this->assertEquals( array( array( - "SolrReindexTest_Variant" => "0" + SolrReindexTest_Variant::class => "0" ), array( - "SolrReindexTest_Variant" => "1" + SolrReindexTest_Variant::class => "1" ), array( - "SolrReindexTest_Variant" => "2" + SolrReindexTest_Variant::class => "2" ) ), $allStates @@ -158,36 +161,36 @@ class SolrReindexTest extends SapphireTest */ public function testReindexSegmentsGroups() { + $this->service->method('deleteByQuery') + ->withConsecutive( + ['-(ClassHierarchy:' . SolrReindexTest_Item::class . ')'], + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +(_testvariant:"2")'] + ); + $this->createDummyData(120); // Initiate re-index $logger = new SolrReindexTest_RecordingLogger(); - $this->getHandler()->runReindex($logger, 21, 'Solr_Reindex'); + $this->getHandler()->runReindex($logger, 21, Solr_Reindex::class); // Test that invalid classes are removed - $this->assertNotEmpty($logger->getMessages('Clearing obsolete classes from SolrReindexTest_Index')); - Phockito::verify($this->service, 1) - ->deleteByQuery('-(ClassHierarchy:SolrReindexTest_Item)'); - + $this->assertContains('Clearing obsolete classes from ' . SolrReindexTest_Index::class, $logger->getMessages()); + //var_dump($logger->getMessages()); // Test that valid classes in invalid variants are removed - $this->assertNotEmpty($logger->getMessages( - 'Clearing all records of type SolrReindexTest_Item in the current state: {"SolrReindexTest_Variant":"2"}' - )); - Phockito::verify($this->service, 1) - ->deleteByQuery('+(ClassHierarchy:SolrReindexTest_Item) +(_testvariant:"2")'); + $this->assertContains('Clearing all records of type ' . SolrReindexTest_Item::class . ' in the current state: {' . json_encode(SolrReindexTest_Variant::class) . ':"2"}', $logger->getMessages()); // 120x2 grouped into groups of 21 results in 12 groups $this->assertEquals(12, $logger->countMessages('Called processGroup with ')); - $this->assertEquals(6, $logger->countMessages('{"SolrReindexTest_Variant":"0"}')); - $this->assertEquals(6, $logger->countMessages('{"SolrReindexTest_Variant":"1"}')); + $this->assertEquals(6, $logger->countMessages('{' . json_encode(SolrReindexTest_Variant::class) . ':"0"}')); + $this->assertEquals(6, $logger->countMessages('{' . json_encode(SolrReindexTest_Variant::class) . ':"1"}')); // Given that there are two variants, there should be two group ids of each number - $this->assertEquals(2, $logger->countMessages(' SolrReindexTest_Item, group 0 of 6')); - $this->assertEquals(2, $logger->countMessages(' SolrReindexTest_Item, group 1 of 6')); - $this->assertEquals(2, $logger->countMessages(' SolrReindexTest_Item, group 2 of 6')); - $this->assertEquals(2, $logger->countMessages(' SolrReindexTest_Item, group 3 of 6')); - $this->assertEquals(2, $logger->countMessages(' SolrReindexTest_Item, group 4 of 6')); - $this->assertEquals(2, $logger->countMessages(' SolrReindexTest_Item, group 5 of 6')); + $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 0 of 6')); + $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 1 of 6')); + $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 2 of 6')); + $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 3 of 6')); + $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 4 of 6')); + $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 5 of 6')); // Check various group sizes $logger->clear(); @@ -209,25 +212,23 @@ class SolrReindexTest extends SapphireTest */ public function testRunGroup() { + $this->service->method('deleteByQuery') + ->with('+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=2 u=2}mod(ID, 6)" +(_testvariant:"1")'); + $this->createDummyData(120); $logger = new SolrReindexTest_RecordingLogger(); // Initiate re-index of third group (index 2 of 6) - $state = array('SolrReindexTest_Variant' => '1'); - $this->getHandler()->runGroup($logger, $this->index, $state, 'SolrReindexTest_Item', 6, 2); + $state = array(SolrReindexTest_Variant::class => '1'); + $this->getHandler()->runGroup($logger, $this->index, $state, SolrReindexTest_Item::class, 6, 2); $idMessage = $logger->filterMessages('Updated '); $this->assertNotEmpty(preg_match('/^Updated (?[,\d]+)/i', $idMessage[0], $matches)); $ids = array_unique(explode(',', $matches['ids'])); // Test successful - $this->assertNotEmpty($logger->getMessages('Adding SolrReindexTest_Item')); + $this->assertNotEmpty($logger->getMessages('Adding ' . SolrReindexTest_Item::class)); $this->assertNotEmpty($logger->getMessages('Done')); - // Test that items in this variant / group are cleared from solr - Phockito::verify($this->service, 1)->deleteByQuery( - '+(ClassHierarchy:SolrReindexTest_Item) +_query_:"{!frange l=2 u=2}mod(ID, 6)" +(_testvariant:"1")' - ); - // Test that items in this variant / group are re-indexed // 120 divided into 6 groups should be 20 at least (max 21) $this->assertEquals(21, count($ids), 'Group size is about 20', 1); @@ -242,16 +243,27 @@ class SolrReindexTest extends SapphireTest */ public function testRunAllGroups() { + $this->service->method('deleteByQuery') + ->withConsecutive( + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=0 u=0}mod(ID, 6)" +(_testvariant:"1")'], + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=1 u=1}mod(ID, 6)" +(_testvariant:"1")'], + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=2 u=2}mod(ID, 6)" +(_testvariant:"1")'], + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=3 u=3}mod(ID, 6)" +(_testvariant:"1")'], + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=4 u=4}mod(ID, 6)" +(_testvariant:"1")'], + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=5 u=5}mod(ID, 6)" +(_testvariant:"1")'], + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=6 u=6}mod(ID, 6)" +(_testvariant:"1")'] + ); + $this->createDummyData(120); $logger = new SolrReindexTest_RecordingLogger(); // Test that running all groups covers the complete set of ids - $state = array('SolrReindexTest_Variant' => '1'); + $state = array(SolrReindexTest_Variant::class => '1'); for ($i = 0; $i < 6; $i++) { // See testReindexSegmentsGroups for test that each of these states is invoked during a full reindex $this ->getHandler() - ->runGroup($logger, $this->index, $state, 'SolrReindexTest_Item', 6, $i); + ->runGroup($logger, $this->index, $state, SolrReindexTest_Item::class, 6, $i); } // Count all ids updated @@ -263,24 +275,5 @@ class SolrReindexTest extends SapphireTest // Check ids $this->assertEquals(120, count($ids)); - Phockito::verify($this->service, 6)->deleteByQuery(\Hamcrest_Matchers::anything()); - Phockito::verify($this->service, 1)->deleteByQuery( - '+(ClassHierarchy:SolrReindexTest_Item) +_query_:"{!frange l=0 u=0}mod(ID, 6)" +(_testvariant:"1")' - ); - Phockito::verify($this->service, 1)->deleteByQuery( - '+(ClassHierarchy:SolrReindexTest_Item) +_query_:"{!frange l=1 u=1}mod(ID, 6)" +(_testvariant:"1")' - ); - Phockito::verify($this->service, 1)->deleteByQuery( - '+(ClassHierarchy:SolrReindexTest_Item) +_query_:"{!frange l=2 u=2}mod(ID, 6)" +(_testvariant:"1")' - ); - Phockito::verify($this->service, 1)->deleteByQuery( - '+(ClassHierarchy:SolrReindexTest_Item) +_query_:"{!frange l=3 u=3}mod(ID, 6)" +(_testvariant:"1")' - ); - Phockito::verify($this->service, 1)->deleteByQuery( - '+(ClassHierarchy:SolrReindexTest_Item) +_query_:"{!frange l=4 u=4}mod(ID, 6)" +(_testvariant:"1")' - ); - Phockito::verify($this->service, 1)->deleteByQuery( - '+(ClassHierarchy:SolrReindexTest_Item) +_query_:"{!frange l=5 u=5}mod(ID, 6)" +(_testvariant:"1")' - ); } } diff --git a/tests/SolrReindexTest/SolrReindexTest_Index.php b/tests/SolrReindexTest/SolrReindexTest_Index.php index 64e85b2..b1fafec 100644 --- a/tests/SolrReindexTest/SolrReindexTest_Index.php +++ b/tests/SolrReindexTest/SolrReindexTest_Index.php @@ -9,7 +9,7 @@ class SolrReindexTest_Index extends SolrIndex implements TestOnly { public function init() { - $this->addClass('SolrReindexTest_Item'); + $this->addClass(SolrReindexTest_Item::class); $this->addAllFulltextFields(); } } diff --git a/tests/SolrReindexTest/SolrReindexTest_Item.php b/tests/SolrReindexTest/SolrReindexTest_Item.php index 6a08387..40258d2 100644 --- a/tests/SolrReindexTest/SolrReindexTest_Item.php +++ b/tests/SolrReindexTest/SolrReindexTest_Item.php @@ -9,8 +9,10 @@ use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_ItemExtens /** * Does not have any variant extensions */ -class SolrReindexTest_Item extends DataObject implements TestOnly +class SolrReindexTest_Item extends DataObject { + private static $table_name = 'SolrReindexTest_Item'; + private static $extensions = [ SolrReindexTest_ItemExtension::class ]; diff --git a/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php b/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php index 9981932..faa2e22 100644 --- a/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php +++ b/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php @@ -17,7 +17,7 @@ class SolrReindexTest_ItemExtension extends DataExtension implements TestOnly /** * Filter records on the current variant * - * @param SQLQuery $query + * @param SQLSelect $query * @param DataQuery $dataQuery */ public function augmentSQL(SQLSelect $query, DataQuery $dataQuery = NULL) diff --git a/tests/SolrReindexTest/SolrReindexTest_Variant.php b/tests/SolrReindexTest/SolrReindexTest_Variant.php index dbb6115..94cef6d 100644 --- a/tests/SolrReindexTest/SolrReindexTest_Variant.php +++ b/tests/SolrReindexTest/SolrReindexTest_Variant.php @@ -4,6 +4,7 @@ namespace SilverStripe\FullTextSearch\Tests\SolrReindexTest; use SilverStripe\Dev\TestOnly; use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; +use SilverStripe\ORM\DataObject; /** * Dummy variant that selects items with field Varient matching the current value @@ -28,7 +29,7 @@ class SolrReindexTest_Variant extends SearchVariant implements TestOnly self::$current = 0; self::$variants = array( - 'SolrReindexTest_Variant' => singleton('SolrReindexTest_Variant') + self::class => singleton(self::class) ); } @@ -79,7 +80,7 @@ class SolrReindexTest_Variant extends SearchVariant implements TestOnly 'name' => '_testvariant', 'field' => '_testvariant', 'fullfield' => '_testvariant', - 'base' => ClassInfo::baseDataClass($class), + 'base' => DataObject::getSchema()->baseDataClass($class), 'origin' => $class, 'type' => 'Int', 'lookup_chain' => array(array('call' => 'variant', 'variant' => $self, 'method' => 'currentState')) @@ -94,8 +95,8 @@ class SolrReindexTest_Variant extends SearchVariant implements TestOnly public function appliesTo($class, $includeSubclasses) { - return $class === 'SolrReindexTest_Item' || - ($includeSubclasses && is_subclass_of($class, 'SolrReindexTest_Item', true)); + return $class === SolrReindexTest_Item::class || + ($includeSubclasses && is_subclass_of($class, SolrReindexTest_Item::class, true)); } public function appliesToEnvironment()