/** * Save several new resources in a single operation. Only one of the resources has a type that is applicable based on specifications, * therefore only one ImpactedSubject should be created */ public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject() { $tripod = $this->getMockBuilder('\\Tripod\\Mongo\\Driver')->setMethods(array('getDataUpdater'))->setConstructorArgs(array('CBD_testing', 'tripod_php_testing', array('defaultContext' => 'http://talisaspire.com/', OP_ASYNC => array(OP_VIEWS => true, OP_TABLES => true, OP_SEARCH => true))))->getMock(); $tripodUpdates = $this->getMockBuilder('\\Tripod\\Mongo\\Updates')->setMethods(array('submitJob'))->setConstructorArgs(array($tripod, array('defaultContext' => 'http://talisaspire.com/', OP_ASYNC => array(OP_VIEWS => true, OP_TABLES => true, OP_SEARCH => true))))->getMock(); $tripod->expects($this->once())->method('getDataUpdater')->will($this->returnValue($tripodUpdates)); // first lets add a book, which should trigger a search doc, view and table gen for a single item $g = new \Tripod\Mongo\MongoGraph(); $newSubjectUri1 = "http://talisaspire.com/resources/newdoc1"; $newSubjectUri2 = "http://talisaspire.com/resources/newdoc2"; $newSubjectUri3 = "http://talisaspire.com/resources/newdoc3"; $g->add_resource_triple($newSubjectUri1, $g->qname_to_uri("rdf:type"), $g->qname_to_uri("bibo:Article")); // there are no specs that are applicable for this type alone $g->add_resource_triple($newSubjectUri1, $g->qname_to_uri("dct:creator"), "http://talisaspire.com/authors/1"); $g->add_literal_triple($newSubjectUri1, $g->qname_to_uri("dct:title"), "This is a new resource"); $g->add_literal_triple($newSubjectUri1, $g->qname_to_uri("dct:subject"), "history"); $g->add_literal_triple($newSubjectUri1, $g->qname_to_uri("dct:subject"), "philosophy"); $g->add_resource_triple($newSubjectUri2, $g->qname_to_uri("rdf:type"), $g->qname_to_uri("bibo:Book")); // this is the only resource that should be queued $g->add_resource_triple($newSubjectUri2, $g->qname_to_uri("rdf:type"), $g->qname_to_uri("acorn:Resource")); $g->add_resource_triple($newSubjectUri2, $g->qname_to_uri("dct:creator"), "http://talisaspire.com/authors/1"); $g->add_literal_triple($newSubjectUri2, $g->qname_to_uri("dct:title"), "This is another new resource"); $g->add_literal_triple($newSubjectUri2, $g->qname_to_uri("dct:subject"), "maths"); $g->add_literal_triple($newSubjectUri2, $g->qname_to_uri("dct:subject"), "science"); $g->add_resource_triple($newSubjectUri3, $g->qname_to_uri("rdf:type"), $g->qname_to_uri("bibo:Journal")); // there are no specs that are applicable for this type alone $g->add_resource_triple($newSubjectUri3, $g->qname_to_uri("dct:creator"), "http://talisaspire.com/authors/1"); $g->add_literal_triple($newSubjectUri3, $g->qname_to_uri("dct:title"), "This is yet another new resource"); $g->add_literal_triple($newSubjectUri3, $g->qname_to_uri("dct:subject"), "art"); $g->add_literal_triple($newSubjectUri3, $g->qname_to_uri("dct:subject"), "design"); $subjectsAndPredicatesOfChange = array($newSubjectUri1 => array('rdf:type', 'dct:creator', 'dct:title', 'dct:subject'), $newSubjectUri2 => array('rdf:type', 'dct:creator', 'dct:title', 'dct:subject'), $newSubjectUri3 => array('rdf:type', 'dct:creator', 'dct:title', 'dct:subject')); $tripod->saveChanges(new \Tripod\Mongo\MongoGraph(), $g); /** @var \Tripod\Mongo\Tables $tables */ $search = $tripod->getComposite(OP_SEARCH); $expectedImpactedSubjects = array(new \Tripod\Mongo\ImpactedSubject(array(_ID_RESOURCE => $newSubjectUri2, _ID_CONTEXT => 'http://talisaspire.com/'), OP_SEARCH, 'tripod_php_testing', 'CBD_testing', array())); $impactedSubjects = $search->getImpactedSubjects($subjectsAndPredicatesOfChange, 'http://talisaspire.com/'); $this->assertEquals($expectedImpactedSubjects, $impactedSubjects); }
public function testToTripodViewArray() { $expected = array("_id" => array("r" => "http://example.com/things/1", "c" => "http://example.com/"), "value" => array("_impactIndex" => array("http://example.com/things/1", "http://example.com/things/2"), "_graphs" => array(array("_id" => array("r" => "http://example.com/things/1", "c" => "http://example.com/"), "dct:subject" => array("u" => "http://talisaspire.com/disciplines/physics"), "rdf:type" => array("u" => "bibo:Book"), "bibo:isbn13" => array("l" => "9211234567890")), array("_id" => array("r" => "http://example.com/things/2", "c" => "http://example.com/"), "dct:subject" => array("u" => "http://talisaspire.com/disciplines/maths"), "rdf:type" => array("u" => "acorn:Work"))))); // create a graph adding properties to it $g = new \Tripod\Mongo\MongoGraph(); $g->add_resource_triple("http://example.com/things/1", $g->qname_to_uri("dct:subject"), "http://talisaspire.com/disciplines/physics"); $g->add_resource_triple("http://example.com/things/1", $g->qname_to_uri("rdf:type"), "http://purl.org/ontology/bibo/Book"); $g->add_literal_triple("http://example.com/things/1", $g->qname_to_uri("bibo:isbn13"), "9211234567890"); $g->add_resource_triple("http://example.com/things/2", $g->qname_to_uri("dct:subject"), "http://talisaspire.com/disciplines/maths"); $g->add_resource_triple("http://example.com/things/2", $g->qname_to_uri("rdf:type"), "http://talisaspire.com/schema#Work"); $actual = $g->to_tripod_view_array("http://example.com/things/1", "http://example.com/"); $this->assertEquals($expected, $actual); }
public function testTransactionIsLoggedCorrectlyWhenSaveFails() { $uri = 'http://example.com/resources/1'; // save a new entity, and retrieve it $g = new \Tripod\Mongo\MongoGraph(); $g->add_resource_triple($uri, $g->qname_to_uri("rdf:type"), $g->qname_to_uri("acorn:Resource")); $g->add_literal_triple($uri, $g->qname_to_uri("dct:title"), "wibble"); $mTripod = $this->getMock('\\Tripod\\Mongo\\Driver', array('getDataUpdater'), array('CBD_testing', 'tripod_php_testing')); $mTripodUpdate = $this->getMock('\\Tripod\\Mongo\\Updates', array('getUniqId'), array($mTripod)); $mTripodUpdate->expects($this->atLeastOnce())->method('getUniqId')->will($this->returnValue(1)); $mTripod->expects($this->atLeastOnce())->method('getDataUpdater')->will($this->returnValue($mTripodUpdate)); $mTripod->setTransactionLog($this->tripodTransactionLog); $mTripod->saveChanges(new \Tripod\Mongo\MongoGraph(), $g, 'http://talisaspire.com/'); // STEP 2 // now attempt to update the entity but throw an exception in applyChangeset // this should cause the save to fail, and this should be reflected in the transaction log $mTripod = null; $mTripod = $this->getMock('\\Tripod\\Mongo\\Driver', array('getDataUpdater'), array('CBD_testing', 'tripod_php_testing')); $mTripodUpdate = $this->getMock('\\Tripod\\Mongo\\Updates', array('getUniqId', 'applyChangeSet'), array($mTripod)); $mTripodUpdate->expects($this->atLeastOnce())->method('getUniqId')->will($this->returnValue(2)); $mTripodUpdate->expects($this->atLeastOnce())->method('applyChangeSet')->will($this->throwException(new Exception("exception thrown by mock test"))); $mTripod->expects($this->atLeastOnce())->method('getDataUpdater')->will($this->returnValue($mTripodUpdate)); $mTripod->setTransactionLog($this->tripodTransactionLog); $nG = new \Tripod\Mongo\MongoGraph(); $nG->add_graph($g); $nG->add_literal_triple($uri, $g->qname_to_uri("dct:title"), "another title"); try { $saved = $mTripod->saveChanges($g, $nG, 'http://talisaspire.com/'); $this->fail("Exception should have been thrown"); } catch (\Tripod\Exceptions\Exception $e) { // Squash exception here as we want to keep running assertions below. } // Now assert that the transaction logged the failure $transactionId = 'transaction_2'; $transactionDocument = $this->getDocument($transactionId, $this->tripod, true); $this->assertEquals($transactionId, $transactionDocument['_id'], 'transtion should have the mocked id we injected'); $this->assertEquals('failed', $transactionDocument['status'], 'status of the transaction should be failed'); $this->assertEquals(1, count($transactionDocument['originalCBDs']), 'There should only be on CBD in the originalCBs collection'); $this->assertTransactionDate($transactionDocument, 'startTime'); $this->assertTransactionDate($transactionDocument, 'failedTime'); $this->assertTrue(isset($transactionDocument['changes']), "Transaction should contain changes"); $this->assertChangesForGivenSubject($transactionDocument['changes'], $uri, 1, 0); $expectedCBD = array('_id' => array('r' => 'http://example.com/resources/1', 'c' => 'http://talisaspire.com/'), '_version' => 0, "dct:title" => array('l' => 'wibble'), "rdf:type" => array('u' => "acorn:Resource")); $actualCBD = $transactionDocument['originalCBDs'][0]; // TODO: find a better way of doing this, for now we set the expected created ts and updated ts to the same as actual or test will fail $expectedCBD[_UPDATED_TS] = $actualCBD[_UPDATED_TS]; $expectedCBD[_CREATED_TS] = $actualCBD[_CREATED_TS]; // sort the keys in both arrays to ensure equals check works (it will fail if the keys are in a different order) ksort($actualCBD); ksort($expectedCBD); $this->assertEquals($expectedCBD, $actualCBD, 'CBD in transaction should match our expected value exactly'); // finally check that the actual error was logged in the transaction_log $this->assertTrue(isset($transactionDocument['error']) && isset($transactionDocument['error']['reason']) && isset($transactionDocument['error']['trace']), 'The error should be logged, both the message and a stack trace'); $this->assertEquals('exception thrown by mock test', $transactionDocument['error']['reason'], 'The transaction log should have logged the exception our test suite threw'); $this->assertNotEmpty($transactionDocument['error']['trace'], 'The transaction log have a non empty error trace'); }
array_shift($argv); $config = json_decode(file_get_contents($argv[0]), true); \Tripod\Mongo\Config::setConfig($config); $tu = new \Tripod\Mongo\TriplesUtil(); while (($line = fgets(STDIN)) !== false) { $line = rtrim($line); $graph = new \Tripod\Mongo\MongoGraph(); $doc = json_decode($line, true); if (array_key_exists("_id", $doc)) { $subject = $doc['_id']; unset($doc["_id"]); if (array_key_exists("_version", $doc)) { unset($doc["_version"]); } foreach ($doc as $property => $values) { if (isset($values['value'])) { $doc[$property] = array($values); } } foreach ($doc as $property => $values) { foreach ($values as $value) { if ($value['type'] == "literal") { $graph->add_literal_triple($subject, $graph->qname_to_uri($property), $value['value']); } else { $graph->add_resource_triple($subject, $graph->qname_to_uri($property), $value['value']); } } } print $graph->to_ntriples(); } }
public function testTransactionRollbackDuringLockAllDocumentsWithEmptyOriginalCBDS() { $subjectOne = 'http://example.com/resources/1'; $subjectTwo = 'http://example.com/resources/2'; $oG = new \Tripod\Mongo\MongoGraph(); $nG = new \Tripod\Mongo\MongoGraph(); // save two completely new entities $nG->add_resource_triple($subjectOne, $nG->qname_to_uri("rdf:type"), $nG->qname_to_uri("acorn:Resource")); $nG->add_literal_triple($subjectOne, $nG->qname_to_uri("dct:title"), "Title one"); $nG->add_literal_triple($subjectOne, $nG->qname_to_uri("dct:title"), "Title two"); $nG->add_resource_triple($subjectTwo, $nG->qname_to_uri("rdf:type"), $nG->qname_to_uri("acorn:Book")); $nG->add_literal_triple($subjectTwo, $nG->qname_to_uri("dct:title"), "Title three"); $nG->add_literal_triple($subjectTwo, $nG->qname_to_uri("dct:title"), "Title four"); $mockTransactionId = 'transaction_1'; $mockTripod = $this->getMock('\\Tripod\\Mongo\\Driver', array('getDataUpdater'), array('CBD_testing', 'tripod_php_testing', array('defaultContext' => 'http://talisaspire.com/'))); $mockTripodUpdate = $this->getMock('\\Tripod\\Mongo\\Updates', array('generateTransactionId', 'lockSingleDocument'), array($mockTripod)); $mockTripodUpdate->expects($this->exactly(1))->method('generateTransactionId')->will($this->returnValue($mockTransactionId)); $mockTripodUpdate->expects($this->exactly(2 * 20))->method('lockSingleDocument')->will($this->returnCallback(array($this, 'lockSingleDocumentCauseFailureCallback'))); $mockTripod->expects($this->atLeastOnce())->method('getDataUpdater')->will($this->returnValue($mockTripodUpdate)); /** @var $mockTripod \Tripod\Mongo\Driver */ $mockTripod->setTransactionLog($this->tripodTransactionLog); try { $mockTripod->saveChanges($oG, $nG, "http://talisaspire.com/"); $this->fail('Exception should have been thrown'); } catch (\Tripod\Exceptions\Exception $e) { // Squash the exception here as we need to continue running the assertions. } // make sure the subjects werent changed $uG = $this->tripod->describeResources(array($subjectOne, $subjectTwo)); $this->assertTrue($uG->is_empty()); $this->assertDocumentDoesNotHaveProperty(array('r' => $subjectOne, 'c' => 'http://talisaspire.com/'), _LOCKED_FOR_TRANS, $this->tripod); $this->assertDocumentDoesNotHaveProperty(array('r' => $subjectOne, 'c' => 'http://talisaspire.com/'), _LOCKED_FOR_TRANS_TS, $this->tripod); $this->assertDocumentDoesNotHaveProperty(array('r' => $subjectTwo, 'c' => 'http://talisaspire.com/'), _LOCKED_FOR_TRANS, $this->tripod); $this->assertDocumentDoesNotHaveProperty(array('r' => $subjectTwo, 'c' => 'http://talisaspire.com/'), _LOCKED_FOR_TRANS_TS, $this->tripod); $transaction = $mockTripodUpdate->getTransactionLog()->getTransaction($mockTransactionId); $this->assertNotNull($transaction); $this->assertEquals("Did not obtain locks on documents", $transaction['error']['reason']); $this->assertEquals("failed", $transaction['status']); }
public function testSpecifyQueueForAsyncOperations() { $uri_1 = "http://example.com/1"; $uri_2 = "http://example.com/2"; $oG = new \Tripod\Mongo\MongoGraph(); $oG->add_resource_triple($uri_1, $oG->qname_to_uri("rdf:type"), $oG->qname_to_uri("acorn:Resource")); $oG->add_resource_triple($uri_2, $oG->qname_to_uri("rdf:type"), $oG->qname_to_uri("acorn:Resource")); // a delete and an update $nG = new \Tripod\Mongo\MongoGraph(); $nG->add_graph($oG); $nG->add_literal_triple($uri_1, $nG->qname_to_uri("searchterms:title"), "wibble"); $nG->remove_resource_triple($uri_2, $oG->qname_to_uri("rdf:type"), "http://foo/bar#Class2"); /** @var \Tripod\Mongo\Driver|PHPUnit_Framework_MockObject_MockObject $mockTripod */ $mockTripod = $this->getMock('\\Tripod\\Mongo\\Driver', array('getComposite', 'getDataUpdater'), array('CBD_testing', 'tripod_php_testing', array('defaultContext' => 'http://talisaspire.com/'))); $queueName = 'TRIPOD_TESTING_QUEUE_' . uniqid(); $mockTripodUpdates = $this->getMock('\\Tripod\\Mongo\\Updates', array('storeChanges', 'getDiscoverImpactedSubjects'), array($mockTripod, array(OP_ASYNC => array(OP_TABLES => true, OP_VIEWS => false, OP_SEARCH => true, 'queue' => $queueName)))); $mockViews = $this->getMock('\\Tripod\\Mongo\\Composites\\Views', array('getImpactedSubjects', 'update'), array('tripod_php_testing', \Tripod\Mongo\Config::getInstance()->getCollectionForCBD('tripod_php_testing', 'CBD_testing'), 'http://talisaspire.com/')); $mockDiscoverImpactedSubjects = $this->getMockBuilder('\\Tripod\\Mongo\\Jobs\\DiscoverImpactedSubjects')->setMethods(array('createJob'))->getMock(); $impactedViewSubjects = array($this->getMockBuilder('\\Tripod\\Mongo\\ImpactedSubject')->setConstructorArgs(array(array(_ID_RESOURCE => $uri_1, _ID_CONTEXT => 'http://talisaspire.com'), OP_VIEWS, 'tripod_php_testing', 'CBD_testing'))->setMethods(array('update'))->getMock(), $this->getMockBuilder('\\Tripod\\Mongo\\ImpactedSubject')->setConstructorArgs(array(array(_ID_RESOURCE => $uri_2, _ID_CONTEXT => 'http://talisaspire.com'), OP_VIEWS, 'tripod_php_testing', 'CBD_testing'))->setMethods(array('update'))->getMock()); $labeller = new \Tripod\Mongo\Labeller(); $subjectsAndPredicatesOfChange = array($labeller->uri_to_alias($uri_1) => array('searchterms:title'), $labeller->uri_to_alias($uri_2) => array('rdf:type')); $jobData = array('changes' => $subjectsAndPredicatesOfChange, 'operations' => array(OP_TABLES, OP_SEARCH), 'tripodConfig' => \Tripod\Mongo\Config::getConfig(), 'storeName' => 'tripod_php_testing', 'podName' => 'CBD_testing', 'contextAlias' => 'http://talisaspire.com/', 'queue' => $queueName, 'statsConfig' => array()); // getComposite() should only be called if there are synchronous operations $mockTripod->expects($this->once())->method('getComposite')->with(OP_VIEWS)->will($this->returnValue($mockViews)); $mockTripodUpdates->expects($this->once())->method('getDiscoverImpactedSubjects')->will($this->returnValue($mockDiscoverImpactedSubjects)); $mockTripodUpdates->expects($this->once())->method('storeChanges')->will($this->returnValue(array("subjectsAndPredicatesOfChange" => $subjectsAndPredicatesOfChange, "transaction_id" => "t1234"))); $mockTripod->expects($this->once())->method('getDataUpdater')->will($this->returnValue($mockTripodUpdates)); $mockViews->expects($this->once())->method('getImpactedSubjects')->will($this->returnValue($impactedViewSubjects)); // This shouldn't be called because ImpactedSubject->update has been mocked and isn't doing anything $mockViews->expects($this->never())->method('update'); $impactedViewSubjects[0]->expects($this->once())->method('update'); $impactedViewSubjects[1]->expects($this->once())->method('update'); $mockDiscoverImpactedSubjects->expects($this->once())->method('createJob')->with($jobData, $queueName); $mockTripod->saveChanges($oG, $nG, "http://talisaspire.com/"); }
public function testTransactionLogIsWrittenToCorrectDBAndCollection() { $storeName = 'tripod_php_testing'; $newConfig = \Tripod\Mongo\Config::getConfig(); $newConfig['transaction_log']['database'] = 'tripod_php_testing_transaction_log'; $newConfig['transaction_log']['collection'] = 'transaction_log'; \Tripod\Mongo\Config::setConfig($newConfig); $config = \Tripod\Mongo\Config::getInstance(); // Clear out any old data $tlogDB = $config->getTransactionLogDatabase(); $tlogDB->drop(); // Make sure the dbs do not exist $transactionConnInfo = $newConfig['data_sources'][$newConfig['transaction_log']['data_source']]; $options = isset($transactionConnInfo['replicaSet']) && !empty($transactionConnInfo['replicaSet']) ? array('replicaSet' => $transactionConnInfo['replicaSet']) : array(); $transactionMongo = new Client($transactionConnInfo['connection'], $options); $transactionDbInfo = $transactionMongo->listDatabases(); foreach ($transactionDbInfo as $db) { $this->assertNotEquals($db->getName(), $newConfig['transaction_log']['database']); } $tqueuesConnInfo = $newConfig['data_sources'][$newConfig['transaction_log']['data_source']]; $options = isset($tqueuesConnInfo['replicaSet']) && !empty($tqueuesConnInfo['replicaSet']) ? array('replicaSet' => $tqueuesConnInfo['replicaSet']) : array(); $queuesMongo = new Client($tqueuesConnInfo['connection'], $options); $queuesDbInfo = $queuesMongo->listDatabases(); foreach ($queuesDbInfo as $db) { $this->assertNotEquals($db->getName(), $newConfig['transaction_log']['database']); } // Start adding some data $this->tripod = new \Tripod\Mongo\Driver('CBD_testing', $storeName, array(OP_ASYNC => array(OP_VIEWS => true, OP_TABLES => false, OP_SEARCH => false))); $this->loadResourceDataViaTripod(); $graph = new \Tripod\Mongo\MongoGraph(); $subject = 'http://example.com/' . uniqid(); $labeller = new \Tripod\Mongo\Labeller(); $graph->add_resource_triple($subject, RDF_TYPE, $labeller->qname_to_uri('foaf:Person')); $graph->add_literal_triple($subject, FOAF_NAME, "Anne Example"); $this->tripod->saveChanges(new \Tripod\ExtendedGraph(), $graph); $newGraph = $this->tripod->describeResource($subject); $newGraph->add_literal_triple($subject, $labeller->qname_to_uri('foaf:email'), '*****@*****.**'); $this->tripod->saveChanges($graph, $newGraph); // Make sure the dbs do now exist $transactionDbInfo = $transactionMongo->listDatabases(); $transactionDbExists = false; foreach ($transactionDbInfo as $db) { if ($db->getName() === $newConfig['transaction_log']['database']) { $transactionDbExists = true; } } $this->assertTrue($transactionDbExists); // Make sure the data in the dbs look right $transactionColletion = $transactionMongo->selectCollection($newConfig['transaction_log']['database'], $newConfig['transaction_log']['collection']); $transactionCount = $transactionColletion->count(); $transactionExampleDocument = $transactionColletion->findOne(); $this->assertEquals(24, $transactionCount); $this->assertContains('transaction_', $transactionExampleDocument["_id"]); }