public function testTransactionRollbackDuringApplyChanges() { // Save some basic data into the db before we create a transaction to modify it $subjectOne = 'http://example.com/resources/1'; $subjectTwo = 'http://example.com/resources/2'; $doc1 = array('_id' => array('r' => $subjectOne, 'c' => 'http://talisaspire.com/'), 'rdf:type' => array('u' => 'acorn:Resource'), 'dct:title' => array(array('l' => 'Title one'), array('l' => 'Title two')), '_version' => 0, '_cts' => \Tripod\Mongo\DateUtil::getMongoDate(), '_uts' => \Tripod\Mongo\DateUtil::getMongoDate()); $doc2 = array('_id' => array('r' => $subjectTwo, 'c' => 'http://talisaspire.com/'), 'rdf:type' => array('u' => 'acorn:Book'), 'dct:title' => array(array('l' => 'Title three'), array('l' => 'Title four')), '_version' => 0, '_cts' => \Tripod\Mongo\DateUtil::getMongoDate(), '_uts' => \Tripod\Mongo\DateUtil::getMongoDate()); $this->addDocument($doc1); $this->addDocument($doc2); // now lets modify the data using tripod $g1 = $this->tripod->describeResources(array($subjectOne), 'http://talisaspire.com/'); $g2 = $this->tripod->describeResources(array($subjectTwo), 'http://talisaspire.com/'); $oG = new \Tripod\Mongo\MongoGraph(); $oG->add_graph($g1); $oG->add_graph($g2); $nG = new \Tripod\Mongo\MongoGraph(); $nG->add_graph($oG); $nG->remove_literal_triple($subjectOne, $nG->qname_to_uri("dct:title"), "Title one"); $nG->add_literal_triple($subjectOne, $nG->qname_to_uri("dct:title"), "Updated Title one"); $nG->remove_literal_triple($subjectTwo, $nG->qname_to_uri("dct:title"), "Title three"); $nG->add_literal_triple($subjectTwo, $nG->qname_to_uri("dct:title"), "Updated Title three"); $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', 'applyChangeSet'), array($mockTripod)); $mockTripodUpdate->expects($this->exactly(1))->method('generateTransactionId')->will($this->returnValue($mockTransactionId)); $mockTripodUpdate->expects($this->exactly(2))->method('lockSingleDocument')->will($this->returnCallback(array($this, 'lockSingleDocumentCallback'))); $mockTripodUpdate->expects($this->once())->method('applyChangeSet')->will($this->throwException(new Exception("Exception throw by mock test during applychangeset"))); $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->has_resource_triple($subjectOne, $uG->qname_to_uri("rdf:type"), $uG->qname_to_uri("acorn:Resource"))); $this->assertTrue($uG->has_literal_triple($subjectOne, $uG->qname_to_uri("dct:title"), 'Title one')); $this->assertTrue($uG->has_literal_triple($subjectOne, $uG->qname_to_uri("dct:title"), 'Title two')); $this->assertFalse($uG->has_literal_triple($subjectOne, $uG->qname_to_uri("dct:title"), 'Updated Title two')); $this->assertTrue($uG->has_resource_triple($subjectTwo, $uG->qname_to_uri("rdf:type"), $uG->qname_to_uri("acorn:Book"))); $this->assertTrue($uG->has_literal_triple($subjectTwo, $uG->qname_to_uri("dct:title"), 'Title three')); $this->assertTrue($uG->has_literal_triple($subjectTwo, $uG->qname_to_uri("dct:title"), 'Title four')); $this->assertFalse($uG->has_literal_triple($subjectTwo, $uG->qname_to_uri("dct:title"), 'Updated Title three')); $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("Exception throw by mock test during applychangeset", $transaction['error']['reason']); $this->assertEquals("failed", $transaction['status']); }
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'); }
/** * this test verifies that if we simply want to add some data to a document that exists in we dont need to specify an oldgraph; we just need to specify the new graph * the cs builder should translate that into a single addition statement and apply it. * This builds on the previous test, by operating on data in mongo where _id.r and _id.c are namespaced AND passing context into the save method */ public function testTripodSaveChangesAddsLiteralTripleUsingEmptyOldGraphWithNamespacedContext() { $oG = new \Tripod\Mongo\MongoGraph(); $nG = new \Tripod\Mongo\MongoGraph(); $nG->add_graph($oG); // resource and context are namespaced in base data this time around... $nG->add_literal_triple('http://basedata.com/b/1', $nG->qname_to_uri('searchterms:title'), 'TEST TITLE'); $this->tripod->saveChanges($oG, $nG, "baseData:DefaultGraph", 'my changes'); $uG = $this->tripod->describeResource('http://basedata.com/b/1', "http://basedata.com/b/DefaultGraph"); $this->assertHasLiteralTriple($uG, 'http://basedata.com/b/1', $nG->qname_to_uri('searchterms:title'), 'TEST TITLE'); }