API Update Subsite integration, remove Polyhome variant

Add a method to clear cached variants from SearchVariant, and a configuration flag for whether
a variant should be enabled or not. Add a FullTextSearch TestState class which will globally
disable the queuedjobs and fulltextsearch shutdown handlers during tests, and is not used to
clear cached variants on each test to prevent global state leakage.

Also removes Phockito as a test dependency.
This commit is contained in:
Robbie Averill 2017-12-05 09:11:51 +13:00
parent ceff657c62
commit 861f87514d
26 changed files with 377 additions and 524 deletions

View File

@ -12,6 +12,8 @@ matrix:
env: DB=MYSQL PHPUNIT_TEST=1
- php: 7.1
env: DB=MYSQL PHPUNIT_COVERAGE_TEST=1
- php: 7.1
env: DB=MYSQL PHPUNIT_TEST=1 SUBSITES=1
- php: 7.2
env: DB=MYSQL PHPUNIT_TEST=1
@ -21,7 +23,7 @@ before_script:
- composer validate
- composer require --no-update symbiote/silverstripe-queuedjobs ^4.0
# todo: Add Subsites in
- if [[ $SUBSITES ]]; then composer require --no-update silverstripe/subsites 2.0.x-dev; fi
- composer require --no-update silverstripe/installer 4.0.x-dev
- composer install --prefer-dist --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile

View File

@ -16,7 +16,6 @@ mappings:
SearchUpdater_ObjectHandler: SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater_ObjectHandler
SearchVariant: SilverStripe\FullTextSearch\Search\Variants\SearchVariant
SearchVariant_Caller: SilverStripe\FullTextSearch\Search\Variants\SearchVariant_Caller
SearchVariantSiteTreeSubsitesPolyhome: SilverStripe\FullTextSearch\Search\Variants\SearchVariantSiteTreeSubsitesPolyhome
SearchVariantSubsites: SilverStripe\FullTextSearch\Search\Variants\SearchVariantSubsites
SearchVariantVersioned: SilverStripe\FullTextSearch\Search\Variants\SearchVariantVersioned
SolrReindexBase: SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexBase

View File

@ -13,7 +13,6 @@ Adds support for fulltext search engines like Sphinx and Solr to SilverStripe CM
## Requirements
* SilverStripe 4.0+
* (optional) [silverstripe-phockito](https://github.com/hafriedlander/silverstripe-phockito) (for testing)
**Note:** For SilverStripe 3.x, please use the [2.x release line](https://github.com/silverstripe/silverstripe-fulltextsearch/tree/2).

8
_config/tests.yml Normal file
View File

@ -0,0 +1,8 @@
---
Name: fulltextsearchtests
---
SilverStripe\Core\Injector\Injector:
SilverStripe\Dev\State\SapphireTestState:
properties:
States:
fulltextsearch: '%$SilverStripe\FullTextSearch\Tests\State\FullTextSearchState'

View File

@ -1,4 +1,5 @@
<?php
namespace SilverStripe\FullTextSearch\Search;
use SilverStripe\Core\ClassInfo;

View File

@ -4,6 +4,7 @@ namespace SilverStripe\FullTextSearch\Search\Variants;
use SilverStripe\ORM\DataObject;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\FullTextSearch\Utils\CombinationsArrayIterator;
use ReflectionClass;
@ -13,6 +14,16 @@ use ReflectionClass;
*/
abstract class SearchVariant
{
use Configurable;
/**
* Whether this variant is enabled
*
* @config
* @var boolean
*/
private static $enabled = true;
public function __construct()
{
}
@ -30,7 +41,7 @@ abstract class SearchVariant
*/
public function appliesToEnvironment()
{
return true;
return $this->config()->get('enabled');
}
/**
@ -117,6 +128,14 @@ abstract class SearchVariant
}
}
/**
* Clear the cached variants
*/
public static function clear_variant_cache()
{
self::$class_variants = [];
}
/** Holds a cache of SearchVariant_Caller instances, one for each class/includeSubclasses setting */
protected static $call_instances = array();
@ -175,14 +194,14 @@ abstract class SearchVariant
/**
* Activate all the states in the passed argument
* @static
* @param (array) $state. A set of (string)$variantClass => (any)$state pairs , e.g. as returned by
* @param array $state A set of (string)$variantClass => (any)$state pairs , e.g. as returned by
* SearchVariant::current_state()
* @return void
*/
public static function activate_state($state)
{
foreach (self::variants() as $variant => $instance) {
if (isset($state[$variant])) {
if (isset($state[$variant]) && $instance->appliesToEnvironment()) {
$instance->activateState($state[$variant]);
}
}

View File

@ -1,103 +0,0 @@
<?php
namespace SilverStripe\FullTextSearch\Search\Variants;
use SilverStripe\ORM\Queries\SQLSelect;
use SilverStripe\FullTextSearch\Search\SearchIntrospection;
if (!class_exists('Subsite') || !class_exists('SubsitePolyhome')) {
return;
}
class SearchVariantSiteTreeSubsitesPolyhome extends SearchVariant
{
public function appliesToEnvironment()
{
return class_exists('Subsite') && class_exists('SubsitePolyhome');
}
public function appliesTo($class, $includeSubclasses)
{
return SearchIntrospection::has_extension($class, 'SiteTreeSubsitesPolyhome', $includeSubclasses);
}
public function currentState()
{
return Subsite::currentSubsiteID();
}
public function reindexStates()
{
static $ids = null;
if ($ids === null) {
$ids = array(0);
foreach (DataObject::get('Subsite') as $subsite) {
$ids[] = $subsite->ID;
}
}
return $ids;
}
public function activateState($state)
{
if (Controller::has_curr()) {
Subsite::changeSubsite($state);
} else {
// TODO: This is a nasty hack - calling Subsite::changeSubsite after request ends
// throws error because no current controller to access session on
$_REQUEST['SubsiteID'] = $state;
}
}
public function alterDefinition($class, $index)
{
$self = get_class($this);
$this->addFilterField($index, '_subsite', array(
'name' => '_subsite',
'field' => '_subsite',
'fullfield' => '_subsite',
'base' => DataObject::getSchema()->baseDataClass($class),
'origin' => $class,
'type' => 'Int',
'lookup_chain' => array(array('call' => 'variant', 'variant' => $self, 'method' => 'currentState'))
));
}
public function alterQuery($query, $index)
{
$subsite = Subsite::currentSubsiteID();
$query->filter('_subsite', array($subsite, SearchQuery::$missing));
}
public static $subsites = null;
/**
* We need _really_ complicated logic to find just the changed subsites (because we use versions there's no explicit
* deletes, just new versions with different members) so just always use all of them
*/
public function extractManipulationWriteState(&$writes)
{
$self = get_class($this);
foreach ($writes as $key => $write) {
if (!$this->appliesTo($write['class'], true)) {
continue;
}
if (self::$subsites === null) {
$query = new SQLSelect('ID', 'Subsite');
self::$subsites = array_merge(array('0'), $query->execute()->column());
}
$next = array();
foreach ($write['statefulids'] as $i => $statefulid) {
foreach (self::$subsites as $subsiteID) {
$next[] = array('id' => $statefulid['id'], 'state' => array_merge($statefulid['state'], array($self => $subsiteID)));
}
}
$writes[$key]['statefulids'] = $next;
}
}
}

View File

@ -2,13 +2,21 @@
namespace SilverStripe\FullTextSearch\Search\Variants;
use SilverStripe\Assets\File;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\FullTextSearch\Search\SearchIntrospection;
use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;
use SilverStripe\ORM\Queries\SQLSelect;
use SilverStripe\ORM\DataObject;
use SilverStripe\Security\Permission;
use SilverStripe\FullTextSearch\Search\SearchIntrospection;
use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;
use SilverStripe\Subsites\Model\Subsite;
use SilverStripe\Subsites\Extensions\SiteTreeSubsites;
use SilverStripe\Subsites\Extensions\GroupSubsites;
use SilverStripe\Subsites\Extensions\FileSubsites;
use SilverStripe\Subsites\Extensions\SiteConfigSubsites;
use SilverStripe\Subsites\State\SubsiteState;
if (!class_exists('Subsite')) {
if (!class_exists(Subsite::class)) {
return;
}
@ -16,22 +24,26 @@ class SearchVariantSubsites extends SearchVariant
{
public function appliesToEnvironment()
{
return class_exists('Subsite');
return class_exists(Subsite::class) && parent::appliesToEnvironment();
}
public function appliesTo($class, $includeSubclasses)
{
if (!$this->appliesToEnvironment()) {
return false;
}
// Include all DataExtensions that contain a SubsiteID.
// TODO: refactor subsites to inherit a common interface, so we can run introspection once only.
return SearchIntrospection::has_extension($class, 'SiteTreeSubsites', $includeSubclasses) ||
SearchIntrospection::has_extension($class, 'GroupSubsites', $includeSubclasses) ||
SearchIntrospection::has_extension($class, 'FileSubsites', $includeSubclasses) ||
SearchIntrospection::has_extension($class, 'SiteConfigSubsites', $includeSubclasses);
return SearchIntrospection::has_extension($class, SiteTreeSubsites::class, $includeSubclasses)
|| SearchIntrospection::has_extension($class, GroupSubsites::class, $includeSubclasses)
|| SearchIntrospection::has_extension($class, FileSubsites::class, $includeSubclasses)
|| SearchIntrospection::has_extension($class, SiteConfigSubsites::class, $includeSubclasses);
}
public function currentState()
{
return (string)Subsite::currentSubsiteID();
return (string) SubsiteState::singleton()->getSubsiteId();
}
public function reindexStates()
@ -39,9 +51,9 @@ class SearchVariantSubsites extends SearchVariant
static $ids = null;
if ($ids === null) {
$ids = array('0');
foreach (DataObject::get('Subsite') as $subsite) {
$ids[] = (string)$subsite->ID;
$ids = ['0'];
foreach (Subsite::get() as $subsite) {
$ids[] = (string) $subsite->ID;
}
}
@ -50,26 +62,34 @@ class SearchVariantSubsites extends SearchVariant
public function activateState($state)
{
// We always just set the $_GET variable rather than store in Session - this always works, has highest priority
// in Subsite::currentSubsiteID() and doesn't persist unlike Subsite::changeSubsite
$_GET['SubsiteID'] = $state;
Permission::flush_permission_cache();
if (!$this->appliesToEnvironment()) {
return;
}
// Note: Setting directly to the SubsiteState because we don't want the subsite ID to be persisted
// like Subsite::changeSubsite would do.
SubsiteState::singleton()->setSubsiteId($state);
Permission::reset();
}
public function alterDefinition($class, $index)
{
$self = get_class($this);
if (!$this->appliesTo($class, true)) {
return;
}
// Add field to root
$this->addFilterField($index, '_subsite', array(
$this->addFilterField($index, '_subsite', [
'name' => '_subsite',
'field' => '_subsite',
'fullfield' => '_subsite',
'base' => DataObject::getSchema()->baseDataClass($class),
'origin' => $class,
'type' => 'Int',
'lookup_chain' => array(array('call' => 'variant', 'variant' => $self, 'method' => 'currentState'))
));
'lookup_chain' => [['call' => 'variant', 'variant' => $self, 'method' => 'currentState']],
]);
}
/**
@ -83,12 +103,12 @@ class SearchVariantSubsites extends SearchVariant
*/
public function alterQuery($query, $index)
{
if ($this->isFieldFiltered('_subsite', $query)) {
if ($this->isFieldFiltered('_subsite', $query) || !$this->appliesToEnvironment()) {
return;
}
$subsite = Subsite::currentSubsiteID();
$query->filter('_subsite', array($subsite, SearchQuery::$missing));
$subsite = $this->currentState();
$query->filter('_subsite', [$subsite, SearchQuery::$missing]);
}
/**
@ -98,8 +118,9 @@ class SearchVariantSubsites extends SearchVariant
public function extractManipulationWriteState(&$writes)
{
$self = get_class($this);
$query = new SQLSelect('"ID"', '"Subsite"');
$subsites = array_merge(array('0'), $query->execute()->column());
$tableName = DataObject::getSchema()->tableName(Subsite::class);
$query = SQLSelect::create('"ID"', '"' . $tableName . '"');
$subsites = array_merge(['0'], $query->execute()->column());
foreach ($writes as $key => $write) {
$applies = $this->appliesTo($write['class'], true);
@ -107,25 +128,27 @@ class SearchVariantSubsites extends SearchVariant
continue;
}
if (isset($write['fields']['SiteTree:SubsiteID'])) {
$subsitesForWrite = array($write['fields']['SiteTree:SubsiteID']);
} // files in subsite 0 should be in all subsites as they are global
elseif (isset($write['fields']['File:SubsiteID']) && intval($write['fields']['File:SubsiteID']) !== 0) {
$subsitesForWrite = array($write['fields']['File:SubsiteID']);
if (isset($write['fields'][SiteTree::class . ':SubsiteID'])) {
$subsitesForWrite = [$write['fields'][SiteTree::class . ':SubsiteID']];
} elseif (isset($write['fields'][File::class . ':SubsiteID'])
&& (int) $write['fields'][File::class . ':SubsiteID'] !== 0
) {
// files in subsite 0 should be in all subsites as they are global
$subsitesForWrite = [$write['fields'][File::class . ':SubsiteID']];
} else {
$subsitesForWrite = $subsites;
}
$next = array();
$next = [];
foreach ($write['statefulids'] as $i => $statefulid) {
foreach ($subsitesForWrite as $subsiteID) {
$next[] = array(
$next[] = [
'id' => $statefulid['id'],
'state' => array_merge(
$statefulid['state'],
array($self => (string)$subsiteID)
)
);
[$self => (string) $subsiteID]
),
];
}
}
$writes[$key]['statefulids'] = $next;

View File

@ -12,6 +12,10 @@ class SearchVariantVersioned extends SearchVariant
{
public function appliesTo($class, $includeSubclasses)
{
if (!$this->appliesToEnvironment()) {
return false;
}
return SearchIntrospection::has_extension($class, Versioned::class, $includeSubclasses);
}
@ -57,8 +61,6 @@ class SearchVariantVersioned extends SearchVariant
public function extractManipulationState(&$manipulation)
{
$self = get_class($this);
foreach ($manipulation as $table => $details) {
$class = $details['class'];
$stage = Versioned::DRAFT;
@ -70,7 +72,7 @@ class SearchVariantVersioned extends SearchVariant
if (ClassInfo::exists($class) && $this->appliesTo($class, false)) {
$manipulation[$table]['class'] = $class;
$manipulation[$table]['state'][$self] = $stage;
$manipulation[$table]['state'][get_class($this)] = $stage;
}
}
}
@ -83,10 +85,9 @@ class SearchVariantVersioned extends SearchVariant
if (ClassInfo::exists($class) && $this->appliesTo($class, false)) {
$table = $class;
$self = get_class($this);
foreach ($ids as $i => $statefulid) {
$ids[$i]['state'][$self] = $suffix ? $suffix : Versioned::DRAFT;
$ids[$i]['state'][get_class($this)] = $suffix ?: Versioned::DRAFT;
}
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace SilverStripe\FullTextSearch\Solr\Services;
class Solr4Service extends SolrService

View File

@ -2,12 +2,11 @@
namespace SilverStripe\FullTextSearch\Tests;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\FullTextSearch\Search\FullTextSearch;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\Core\Config\Config;
use SilverStripe\Versioned\Versioned;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\FullTextSearch\Tests\BatchedProcessorTest\BatchedProcessor_QueuedJobService;
use SilverStripe\FullTextSearch\Tests\BatchedProcessorTest\BatchedProcessorTest_Index;
use SilverStripe\FullTextSearch\Tests\BatchedProcessorTest\BatchedProcessorTest_Object;
@ -16,6 +15,9 @@ use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateQueuedJobProcessor
use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateBatchedProcessor;
use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater;
use SilverStripe\FullTextSearch\Search\Variants\SearchVariantVersioned;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\Versioned\Versioned;
use Symbiote\QueuedJobs\Services\QueuedJob;
use Symbiote\QueuedJobs\Services\QueuedJobService;
/**
@ -29,37 +31,30 @@ class BatchedProcessorTest extends SapphireTest
BatchedProcessorTest_Object::class
);
protected $illegalExtensions = array(
'SiteTree' => array(
'SiteTreeSubsites',
'Translatable'
)
);
protected static $illegal_extensions = [
SiteTree::class => [
SiteTreeSubsites::class,
],
];
public function setUpOnce()
public static function setUpBeforeClass()
{
// Disable illegal extensions if skipping this test
if (class_exists('Subsite') || !interface_exists('Symbiote\QueuedJobs\Services\QueuedJob')) {
$this->illegalExtensions = array();
if (class_exists(Subsite::class) || !interface_exists(QueuedJob::class)) {
static::$illegal_extensions = [];
}
parent::setUpOnce();
parent::setUpBeforeClass();
}
protected function setUp()
{
Config::modify()->set(SearchUpdater::class, 'flush_on_shutdown', false);
parent::setUp();
if (!interface_exists('Symbiote\QueuedJobs\Services\QueuedJob')) {
$this->skipTest = true;
if (!interface_exists(QueuedJob::class)) {
$this->markTestSkipped("These tests need the QueuedJobs module installed to run");
}
Config::modify()->set(QueuedJobService::class, 'use_shutdown_function', false);
if (class_exists('Subsite')) {
$this->skipTest = true;
if (class_exists(Subsite::class)) {
$this->markTestSkipped(get_class() . ' skipped when running with subsites');
}
@ -69,7 +64,7 @@ class BatchedProcessorTest extends SapphireTest
Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_soft_cap', 0);
Config::modify()->set(SearchUpdateCommitJobProcessor::class, 'cooldown', 600);
Versioned::set_stage("Stage");
Versioned::set_stage(Versioned::DRAFT);
Injector::inst()->registerService(new BatchedProcessor_QueuedJobService(), QueuedJobService::class);

View File

@ -22,8 +22,6 @@ class SearchUpdaterTest extends SapphireTest
protected function setUp()
{
Config::modify()->set(SearchUpdater::class, 'flush_on_shutdown', false);
parent::setUp();
if (self::$index === null) {

View File

@ -1,74 +0,0 @@
<?php
namespace SilverStripe\FullTextSearch\Tests;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\FullTextSearch\Search\Indexes\SearchIndex_Recording;
use SilverStripe\FullTextSearch\Tests\SearchVariantSiteTreeSubsitesPolyhomeTest\SearchVariantSiteTreeSubsitesPolyhomeTest_Index;
use SilverStripe\FullTextSearch\Tests\SearchVariantSiteTreeSubsitesPolyhomeTest\SearchVariantSiteTreeSubsitesPolyhomeTest_Item;
class SearchVariantSiteTreeSubsitesPolyhomeTest extends SapphireTest
{
private static $index = null;
private static $subsite_a = null;
private static $subsite_b = null;
public function setUp()
{
parent::setUp();
// Check subsites installed
if (!class_exists('Subsite') || !class_exists('SubsitePolyhome')) {
return $this->markTestSkipped('The subsites polyhome module is not installed');
}
if (self::$index === null) {
self::$index = singleton('SearchVariantSiteTreeSubsitesPolyhomeTest_Index');
}
if (self::$subsite_a === null) {
self::$subsite_a = new Subsite();
self::$subsite_a->write();
self::$subsite_b = new Subsite();
self::$subsite_b->write();
}
FullTextSearch::force_index_list(self::$index);
SearchUpdater::clear_dirty_indexes();
}
public function testSavingDirect()
{
// Initial add
$item = new SearchVariantSiteTreeSubsitesPolyhomeTest_Item();
$item->write();
SearchUpdater::flush_dirty_indexes();
$this->assertEquals(self::$index->getAdded(array('ID', '_subsite')), array(
array('ID' => $item->ID, '_subsite' => 0)
));
// Check that adding to subsites works
self::$index->reset();
$item->setField('AddToSubsite[0]', 1);
$item->setField('AddToSubsite['.(self::$subsite_a->ID).']', 1);
$item->write();
SearchUpdater::flush_dirty_indexes();
$this->assertEquals(self::$index->getAdded(array('ID', '_subsite')), array(
array('ID' => $item->ID, '_subsite' => 0),
array('ID' => $item->ID, '_subsite' => self::$subsite_a->ID)
));
$this->assertEquals(self::$index->deleted, array(
array('base' => 'SiteTree', 'id' => $item->ID, 'state' => array(
'SearchVariantVersioned' => 'Stage', 'SearchVariantSiteTreeSubsitesPolyhome' => self::$subsite_b->ID
))
));
}
}

View File

@ -1,14 +0,0 @@
<?php
namespace SilverStripe\FullTextSearch\Tests\SearchVariantSiteTreeSubsitesPolyhomeTest;
use SilverStripe\FullTextSearch\Search\Indexes\SearchIndex_Recording;
class SearchVariantSiteTreeSubsitesPolyhomeTest_Index extends SearchIndex_Recording
{
public function init()
{
$this->addClass(SearchVariantSiteTreeSubsitesPolyhomeTest_Item::class);
$this->addFilterField('TestText');
}
}

View File

@ -1,15 +0,0 @@
<?php
namespace SilverStripe\FullTextSearch\Tests\SearchVariantSiteTreeSubsitesPolyhomeTest;
use SilverStripe\CMS\Model\SiteTree;
class SearchVariantSiteTreeSubsitesPolyhomeTest_Item extends SiteTree
{
private static $table_name = 'SearchVariantSiteTreeSubsitesPolyhomeTest_Item';
// TODO: Currently theres a failure if you addClass a non-table class
private static $db = array(
'TestText' => 'Varchar'
);
}

View File

@ -2,32 +2,40 @@
namespace SilverStripe\FullTextSearch\Tests;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\FullTextSearch\Search\FullTextSearch;
use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateProcessor;
use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;
use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater;
use SilverStripe\FullTextSearch\Search\Variants\SearchVariantSubsites;
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container;
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_FakeIndex;
use SilverStripe\Subsites\Model\Subsite;
class SearchVariantSubsiteTest extends SapphireTest
{
private static $index = null;
public function setUp()
protected function setUp()
{
parent::setUp();
// Check versioned available
if (!class_exists('Subsite')) {
if (!class_exists(Subsite::class)) {
return $this->markTestSkipped('The subsites module is not installed');
}
if (self::$index === null) {
self::$index = singleton('SearchVariantSubsiteTest');
self::$index = singleton(static::class);
}
SearchUpdater::bind_manipulation_capture();
Config::inst()->update('Injector', 'SearchUpdateProcessor', array(
'class' => 'SearchUpdateImmediateProcessor'
));
Config::modify()->set(Injector::class, SearchUpdateProcessor::class, [
'class' => SearchUpdateImmediateProcessor::class
]);
FullTextSearch::force_index_list(self::$index);
SearchUpdater::clear_dirty_indexes();
@ -41,13 +49,13 @@ class SearchVariantSubsiteTest extends SapphireTest
//typical behaviour: nobody is explicitly filtering on subsite, so the search variant adds a filter to the query
$this->assertArrayNotHasKey('_subsite', $query->require);
$variant = new SearchVariantSubsites();
$variant->alterDefinition('SearchUpdaterTest_Container', $index);
$variant->alterDefinition(SearchUpdaterTest_Container::class, $index);
$variant->alterQuery($query, $index);
//check that the "default" query has been put in place: it's not empty, and we're searching on Subsite ID:0 and
// an object of SearchQuery::missing
$this->assertNotEmpty($query->require['_subsite']);
$this->assertEquals(0, $query->require['_subsite'][0]);
$this->assertEmpty($query->require['_subsite'][0]);
//check that SearchQuery::missing is set (by default, it is an object of stdClass)
$this->assertInstanceOf('stdClass', $query->require['_subsite'][1]);
@ -71,7 +79,7 @@ class SearchVariantSubsiteTest extends SapphireTest
//apply the search variant's definition and query
$variant = new SearchVariantSubsites();
$variant->alterDefinition('SearchUpdaterTest_Container', $index);
$variant->alterDefinition(SearchUpdaterTest_Container::class, $index);
//the protected function isFieldFiltered is implicitly tested here
$variant->alterQuery($query, $index);

View File

@ -28,8 +28,6 @@ class SearchVariantVersionedTest extends SapphireTest
protected function setUp()
{
Config::modify()->set(SearchUpdater::class, 'flush_on_shutdown', false);
parent::setUp();
if (self::$index === null) {
@ -130,4 +128,15 @@ class SearchVariantVersionedTest extends SapphireTest
array('ID' => $item->ID, '_versionedstage' => 'Live')
), $index->getAdded(array('ID', '_versionedstage')));
}
public function testCanBeDisabledViaConfig()
{
$variant = new SearchVariantVersioned;
Config::modify()->set(SearchVariantVersioned::class, 'enabled', true);
$this->assertTrue($variant->appliesToEnvironment());
Config::modify()->set(SearchVariantVersioned::class, 'enabled', false);
$this->assertFalse($variant->appliesToEnvironment());
}
}

View File

@ -2,20 +2,32 @@
namespace SilverStripe\FullTextSearch\Tests;
use Apache_Solr_Document;
use Page;
use SilverStripe\Assets\File;
use SilverStripe\Assets\Image;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\FullTextSearch\Search\FullTextSearch;
use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateImmediateProcessor;
use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateProcessor;
use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater;
use SilverStripe\FullTextSearch\Search\Variants\SearchVariantSubsites;
use SilverStripe\FullTextSearch\Solr\Services\Solr4Service;
use SilverStripe\FullTextSearch\Tests\SolrIndexSubsitesTest\SolrIndexSubsitesTest_Index;
if (class_exists('\Phockito')) {
\Phockito::include_hamcrest(false);
}
use SilverStripe\FullTextSearch\Tests\SolrIndexVersionedTest\SolrDocumentMatcher;
use SilverStripe\ORM\DataObject;
use SilverStripe\Subsites\Model\Subsite;
use SilverStripe\Versioned\Versioned;
/**
* Subsite specific solr testing
*/
class SolrIndexSubsitesTest extends SapphireTest
{
// @todo
// protected static $fixture_file = 'SolrIndexSubsitesTest/SolrIndexSubsitesTest.yml';
protected static $fixture_file = 'SolrIndexSubsitesTest/SolrIndexSubsitesTest.yml';
/**
* @var SolrIndexSubsitesTest_Index
@ -26,31 +38,28 @@ class SolrIndexSubsitesTest extends SapphireTest
protected function setUp()
{
// Prevent parent::setUp() crashing on db build
if (!class_exists(Subsite::class)) {
static::$fixture_file = null;
}
parent::setUp();
// Prevent parent::setUp() crashing on db build
if (!class_exists('Subsite')) {
$this->skipTest = true;
if (!class_exists(Subsite::class)) {
$this->markTestSkipped("These tests need the Subsite module installed to run");
}
$this->server = $_SERVER;
if (!class_exists('\Phockito')) {
$this->skipTest = true;
$this->markTestSkipped("These tests need the \Phockito module installed to run");
return;
}
if (self::$index === null) {
self::$index = singleton('SolrIndexSubsitesTest_Index');
self::$index = singleton(SolrIndexSubsitesTest_Index::class);
}
SearchUpdater::bind_manipulation_capture();
Config::modify()->set('Injector', 'SearchUpdateProcessor', array(
'class' => 'SearchUpdateImmediateProcessor'
));
Config::modify()->set(Injector::class, SearchUpdateProcessor::class, [
'class' => SearchUpdateImmediateProcessor::class,
]);
FullTextSearch::force_index_list(self::$index);
SearchUpdater::clear_dirty_indexes();
@ -67,7 +76,9 @@ class SolrIndexSubsitesTest extends SapphireTest
protected function getServiceMock()
{
return \Phockito::mock('Solr4Service');
return $this->getMockBuilder(Solr4Service::class)
->setMethods(['addDocument', 'commit'])
->getMock();
}
/**
@ -83,7 +94,9 @@ class SolrIndexSubsitesTest extends SapphireTest
$variants = array();
// Check subsite
if (class_exists('Subsite') && DataObject::getSchema()->hasOneComponent($object->getClassName(), 'Subsite')) {
if (class_exists(Subsite::class)
&& DataObject::getSchema()->hasOneComponent($object->getClassName(), 'Subsite')
) {
$variants[] = '"SearchVariantSubsites":"' . $subsiteID. '"';
}
@ -91,7 +104,7 @@ class SolrIndexSubsitesTest extends SapphireTest
if ($stage) {
$variants[] = '"SearchVariantVersioned":"' . $stage . '"';
}
return $id.'-'.$class.'-{'.implode(',', $variants).'}';
return $id . '-' . $class . '-{' . implode(',', $variants) . '}';
}
public function testPublishing()
@ -100,146 +113,163 @@ class SolrIndexSubsitesTest extends SapphireTest
$serviceMock = $this->getServiceMock();
self::$index->setService($serviceMock);
$subsite1 = $this->objFromFixture('Subsite', 'subsite1');
$subsite1 = $this->objFromFixture(Subsite::class, 'subsite1');
// Add records to first subsite
Versioned::reading_stage('Stage');
Versioned::set_stage(Versioned::DRAFT);
$_SERVER['HTTP_HOST'] = 'www.subsite1.com';
\Phockito::reset($serviceMock);
$file = new File();
$file->Title = 'My File';
$file->SubsiteID = $subsite1->ID;
$file->write();
$page = new Page();
$page->Title = 'My Page';
$page->SubsiteID = $subsite1->ID;
$page->write();
SearchUpdater::flush_dirty_indexes();
$doc1 = new SolrDocumentMatcher(array(
$doc1 = new Apache_Solr_Document([
'_documentid' => $this->getExpectedDocumentId($page, $subsite1->ID, 'Stage'),
'ClassName' => 'Page',
'SiteTree_Title' => 'My Page',
'_versionedstage' => 'Stage',
'_subsite' => $subsite1->ID
));
$doc2 = new SolrDocumentMatcher(array(
'_subsite' => $subsite1->ID,
]);
$doc2 = new Apache_Solr_Document([
'_documentid' => $this->getExpectedDocumentId($file, $subsite1->ID),
'ClassName' => 'File',
'ClassName' => File::class,
'File_Title' => 'My File',
'_subsite' => $subsite1->ID
));
\Phockito::verify($serviceMock)->addDocument($doc1);
\Phockito::verify($serviceMock)->addDocument($doc2);
'_subsite' => $subsite1->ID,
]);
$serviceMock
->expects($this->exactly(2))
->method('addDocument')
->withConsecutive($doc1, $doc2);
SearchUpdater::flush_dirty_indexes();
}
public function testCorrectSubsiteIDOnPageWrite()
{
$mockWrites = array(
'3367:SiteTree:a:1:{s:22:"SearchVariantVersioned";s:4:"Live";}' => array(
'base' => 'SiteTree',
$mockWrites = [
'3367:SiteTree:a:1:{s:22:"SearchVariantVersioned";s:4:"Live";}' => [
'base' => 'SilverStripe\\CMS\\Model\\SiteTree',
'class' => 'Page',
'id' => 3367,
'statefulids' => array(
array(
'statefulids' => [
[
'id' => 3367,
'state' => array(
'state' => [
'SearchVariantVersioned' => 'Live',
),
),
),
'fields' => array(
'SiteTree:ClassName' => 'Page',
'SiteTree:LastEdited' => '2016-12-08 23:55:30',
'SiteTree:Created' => '2016-11-30 05:23:58',
'SiteTree:URLSegment' => 'test',
'SiteTree:Title' => 'Test Title',
'SiteTree:Content' => '<p>test content</p>',
'SiteTree:MetaDescription' => 'a solr test',
'SiteTree:ShowInMenus' => 1,
'SiteTree:ShowInSearch' => 1,
'SiteTree:Sort' => 77,
'SiteTree:HasBrokenFile' => 0,
'SiteTree:HasBrokenLink' => 0,
'SiteTree:CanViewType' => 'Inherit',
'SiteTree:CanEditType' => 'Inherit',
'SiteTree:Locale' => 'en_NZ',
'SiteTree:SubsiteID' => 0,
],
],
],
'fields' => [
'SilverStripe\\CMS\\Model\\SiteTree:ClassName' => 'Page',
'SilverStripe\\CMS\\Model\\SiteTree:LastEdited' => '2016-12-08 23:55:30',
'SilverStripe\\CMS\\Model\\SiteTree:Created' => '2016-11-30 05:23:58',
'SilverStripe\\CMS\\Model\\SiteTree:URLSegment' => 'test',
'SilverStripe\\CMS\\Model\\SiteTree:Title' => 'Test Title',
'SilverStripe\\CMS\\Model\\SiteTree:Content' => '<p>test content</p>',
'SilverStripe\\CMS\\Model\\SiteTree:MetaDescription' => 'a solr test',
'SilverStripe\\CMS\\Model\\SiteTree:ShowInMenus' => 1,
'SilverStripe\\CMS\\Model\\SiteTree:ShowInSearch' => 1,
'SilverStripe\\CMS\\Model\\SiteTree:Sort' => 77,
'SilverStripe\\CMS\\Model\\SiteTree:HasBrokenFile' => 0,
'SilverStripe\\CMS\\Model\\SiteTree:HasBrokenLink' => 0,
'SilverStripe\\CMS\\Model\\SiteTree:CanViewType' => 'Inherit',
'SilverStripe\\CMS\\Model\\SiteTree:CanEditType' => 'Inherit',
'SilverStripe\\CMS\\Model\\SiteTree:Locale' => 'en_NZ',
'SilverStripe\\CMS\\Model\\SiteTree:SubsiteID' => 0,
'Page:ID' => 3367,
'Page:MetaKeywords' => null,
),
),
);
],
],
];
$variant = new SearchVariantSubsites();
$tmpMockWrites = $mockWrites;
$variant->extractManipulationWriteState($tmpMockWrites);
foreach ($tmpMockWrites as $mockWrite) {
$this->assertCount(1, $mockWrite['statefulids']);
$statefulIDs = array_shift($mockWrite['statefulids']);
$this->assertEquals(0, $statefulIDs['state']['SearchVariantSubsites']);
$this->assertArrayHasKey(SearchVariantSubsites::class, $statefulIDs['state']);
$this->assertEquals(0, $statefulIDs['state'][SearchVariantSubsites::class]);
}
$subsite = $this->objFromFixture('Subsite', 'subsite1');
$subsite = $this->objFromFixture(Subsite::class, 'subsite1');
$tmpMockWrites = $mockWrites;
$tmpMockWrites['3367:SiteTree:a:1:{s:22:"SearchVariantVersioned";s:4:"Live";}']['fields']['SiteTree:SubsiteID'] = $subsite->ID;
$tmpMockWrites['3367:SiteTree:a:1:{s:22:"SearchVariantVersioned";s:4:"Live";}']['fields'][SiteTree::class . ':SubsiteID'] = $subsite->ID;
$variant->extractManipulationWriteState($tmpMockWrites);
foreach ($tmpMockWrites as $mockWrite) {
$this->assertCount(1, $mockWrite['statefulids']);
$statefulIDs = array_shift($mockWrite['statefulids']);
$this->assertEquals($subsite->ID, $statefulIDs['state']['SearchVariantSubsites']);
$this->assertArrayHasKey(SearchVariantSubsites::class, $statefulIDs['state']);
$this->assertEquals($subsite->ID, $statefulIDs['state'][SearchVariantSubsites::class]);
}
}
public function testCorrectSubsiteIDOnFileWrite()
{
$subsiteIDs = array('0') + $this->allFixtureIDs('Subsite');
$mockWrites = array(
'35910:File:a:0:{}' => array(
'base' => 'File',
'class' => 'File',
$subsiteIDs = ['0'] + $this->allFixtureIDs(Subsite::class);
$mockWrites = [
'35910:File:a:0:{}' => [
'base' => File::class,
'class' => File::class,
'id' => 35910,
'statefulids' => array(
array(
'statefulids' => [
[
'id' => 35910,
'state' => array(),
),
),
'fields' => array(
'File:ClassName' => 'Image',
'File:ShowInSearch' => 1,
'File:ParentID' => 26470,
'File:Filename' => 'assets/Uploads/pic.jpg',
'File:Name' => 'pic.jpg',
'File:Title' => 'pic',
'File:SubsiteID' => 0,
'File:OwnerID' => 661,
'File:CurrentVersionID' => 22038,
'File:LastEdited' => '2016-12-09 00:35:13',
),
),
);
'state' => [],
],
],
'fields' => [
File::class . ':ClassName' => Image::class,
File::class . ':ShowInSearch' => 1,
File::class . ':ParentID' => 26470,
File::class . ':Filename' => 'assets/Uploads/pic.jpg',
File::class . ':Name' => 'pic.jpg',
File::class . ':Title' => 'pic',
File::class . ':SubsiteID' => 0,
File::class . ':OwnerID' => 661,
File::class . ':CurrentVersionID' => 22038,
File::class . ':LastEdited' => '2016-12-09 00:35:13',
],
],
];
$variant = new SearchVariantSubsites();
$tmpMockWrites = $mockWrites;
$variant->extractManipulationWriteState($tmpMockWrites);
foreach ($tmpMockWrites as $mockWrite) {
$this->assertCount(count($subsiteIDs), $mockWrite['statefulids']);
foreach ($mockWrite['statefulids'] as $statefulIDs) {
$this->assertTrue(
in_array($statefulIDs['state']['SearchVariantSubsites'], $subsiteIDs),
sprintf('Failed to assert that %s is in list of valid subsites: %s', $statefulIDs['state']['SearchVariantSubsites'], implode(', ', $subsiteIDs))
$this->assertContains(
$statefulIDs['state'][SearchVariantSubsites::class],
$subsiteIDs,
sprintf(
'Failed to assert that %s is in list of valid subsites: %s',
$statefulIDs['state'][SearchVariantSubsites::class],
implode(', ', $subsiteIDs)
)
);
}
}
$subsite = $this->objFromFixture('Subsite', 'subsite1');
$subsite = $this->objFromFixture(Subsite::class, 'subsite1');
$tmpMockWrites = $mockWrites;
$tmpMockWrites['35910:File:a:0:{}']['fields']['File:SubsiteID'] = $subsite->ID;
$tmpMockWrites['35910:File:a:0:{}']['fields'][File::class . ':SubsiteID'] = $subsite->ID;
$variant->extractManipulationWriteState($tmpMockWrites);
foreach ($tmpMockWrites as $mockWrite) {
$this->assertCount(1, $mockWrite['statefulids']);
$statefulIDs = array_shift($mockWrite['statefulids']);
$this->assertEquals($subsite->ID, $statefulIDs['state']['SearchVariantSubsites']);
$this->assertEquals($subsite->ID, $statefulIDs['state'][SearchVariantSubsites::class]);
}
}
}

View File

@ -1,16 +1,17 @@
Subsite:
SilverStripe\Subsites\Model\Subsite:
main:
Title: Template
subsite1:
Title: 'Subsite1 Template'
subsite2:
Title: 'Subsite2 Template'
SubsiteDomain:
SilverStripe\Subsites\Model\SubsiteDomain:
subsite1:
SubsiteID: =>Subsite.subsite1
SubsiteID: =>SilverStripe\Subsites\Model\Subsite.subsite1
Domain: www.subsite1.com
Protocol: automatic
subsite2:
SubsiteID: =>Subsite.subsite2
SubsiteID: =>SilverStripe\Subsites\Model\Subsite.subsite2
Domain: www.subsite2.com
Protocol: automatic

View File

@ -2,9 +2,9 @@
namespace SilverStripe\FullTextSearch\Tests\SolrIndexSubsitesTest;
use SilverStripe\FullTextSearch\Solr\SolrIndex;
use SilverStripe\Assets\File;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\FullTextSearch\Solr\SolrIndex;
class SolrIndexSubsitesTest_Index extends SolrIndex
{

View File

@ -7,18 +7,20 @@ use SilverStripe\Core\Environment;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Kernel;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_AmbiguousRelationIndex;
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_AmbiguousRelationInheritedIndex;
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_FakeIndex;
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_FakeIndex2;
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_BoostedIndex;
use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;
use SilverStripe\FullTextSearch\Search\Variants\SearchVariantSubsites;
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\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_OtherContainer;
use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;
use SilverStripe\FullTextSearch\Solr\Services\Solr3Service;
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_AmbiguousRelationIndex;
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_AmbiguousRelationInheritedIndex;
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_BoostedIndex;
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_FakeIndex;
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_FakeIndex2;
use SilverStripe\Subsites\Model\Subsite;
class SolrIndexTest extends SapphireTest
{
@ -151,6 +153,10 @@ class SolrIndexTest extends SapphireTest
*/
public function testBoostedField()
{
if (class_exists(Subsite::class)) {
Config::modify()->set(SearchVariantSubsites::class, 'enabled', false);
}
/** @var Solr3Service|PHPUnit_Framework_MockObject_MockObject $serviceMock */
$serviceMock = $this->getMockBuilder(Solr3Service::class)
->setMethods(['search'])
@ -162,8 +168,11 @@ class SolrIndexTest extends SapphireTest
$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->equalTo([
'qf' => SearchUpdaterTest_Container::class . '_Field1^1.5 '
. SearchUpdaterTest_Container::class . '_Field2^2.1 _text',
'fq' => '+(_versionedstage:"" (*:* -_versionedstage:[* TO *]))',
]),
$this->anything()
)->willReturn($this->getFakeRawSolrResponse());

View File

@ -2,8 +2,10 @@
namespace SilverStripe\FullTextSearch\Tests;
use Apache_Solr_Document;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\DataObject;
use SilverStripe\FullTextSearch\Search\FullTextSearch;
use SilverStripe\FullTextSearch\Search\SearchIntrospection;
@ -15,23 +17,28 @@ use SilverStripe\FullTextSearch\Tests\SolrIndexVersionedTest\SolrVersionedTest_I
use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateProcessor;
use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateImmediateProcessor;
use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater;
use SilverStripe\FullTextSearch\Search\Variants\SearchVariantSubsites;
use SilverStripe\FullTextSearch\Search\Variants\SearchVariantVersioned;
use SilverStripe\Subsites\Model\Subsite;
use SilverStripe\Versioned\Versioned;
class SolrIndexVersionedTest extends SapphireTest
{
protected $usesDatabase = true;
protected $oldMode = null;
protected static $index = null;
protected static $extra_dataobjects = array(
protected static $extra_dataobjects = [
SearchVariantVersionedTest_Item::class,
SolrIndexVersionedTest_Object::class
);
SolrIndexVersionedTest_Object::class,
];
protected function setUp()
{
Config::modify()->set(SearchUpdater::class, 'flush_on_shutdown', false);
// Need to be set before parent::setUp() since they're executed before the tests start
Config::modify()->set(SearchVariantSubsites::class, 'enabled', false);
parent::setUp();
@ -41,18 +48,18 @@ class SolrIndexVersionedTest extends SapphireTest
SearchUpdater::bind_manipulation_capture();
Config::modify()->set(Injector::class, SearchUpdateProcessor::class, array(
Config::modify()->set(Injector::class, SearchUpdateProcessor::class, [
'class' => SearchUpdateImmediateProcessor::class
));
]);
FullTextSearch::force_index_list(self::$index);
SearchUpdater::clear_dirty_indexes();
$this->oldMode = Versioned::get_reading_mode();
Versioned::set_stage('Stage');
Versioned::set_stage(Versioned::DRAFT);
}
public function tearDown()
protected function tearDown()
{
Versioned::set_reading_mode($this->oldMode);
parent::tearDown();
@ -80,13 +87,7 @@ class SolrIndexVersionedTest extends SapphireTest
{
$id = $object->ID;
$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') && DataObject::getSchema()->hasOneComponent($object->getClassName(), 'Subsite')) {
$subsites = '"SearchVariantSubsites":"0",';
}
return $id.'-'.$class.'-{'.$subsites. json_encode(SearchVariantVersioned::class) . ':"'.$stage.'"}';
return $id.'-'.$class.'-{'.json_encode(SearchVariantVersioned::class).':"'.$stage.'"}';
}
/**
@ -98,12 +99,12 @@ class SolrIndexVersionedTest extends SapphireTest
*/
protected function getSolrDocument($class, $object, $value, $stage)
{
$doc = new \Apache_Solr_Document();
$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('ID', (int) $object->ID);
$doc->setField('ClassHierarchy', SearchIntrospection::hierarchy($class));
$doc->setFieldBoost('ID', false);
$doc->setFieldBoost('ClassHierarchy', false);
@ -114,89 +115,52 @@ class SolrIndexVersionedTest extends SapphireTest
public function testPublishing()
{
// Check that write updates Stage
Versioned::set_stage('Stage');
Versioned::set_stage(Versioned::DRAFT);
$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');
$doc1 = $this->getSolrDocument(SearchVariantVersionedTest_Item::class, $item, 'Foo', Versioned::DRAFT);
$doc2 = $this->getSolrDocument(SolrIndexVersionedTest_Object::class, $object, 'Bar', Versioned::DRAFT);
// 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()
]
[$this->equalTo($doc1)],
[$this->equalTo($doc2)]
);
SearchUpdater::flush_dirty_indexes();
// Check that write updates Live
Versioned::set_stage('Stage');
Versioned::set_stage(Versioned::DRAFT);
$item = new SearchVariantVersionedTest_Item(array('TestText' => 'Foo'));
$item->write();
$item->copyVersionToStage('Stage', 'Live');
$item->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
$object = new SolrIndexVersionedTest_Object(array('TestText' => 'Bar'));
$object->write();
$object->copyVersionToStage('Stage', 'Live');
$object->copyVersionToStage(Versioned::DRAFT, Versioned::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');
$doc1 = $this->getSolrDocument(SearchVariantVersionedTest_Item::class, $item, 'Foo', Versioned::DRAFT);
$doc2 = $this->getSolrDocument(SearchVariantVersionedTest_Item::class, $item, 'Foo', Versioned::LIVE);
$doc3 = $this->getSolrDocument(SolrIndexVersionedTest_Object::class, $object, 'Bar', Versioned::DRAFT);
$doc4 = $this->getSolrDocument(SolrIndexVersionedTest_Object::class, $object, 'Bar', Versioned::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()
]
[$doc1],
[$doc2],
[$doc3],
[$doc4]
);
SearchUpdater::flush_dirty_indexes();
@ -205,12 +169,12 @@ class SolrIndexVersionedTest extends SapphireTest
public function testDelete()
{
// Delete the live record (not the stage)
Versioned::set_stage('Stage');
Versioned::set_stage(Versioned::DRAFT);
$item = new SearchVariantVersionedTest_Item(array('TestText' => 'Too'));
$item->write();
$item->copyVersionToStage('Stage', 'Live');
Versioned::set_stage('Live');
$item->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
Versioned::set_stage(Versioned::LIVE);
$id = clone $item;
$item->delete();
@ -218,16 +182,16 @@ class SolrIndexVersionedTest extends SapphireTest
$this->getServiceMock(['addDocument', 'commit', 'deleteById'])
->expects($this->exactly(1))
->method('deleteById')
->with($this->equalTo($this->getExpectedDocumentId($id, 'Live')));
->with($this->getExpectedDocumentId($id, Versioned::LIVE));
SearchUpdater::flush_dirty_indexes();
// Delete the stage record
Versioned::set_stage('Stage');
Versioned::set_stage(Versioned::DRAFT);
$item = new SearchVariantVersionedTest_Item(array('TestText' => 'Too'));
$item->write();
$item->copyVersionToStage('Stage', 'Live');
$item->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
$id = clone $item;
$item->delete();
@ -235,7 +199,7 @@ class SolrIndexVersionedTest extends SapphireTest
$this->getServiceMock(['addDocument', 'commit', 'deleteById'])
->expects($this->exactly(1))
->method('deleteById')
->with($this->equalTo($this->getExpectedDocumentId($id, 'Stage')));
->with($this->getExpectedDocumentId($id, Versioned::DRAFT));
SearchUpdater::flush_dirty_indexes();
}

View File

@ -1,39 +0,0 @@
<?php
namespace SilverStripe\FullTextSearch\Tests\SolrIndexVersionedTest;
if (!class_exists('\Phockito')) {
return;
}
\Phockito::include_hamcrest(false);
class SolrDocumentMatcher extends \Hamcrest_BaseMatcher
{
protected $properties;
public function __construct($properties)
{
$this->properties = $properties;
}
public function describeTo(\Hamcrest_Description $description)
{
$description->appendText('\Apache_Solr_Document with properties '.var_export($this->properties, true));
}
public function matches($item)
{
if (! ($item instanceof \Apache_Solr_Document)) {
return false;
}
foreach ($this->properties as $key => $value) {
if ($item->{$key} != $value) {
return false;
}
}
return true;
}
}

View File

@ -49,17 +49,13 @@ class SolrReindexQueuedTest extends SapphireTest
protected function setUp()
{
Config::modify()->set(SearchUpdater::class, 'flush_on_shutdown', false);
parent::setUp();
if (!interface_exists('Symbiote\QueuedJobs\Services\QueuedJob')) {
if (!interface_exists(QueuedJob::class)) {
$this->skipTest = true;
return $this->markTestSkipped("These tests need the QueuedJobs module installed to run");
}
Config::modify()->set(QueuedJobService::class, 'use_shutdown_function', false);
// Set queued handler for reindex
Config::modify()->set(Injector::class, SolrReindexHandler::class, array(
'class' => SolrReindexQueuedHandler::class

View File

@ -43,8 +43,6 @@ class SolrReindexTest extends SapphireTest
protected function setUp()
{
Config::modify()->set(SearchUpdater::class, 'flush_on_shutdown', false);
parent::setUp();
// Set test handler for reindex

View File

@ -0,0 +1,37 @@
<?php
namespace SilverStripe\FullTextSearch\Tests\State;
use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Dev\State\TestState;
use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater;
use SilverStripe\FullTextSearch\Search\Variants\SearchVariant;
use Symbiote\QueuedJobs\Services\QueuedJobService;
class FullTextSearchState implements TestState
{
public function setUp(SapphireTest $test)
{
// noop
}
public function tearDown(SapphireTest $test)
{
SearchVariant::clear_variant_cache();
}
public function setUpOnce($class)
{
Config::modify()->set(SearchUpdater::class, 'flush_on_shutdown', false);
if (class_exists(QueuedJobService::class)) {
Config::modify()->set(QueuedJobService::class, 'use_shutdown_function', false);
}
}
public function tearDownOnce($class)
{
// noop
}
}