diff --git a/composer.json b/composer.json index 6b99f08f..c7cee24e 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "semsol/arc2": "v2.2.4", "chrisboulton/php-resque": "dev-master#98fde571db008a8b48e73022599d1d1c07d4a7b5", - "monolog/monolog" : "1.13.1" + "monolog/monolog" : "~1.13" }, "require-dev": { "phpunit/phpunit": "4.1.*" diff --git a/src/IDriver.php b/src/IDriver.php index 70d547a2..a0b5c32d 100644 --- a/src/IDriver.php +++ b/src/IDriver.php @@ -8,44 +8,177 @@ */ interface IDriver { - // graph functions - - public function graph($query,$includeProperties=array()); - /** - * @deprecated - * @abstract - * @param $query + * Equivalent to CONSTRUCT + * @param array $filter conditions to filter by + * @param array $includeProperties only include these predicates, empty array means return all predicates * @return mixed */ - public function describe($query); + public function graph($filter,$includeProperties=array()); + + /** + * Return (DESCRIBE) the concise bound description of a resource + * @param string $resource uri resource you'd like to describe + * @param null|string $context string uri of the context, or named graph, you'd like to describe from + * @return ExtendedGraph + */ public function describeResource($resource,$context=null); + + /** + * Return (DESCRIBE) the concise bound descriptions of a bunch of resources + * @param array $resources uris of resources you'd like to describe + * @param null|string $context string uri of the context, or named graph, you'd like to describe from + * @return ExtendedGraph + */ public function describeResources(Array $resources,$context=null); + /** + * Get a view of a given type for a given resource + * @param string $resource uri of the resource you'd like the view for + * @param string $viewType string type of view + * @return ExtendedGraph + */ public function getViewForResource($resource,$viewType); + + /** + * Get views for multiple resources in one graph + * @param array $resources uris of resources you'd like to describe + * @param string $viewType type of view + * @return ExtendedGraph + */ public function getViewForResources(Array $resources,$viewType); + + /** + * Get views based on a pattern-match $filter + * @param array $filter pattern to match to select views + * @param string $viewType type of view + * @return ExtendedGraph + */ public function getViews(Array $filter,$viewType); + /** + * Returns the etag of a resource, useful for caching + * @param string $resource + * @param null|string $context + * @return string + */ public function getETag($resource,$context=null); - // tabular functions - - public function select($query,$fields,$sortBy=null,$limit=null,$context=null); + /** + * Select data in a tabular format + * @param array $filter pattern to match to select views + * @param $fields + * @param null $sortBy + * @param null $limit + * @param null $context + * @return array + */ + public function select($filter,$fields,$sortBy=null,$limit=null,$context=null); + /** + * Select data from a table + * @param $tableType + * @param array $filter + * @param array $sortBy + * @param int $offset + * @param int $limit + * @return array + */ public function getTableRows($tableType,$filter=array(),$sortBy=array(),$offset=0,$limit=10); - public function generateTableRows($tableType,$resource=null,$context=null); + /** + * todo: work out what this does + * @param $tableType + * @param $fieldName + * @param array $filter + * @return array + */ public function getDistinctTableColumnValues($tableType, $fieldName, array $filter = array()); - // aggregate, save and search functions + /** + * Get a count of resources matching the pattern in $query. Optionally group counts by specifying a $groupBy predicate + * @param $query + * @param null|string $groupBy + * @return array|int multidimensional array with int values if grouped by, otherwise int + */ public function getCount($query,$groupBy=null); + /** + * Save the changes between $oldGraph -> $newGraph + * @param ExtendedGraph $oldGraph + * @param ExtendedGraph $newGraph + * @param null|string $context + * @param null|string $description + * @return bool true or throws exception on error + */ public function saveChanges(ExtendedGraph $oldGraph, ExtendedGraph $newGraph,$context=null,$description=null); + /** + * Register an event hook, which will be executed when the event fires. + * @param $eventType + * @param IEventHook $hook + */ + public function registerHook($eventType,IEventHook $hook); + + /* START Deprecated methods that will be removed in 1.x.x */ + + /** + * Return (DESCRIBE) according to a filter + * @deprecated Use graph() instead + * @param array $filter conditions to filter by + * @return ExtendedGraph + */ + public function describe($filter); + + /** + * Generates table rows + * @deprecated calling save will generate table rows - this method seems to be only used in tests and does not belong on the interface + * @param $tableType + * @param null|string $resource + * @param null|string $context + */ + public function generateTableRows($tableType,$resource=null,$context=null); + + /** + * Submits search params to configured search provider + * the params array must contain the following keys + * -q the query string to search for + * -type the search document type to restrict results to, in other words _id.type + * -indices an array of indices (from spec) to match query terms against, must specify at least one + * -fields an array of the fields (from spec) you want included in the search results, must specify at least one + * -limit integer the number of results to return per page + * -offset the offset to skip to when returning results + * + * this method looks for the above keys in the params array and naively passes them to the search provider which will + * throw SearchException if any of the params are invalid + * + * @deprecated Search will be removed from a future version of Tripod as its functionality is equivalent to tables + * @param Array $params + * @throws \Tripod\Exceptions\Exception - if search provider cannot be found + * @throws \Tripod\Exceptions\SearchException - if something goes wrong + * @return Array results + */ public function search(Array $params); + /** + * Get any documents that were left in a locked state + * @deprecated this is a feature of the mongo implementation - this method will move from the interface to the mongo-specific Driver class soon. + * @param null|string $fromDateTime strtotime compatible string + * @param null|string $tillDateTime strtotime compatible string + * @return array of locked documents + */ public function getLockedDocuments($fromDateTime =null , $tillDateTime = null); + /** + * Remove any inert locks left by a given transaction + * @deprecated this is a feature of the mongo implementation - this method will move from the interface to the mongo-specific Driver class soon. + * @param string $transaction_id + * @param string $reason + * @return bool true or throws exception on error + */ public function removeInertLocks($transaction_id, $reason); + + /* END Deprecated methods that will be removed in 1.x.x */ + } \ No newline at end of file diff --git a/src/IEventHook.php b/src/IEventHook.php new file mode 100644 index 00000000..a46da36c --- /dev/null +++ b/src/IEventHook.php @@ -0,0 +1,49 @@ +getDataUpdater()->replayTransactionLog($fromDate, $toDate); } + /** + * Register an event hook, which + * @param $eventType + * @param IEventHook $ + * @return mixed + */ + public function registerHook($eventType, IEventHook $hook) + { + switch ($eventType) { + case IEventHook::EVENT_SAVE_CHANGES: + $this->getDataUpdater()->registerSaveChangesEventHook($hook); + break; + default: + throw new Exception("Unrecognised type $eventType whilst registering event hook"); + } + } + + /** * For mocking * @return Config diff --git a/src/mongo/MongoGraph.class.php b/src/mongo/MongoGraph.class.php index 436131c9..f4924854 100644 --- a/src/mongo/MongoGraph.class.php +++ b/src/mongo/MongoGraph.class.php @@ -127,18 +127,25 @@ private function add_tarray_to_index($tarray) $predObjects = array(); foreach ($tarray as $key=>$value) { - if($key[0] != '_') + if (empty($key)) + { + throw new \Tripod\Exceptions\Exception("The predicate cannot be an empty string"); + } + else if($key[0] != '_') { $predicate = $this->qname_to_uri($key); $graphValueObject = $this->toGraphValueObject($value); // Only add if valid values have been found - if (!empty($graphValueObject)) { + if (!empty($graphValueObject)) + { $predObjects[$predicate] = $graphValueObject; } } - else if($key == "_id"){ + else if($key == "_id") + { // If the subject is invalid then throw an exception - if(!isset($value['r']) || !$this->isValidResource($value['r'])){ + if(!isset($value['r']) || !$this->isValidResource($value['r'])) + { throw new \Tripod\Exceptions\Exception("The subject cannot be an empty string"); } } diff --git a/src/mongo/base/DriverBase.class.php b/src/mongo/base/DriverBase.class.php index 9a4d6cd1..bf5f8ac7 100644 --- a/src/mongo/base/DriverBase.class.php +++ b/src/mongo/base/DriverBase.class.php @@ -7,6 +7,8 @@ $TOTAL_TIME=0; use Monolog\Logger; +use Tripod\Exceptions\Exception; +use Tripod\IEventHook; /** * Class DriverBase @@ -14,6 +16,13 @@ */ abstract class DriverBase { + /** + * constants for the supported hook functions that can be applied + */ + const HOOK_FN_PRE = "pre"; + const HOOK_FN_SUCCESS = "success"; + const HOOK_FN_FAILURE = "failure"; + /** * @var \MongoCollection */ @@ -376,6 +385,31 @@ protected function getCollection() return $this->collection; } + protected function applyHooks($fn,$hooks,$args=array()) + { + switch ($fn) { + case $this::HOOK_FN_PRE: + case $this::HOOK_FN_SUCCESS: + case $this::HOOK_FN_FAILURE: + break; + default: + throw new Exception("Invalid hook function $fn requested"); + } + foreach ($hooks as $hook) + { + try + { + /* @var $hook IEventHook */ + $hook->$fn($args); + } + catch (\Exception $e) + { + // don't let rabid hooks stop tripod + $this->getLogger()->error("Hook ".get_class($hook)." threw exception {$e->getMessage()}, continuing"); + } + } + } + } /** diff --git a/src/mongo/delegates/Tables.class.php b/src/mongo/delegates/Tables.class.php index 99b55ddf..50371571 100644 --- a/src/mongo/delegates/Tables.class.php +++ b/src/mongo/delegates/Tables.class.php @@ -252,6 +252,8 @@ public function getTableRows($tableSpecId,$filter=array(),$sortBy=array(),$offse $rows = array(); foreach ($results as $doc) { +// $log = new \Monolog\Logger("TEST"); +// $log->error("Doc",$doc); if (array_key_exists(_IMPACT_INDEX,$doc['value'])) unset($doc['value'][_IMPACT_INDEX]); // remove impact index from client $rows[] = $doc['value']; } @@ -509,16 +511,19 @@ public function generateTableRows($tableType,$resource=null,$context=null,$queue ); // ensure any custom view indexes - if (isset($tableSpec['ensureIndexes'])) + foreach (Config::getInstance()->getTableSpecifications($this->storeName) as $tSpec) { - foreach ($tableSpec['ensureIndexes'] as $ensureIndex) + if (isset($tSpec['ensureIndexes'])) { - $collection->ensureIndex( - $ensureIndex, - array( - 'background'=>1 - ) - ); + foreach ($tSpec['ensureIndexes'] as $ensureIndex) + { + $collection->ensureIndex( + $ensureIndex, + array( + 'background'=>1 + ) + ); + } } } diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index b70df06d..edf6d2de 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -2,6 +2,9 @@ namespace Tripod\Mongo; +use Tripod\Exceptions\Exception; +use Tripod\IEventHook; + require_once TRIPOD_DIR . 'mongo/Config.class.php'; /** @@ -68,6 +71,11 @@ class Updates extends DriverBase { */ protected $discoverImpactedSubjects; + /** + * @var array + */ + private $saveChangesHooks = array(); + /** * @param Driver $tripod * @param array $opts @@ -144,6 +152,12 @@ public function saveChanges( $context=null, $description=null) { + $this->applyHooks($this::HOOK_FN_PRE,$this->saveChangesHooks,array( + "pod"=>$this->getPodName(), + "oldGraph"=>$oldGraph, + "newGraph"=>$newGraph, + "context"=>$context + )); $this->setReadPreferenceToPrimary(); try{ $contextAlias = $this->getContextAlias($context); @@ -160,10 +174,17 @@ public function saveChanges( $args = array('before' => $oldIndex, 'after' => $newIndex, 'changeReason' => $description); $cs = new \Tripod\ChangeSet($args); + $subjectsAndPredicatesOfChange = array(); + $transaction_id = null; if ($cs->has_changes()) { // store the actual CBDs - $subjectsAndPredicatesOfChange = $this->storeChanges($cs, $contextAlias); + $result = $this->storeChanges($cs, $contextAlias); + if (!isset($result['subjectsAndPredicatesOfChange'])|| !isset($result['transaction_id'])) { + $this->errorLog("Result of storeChanges malformed, should have transaction_id and subjectsAndPredicatesOfChange array keys",array("result"=>$result)); + throw new Exception("Result of storeChanges malformed, should have transaction_id and subjectsAndPredicatesOfChange array keys"); + } + extract($result); // will unpack into $subjectsAndPredicatesOfChange // Process any syncronous operations $this->processSyncOperations($subjectsAndPredicatesOfChange,$contextAlias); @@ -171,10 +192,26 @@ public function saveChanges( // Schedule calculation of any async activity $this->queueAsyncOperations($subjectsAndPredicatesOfChange,$contextAlias); } + + $this->applyHooks($this::HOOK_FN_SUCCESS,$this->saveChangesHooks,array( + "pod"=>$this->getPodName(), + "oldGraph"=>$oldGraph, + "newGraph"=>$newGraph, + "context"=>$context, + "changeSet"=>$cs, + "subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange, + "transaction_id"=>$transaction_id + )); } catch(\Exception $e){ // ensure we reset the original read preference in the event of an exception $this->resetOriginalReadPreference(); + $this->applyHooks($this::HOOK_FN_FAILURE,$this->saveChangesHooks,array( + "pod"=>$this->getPodName(), + "oldGraph"=>$oldGraph, + "newGraph"=>$newGraph, + "context"=>$context + )); throw $e; } @@ -337,7 +374,7 @@ protected function storeChanges(\Tripod\ChangeSet $cs, $contextAlias) $this->timingLog(MONGO_WRITE, array('duration'=>$t->result(), 'subjectsOfChange'=>implode(", ",$subjectsOfChange))); $this->getStat()->timer(MONGO_WRITE.".{$this->getPodName()}",$t->result()); - return $changes['subjectsAndPredicatesOfChange']; + return $changes; } catch(\Exception $e) { @@ -596,7 +633,8 @@ protected function applyChangeSet(\Tripod\ChangeSet $cs, $originalCBDs, $context return array( 'newCBDs'=>$newCBDs, - 'subjectsAndPredicatesOfChange'=>$this->subjectsAndPredicatesOfChangeUrisToAliases($subjectsAndPredicatesOfChange) + 'subjectsAndPredicatesOfChange'=>$this->subjectsAndPredicatesOfChangeUrisToAliases($subjectsAndPredicatesOfChange), + 'transaction_id'=>$transaction_id ); } else @@ -1056,12 +1094,12 @@ protected function lockSingleDocument($s, $transaction_id, $contextAlias) { $countEntriesInLocksCollection = $this->getLocksCollection() ->count( - array( - _ID_KEY => array( - _ID_RESOURCE => $this->labeller->uri_to_alias($s), - _ID_CONTEXT => $contextAlias) - ) - ); + array( + _ID_KEY => array( + _ID_RESOURCE => $this->labeller->uri_to_alias($s), + _ID_CONTEXT => $contextAlias) + ) + ); if($countEntriesInLocksCollection > 0) //Subject is already locked return false; @@ -1204,6 +1242,14 @@ public function setTransactionLog(TransactionLog $transactionLog) $this->transactionLog = $transactionLog; } + /** + * Register save changes event hooks + * @param IEventHook $hook + */ + public function registerSaveChangesEventHook(IEventHook $hook) + { + $this->saveChangesHooks[] = $hook; + } /** * Saves a transaction diff --git a/src/mongo/providers/MongoSearchProvider.class.php b/src/mongo/providers/MongoSearchProvider.class.php index 614f0a8d..68680bcb 100644 --- a/src/mongo/providers/MongoSearchProvider.class.php +++ b/src/mongo/providers/MongoSearchProvider.class.php @@ -106,7 +106,7 @@ public function deleteDocument($resource, $context, $specId = array()) { return; } - $query[_ID_KEY . '.' . _ID_TYPE] = array('$in'=>$specId); + $query[_ID_KEY . '.' . _ID_TYPE] = array('$in'=>array_values($specId)); $searchTypes = $specId; } } diff --git a/src/tripod.inc.php b/src/tripod.inc.php index a63e7b12..6c374dd8 100644 --- a/src/tripod.inc.php +++ b/src/tripod.inc.php @@ -23,6 +23,7 @@ require_once TRIPOD_DIR . 'mongo/delegates/Views.class.php'; require_once TRIPOD_DIR . 'mongo/delegates/Tables.class.php'; require_once TRIPOD_DIR . 'mongo/delegates/SearchIndexer.class.php'; +require_once TRIPOD_DIR . 'IEventHook.php'; require_once TRIPOD_DIR . 'IDriver.php'; require_once TRIPOD_DIR.'classes/ChangeSet.class.php'; require_once TRIPOD_DIR.'classes/Labeller.class.php'; diff --git a/test/unit/mongo/MongoGraphTest.php b/test/unit/mongo/MongoGraphTest.php index 98243b98..1f0f484f 100644 --- a/test/unit/mongo/MongoGraphTest.php +++ b/test/unit/mongo/MongoGraphTest.php @@ -209,8 +209,8 @@ public function addTripodArrayContainingInvalidPredicates_Provider(){ */ public function testAddTripodArrayContainingEmptyPredicate() { - // An Uninitialized string offset should occur if an empty predicate is passed. - $this->setExpectedException("PHPUnit_Framework_Error"); + // Should not be able to label '' + $this->setExpectedException('\Tripod\Exceptions\Exception','The predicate cannot be an empty string'); $doc = array( "_id"=>array("r"=>"http://talisaspire.com/works/4d101f63c10a6-2", "c"=>"http://talisaspire.com/works/4d101f63c10a6-2"), "_version"=>0, diff --git a/test/unit/mongo/MongoTripodDriverTest.php b/test/unit/mongo/MongoTripodDriverTest.php index 9ea1ebf0..590977db 100755 --- a/test/unit/mongo/MongoTripodDriverTest.php +++ b/test/unit/mongo/MongoTripodDriverTest.php @@ -26,7 +26,7 @@ protected function setUp() // Stub ouf 'addToElastic' search to prevent writes into Elastic Search happening by default. $this->tripod = $this->getMock( '\Tripod\Mongo\Driver', - array('addToSearchIndexQueue'), + array('validateGraphCardinality'), array( 'CBD_testing', 'tripod_php_testing', @@ -937,7 +937,7 @@ public function testDiscoverImpactedSubjectsAreDoneAllOperationsASync() $mockTripodUpdates->expects($this->once()) ->method('storeChanges') - ->will($this->returnValue($subjectsAndPredicatesOfChange)); + ->will($this->returnValue(array("subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange,"transaction_id"=>"t1234"))); $mockTripod->expects($this->once()) ->method('getDataUpdater') @@ -1134,7 +1134,7 @@ public function testDiscoverImpactedSubjectsForDeletionsSyncOpsAreDoneAsyncJobSu $mockTripodUpdates->expects($this->once()) ->method('storeChanges') - ->will($this->returnValue($subjectsAndPredicatesOfChange)); + ->will($this->returnValue(array("subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange,"transaction_id"=>"t1234"))); $mockTripod->expects($this->exactly(2)) ->method('getComposite') @@ -1279,7 +1279,7 @@ public function testDiscoverImpactedSubjectsForDefaultOperationsSetting() $mockTripodUpdates->expects($this->once()) ->method('storeChanges') - ->will($this->returnValue($subjectsAndPredicatesOfChange)); + ->will($this->returnValue(array("subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange,"transaction_id"=>"t1234"))); $mockTripod->expects($this->once()) ->method('getDataUpdater') @@ -1429,7 +1429,7 @@ public function testSpecifyQueueForAsyncOperations() $mockTripodUpdates->expects($this->once()) ->method('storeChanges') - ->will($this->returnValue($subjectsAndPredicatesOfChange)); + ->will($this->returnValue(array("subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange,"transaction_id"=>"t1234"))); $mockTripod->expects($this->once()) ->method('getDataUpdater') @@ -1975,6 +1975,114 @@ public function testRemoveInertLocks() $this->assertEquals(0, count($docs)); } - /** END: removeInertLocks tests */ + + /** START: saveChangesHooks tests */ + public function testRegisteredHooksAreCalled() + { + $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'success'), array(), '', false); + $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'success'), array(), '', false); + + $mockHookA->expects($this->once())->method("pre"); + $mockHookA->expects($this->once())->method("success"); + $mockHookA->expects($this->never())->method("failure"); + $mockHookB->expects($this->once())->method("pre"); + $mockHookB->expects($this->once())->method("success"); + $mockHookB->expects($this->never())->method("failure"); + + $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookA); + $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookB); + + $this->tripod->saveChanges(new \Tripod\ExtendedGraph(),new \Tripod\ExtendedGraph()); + } + + public function testRegisteredSuccessHooksAreNotCalledOnException() + { + $this->setExpectedException('\Tripod\Exceptions\Exception','Could not validate'); + + /* @var $tripodUpdate \Tripod\Mongo\Updates|PHPUnit_Framework_MockObject_MockObject */ + $tripodUpdate = $this->getMock( + '\Tripod\Mongo\Updates', + array('validateGraphCardinality'), + array($this->tripod) + ); + + /* @var $mockHookA \Tripod\IEventHook|PHPUnit_Framework_MockObject_MockObject*/ + $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'success', 'failure'), array(), '', false); + /* @var $mockHookB \Tripod\IEventHook|PHPUnit_Framework_MockObject_MockObject*/ + $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'success', 'failure'), array(), '', false); + + $mockHookA->expects($this->once())->method("pre"); + $mockHookA->expects($this->never())->method("success"); + $mockHookA->expects($this->once())->method("failure"); + $mockHookB->expects($this->once())->method("pre"); + $mockHookB->expects($this->never())->method("success"); + $mockHookB->expects($this->once())->method("failure"); + + $tripodUpdate->registerSaveChangesEventHook($mockHookA); + $tripodUpdate->registerSaveChangesEventHook($mockHookB); + + $tripodUpdate->expects($this->once())->method('validateGraphCardinality')->willThrowException(new \Tripod\Exceptions\Exception("Could not validate")); + $tripodUpdate->saveChanges(new \Tripod\ExtendedGraph(),new \Tripod\ExtendedGraph()); + } + + public function testMisbehavingHookDoesNotPreventSaveOrInterfereWithOtherHooks() + { + $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'success'), array(), '', false); + $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'success'), array(), '', false); + + $mockHookA->expects($this->once())->method("pre")->will($this->throwException(new Exception("Misbehaving hook"))); + $mockHookA->expects($this->once())->method("success")->will($this->throwException(new Exception("Misbehaving hook"))); + $mockHookA->expects($this->never())->method("failure"); + $mockHookB->expects($this->once())->method("pre"); + $mockHookB->expects($this->once())->method("success"); + $mockHookB->expects($this->never())->method("failure"); + + $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookA); + $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookB); + + $this->tripod->saveChanges(new \Tripod\ExtendedGraph(),new \Tripod\ExtendedGraph()); + } + + /** END: saveChangesHooks tests */ + +} +class TestSaveChangesHookA implements \Tripod\IEventHook +{ + /** + * This method gets called just before the event happens. The arguments passed depend on the event in question, see + * the documentation for that event type for details + * @param $args array of arguments + */ + public function pre(array $args) + { + // do nothing + } + + /** + * This method gets called after the event has successfully completed. The arguments passed depend on the event in + * question, see the documentation for that event type for details + * If the event throws an exception or fatal error, this method will not be called. + * @param $args array of arguments + */ + public function success(array $args) + { + // do nothing + } + + /** + * This method gets called if the event failed for any reason. The arguments passed should be the same as IEventHook::pre + * @param array $args + * @return mixed + */ + public function failure(array $args) + { + // do nothing + } +} + +class TestSaveChangesHookB extends TestSaveChangesHookA +{ + // empty } +/** END: saveChangesHooks tests */ diff --git a/test/unit/mongo/MongoTripodSearchIndexerTest.php b/test/unit/mongo/MongoTripodSearchIndexerTest.php index d9c74820..6abdad7b 100644 --- a/test/unit/mongo/MongoTripodSearchIndexerTest.php +++ b/test/unit/mongo/MongoTripodSearchIndexerTest.php @@ -64,7 +64,7 @@ public function testSearchDocumentsRegenerateWhenDefinedPredicateChanged() $tripodUpdate->expects($this->atLeastOnce()) ->method('storeChanges') - ->will($this->returnValue($subjectsAndPredicatesOfChange)); + ->will($this->returnValue(array("subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange,"transaction_id"=>"t1234"))); $tripod->expects($this->atLeastOnce()) ->method('getDataUpdater') @@ -364,7 +364,7 @@ function testSearchDocumentsNotRegeneratedIfChangeIsNotInSearchSpec() ); $tripodUpdate->expects($this->atLeastOnce()) ->method('storeChanges') - ->will($this->returnValue(array('deletedSubjects'=>array()))); + ->will($this->returnValue(array('deletedSubjects'=>array(),"subjectsAndPredicatesOfChange"=>array(),"transaction_id"=>'t1234'))); $tripod->expects($this->atLeastOnce()) ->method('getDataUpdater') diff --git a/test/unit/mongo/MongoTripodTablesTest.php b/test/unit/mongo/MongoTripodTablesTest.php index 4f2abeb4..eba9d701 100644 --- a/test/unit/mongo/MongoTripodTablesTest.php +++ b/test/unit/mongo/MongoTripodTablesTest.php @@ -178,7 +178,7 @@ public function testGenerateTableRowsWithCountUpdateAndRequery() $this->assertEquals(count($t2['results']),2); foreach ($t2['results'] as $r) { - if ($r['_id']['r'] = $subject) { + if ($r['_id']['r'] == $subject) { $result = $r; } } @@ -224,7 +224,7 @@ public function testGenerateTableRowsWithCountAndRegexUpdateAndRequery() $this->assertEquals(count($t2['results']),2); foreach ($t2['results'] as $r) { - if ($r['_id']['r'] = $subject) { + if ($r['_id']['r'] == $subject) { $result = $r; } }