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');
 }