예제 #1
0
 /**
  * Run the ApplyOperation job
  * @throws \Exception
  */
 public function perform()
 {
     try {
         $this->debugLog("[JOBID " . $this->job->payload['id'] . "] ApplyOperation::perform() start");
         $timer = new \Tripod\Timer();
         $timer->start();
         $this->validateArgs();
         $statsConfig = array();
         if (isset($this->args['statsConfig'])) {
             $statsConfig['statsConfig'] = $this->args['statsConfig'];
         }
         // set the config to what is received
         \Tripod\Mongo\Config::setConfig($this->args[self::TRIPOD_CONFIG_KEY]);
         $this->getStat()->increment(MONGO_QUEUE_APPLY_OPERATION_JOB . '.' . SUBJECT_COUNT, count($this->args[self::SUBJECTS_KEY]));
         foreach ($this->args[self::SUBJECTS_KEY] as $subject) {
             $opTimer = new \Tripod\Timer();
             $opTimer->start();
             $impactedSubject = $this->createImpactedSubject($subject);
             $impactedSubject->update();
             $opTimer->stop();
             // stat time taken to perform operation for the given subject
             $this->getStat()->timer(MONGO_QUEUE_APPLY_OPERATION . '.' . $subject['operation'], $opTimer->result());
         }
         $timer->stop();
         // stat time taken to process job, from time it was picked up
         $this->getStat()->timer(MONGO_QUEUE_APPLY_OPERATION_SUCCESS, $timer->result());
         $this->debugLog("[JOBID " . $this->job->payload['id'] . "] ApplyOperation::perform() done in {$timer->result()}ms");
     } catch (\Exception $e) {
         $this->getStat()->increment(MONGO_QUEUE_APPLY_OPERATION_FAIL);
         $this->errorLog("Caught exception in " . get_class($this) . ": " . $e->getMessage());
         throw $e;
     }
 }
예제 #2
0
 /**
  * Note: Current version of this test tried to create 1000 objects within 6000ms which is reasonable at this time.
  *       Any change to this class if make it a more a big number it should be validated and tested to ensure performance impact.
  *
  * Create some instances of Config to see what amount of time is taken in creating instance and processing in constructor.
  */
 public function testCreateMongoTripodConfigObject()
 {
     $testStartTime = microtime();
     //Let's try to create 1000 objects to see how much time they take.
     for ($i = 0; $i < self::BENCHMARK_OBJECT_CREATE_ITERATIONS; $i++) {
         \Tripod\Mongo\Config::setConfig($this->config);
         $instance = \Tripod\Mongo\Config::getInstance();
     }
     $testEndTime = microtime();
     $this->assertLessThan(self::BENCHMARK_OBJECT_CREATE_TIME, $this->getTimeDifference($testStartTime, $testEndTime), "It should always take less than " . self::BENCHMARK_OBJECT_CREATE_TIME . "ms to create " . self::BENCHMARK_OBJECT_CREATE_ITERATIONS . " objects of Config class");
 }
예제 #3
0
 protected function setUp()
 {
     date_default_timezone_set('Europe/London');
     $config = json_decode(file_get_contents($this->getConfigLocation()), true);
     if (getenv('TRIPOD_DATASOURCE_RS1_CONFIG')) {
         $config['data_sources']['rs1'] = json_decode(getenv('TRIPOD_DATASOURCE_RS1_CONFIG'), true);
     }
     if (getenv('TRIPOD_DATASOURCE_RS2_CONFIG')) {
         $config['data_sources']['rs2'] = json_decode(getenv('TRIPOD_DATASOURCE_RS2_CONFIG'), true);
     }
     \Tripod\Mongo\Config::setConfig($config);
     $className = get_class($this);
     $testName = $this->getName();
     echo "\nTest: {$className}->{$testName}\n";
     // make sure log statements don't go to stdout during tests...
     $log = new \Monolog\Logger("unittest");
     $log->pushHandler(new \Monolog\Handler\NullHandler());
     \Tripod\Mongo\DriverBase::$logger = $log;
 }
예제 #4
0
        \Tripod\Mongo\Config::getInstance()->setMongoCursorTimeout(-1);
        print "Generating {$tableId}";
        $tripod = new \Tripod\Mongo\Driver($tableSpec['from'], $storeName, array('stat' => $stat));
        $tTables = $tripod->getTripodTables();
        if ($id) {
            print " for {$id}....\n";
            $tTables->generateTableRows($tableId, $id);
        } else {
            print " for all tables....\n";
            $tTables->generateTableRows($tableId, null, null, $queue);
        }
    }
}
$t = new \Tripod\Timer();
$t->start();
\Tripod\Mongo\Config::setConfig(json_decode(file_get_contents($configLocation), true));
if (isset($options['s']) || isset($options['storename'])) {
    $storeName = isset($options['s']) ? $options['s'] : $options['storename'];
} else {
    $storeName = null;
}
if (isset($options['t']) || isset($options['spec'])) {
    $tableId = isset($options['t']) ? $options['t'] : $options['spec'];
} else {
    $tableId = null;
}
if (isset($options['i']) || isset($options['id'])) {
    $id = isset($options['i']) ? $options['i'] : $options['id'];
} else {
    $id = null;
}
예제 #5
0
        $loader->loadTriplesAbout($subject, $triples, $storeName, $podName);
    } catch (Exception $e) {
        print "Exception for subject {$subject} failed with message: " . $e->getMessage() . "\n";
        $errors[] = $subject;
    }
}
$timer = new \Tripod\Timer();
$timer->start();
if ($argc != 4) {
    echo "usage: ./loadTriples.php storename podname tripodConfig.json < ntriplesdata\n";
    die;
}
array_shift($argv);
$storeName = $argv[0];
$podName = $argv[1];
\Tripod\Mongo\Config::setConfig(json_decode(file_get_contents($argv[2]), true));
$i = 0;
$currentSubject = "";
$triples = array();
$errors = array();
// array of subjects that failed to insert, even after retry...
$loader = new \Tripod\Mongo\TriplesUtil();
while (($line = fgets(STDIN)) !== false) {
    $i++;
    if ($i % 250000 == 0) {
        print "Memory: " . memory_get_usage() . "\n";
    }
    $line = rtrim($line);
    $parts = preg_split("/\\s/", $line);
    $subject = trim($parts[0], '><');
    if (empty($currentSubject)) {
 /**
  * Run the DiscoverImpactedSubjects job
  * @throws \Exception
  */
 public function perform()
 {
     try {
         $this->debugLog("[JOBID " . $this->job->payload['id'] . "] DiscoverImpactedSubjects::perform() start");
         $timer = new \Tripod\Timer();
         $timer->start();
         $this->validateArgs();
         // set the config to what is received
         \Tripod\Mongo\Config::setConfig($this->args[self::TRIPOD_CONFIG_KEY]);
         $statsConfig = array();
         if (isset($this->args['statsConfig'])) {
             $statsConfig['statsConfig'] = $this->args['statsConfig'];
         }
         $tripod = $this->getTripod($this->args[self::STORE_NAME_KEY], $this->args[self::POD_NAME_KEY], $statsConfig);
         $operations = $this->args[self::OPERATIONS_KEY];
         $subjectsAndPredicatesOfChange = $this->args[self::CHANGES_KEY];
         $subjectCount = 0;
         foreach ($operations as $op) {
             /** @var \Tripod\Mongo\Composites\IComposite $composite */
             $composite = $tripod->getComposite($op);
             $modifiedSubjects = $composite->getImpactedSubjects($subjectsAndPredicatesOfChange, $this->args[self::CONTEXT_ALIAS_KEY]);
             if (!empty($modifiedSubjects)) {
                 /* @var $subject \Tripod\Mongo\ImpactedSubject */
                 foreach ($modifiedSubjects as $subject) {
                     $subjectCount++;
                     $subjectTimer = new \Tripod\Timer();
                     $subjectTimer->start();
                     if (isset($this->args[self::QUEUE_KEY]) || count($subject->getSpecTypes()) == 0) {
                         $queueName = isset($this->args[self::QUEUE_KEY]) ? $this->args[self::QUEUE_KEY] : Config::getApplyQueueName();
                         $this->addSubjectToQueue($subject, $queueName);
                     } else {
                         $specsGroupedByQueue = array();
                         foreach ($subject->getSpecTypes() as $specType) {
                             $spec = null;
                             switch ($subject->getOperation()) {
                                 case OP_VIEWS:
                                     $spec = Config::getInstance()->getViewSpecification($this->args[self::STORE_NAME_KEY], $specType);
                                     break;
                                 case OP_TABLES:
                                     $spec = Config::getInstance()->getTableSpecification($this->args[self::STORE_NAME_KEY], $specType);
                                     break;
                                 case OP_SEARCH:
                                     $spec = Config::getInstance()->getSearchDocumentSpecification($this->args[self::STORE_NAME_KEY], $specType);
                                     break;
                             }
                             if (!$spec || !isset($spec['queue'])) {
                                 if (!$spec) {
                                     $spec = array();
                                 }
                                 $spec['queue'] = Config::getApplyQueueName();
                             }
                             if (!isset($specsGroupedByQueue[$spec['queue']])) {
                                 $specsGroupedByQueue[$spec['queue']] = array();
                             }
                             $specsGroupedByQueue[$spec['queue']][] = $specType;
                         }
                         foreach ($specsGroupedByQueue as $queueName => $specs) {
                             $queuedSubject = new \Tripod\Mongo\ImpactedSubject($subject->getResourceId(), $subject->getOperation(), $subject->getStoreName(), $subject->getPodName(), $specs);
                             $this->addSubjectToQueue($queuedSubject, $queueName);
                         }
                     }
                     $subjectTimer->stop();
                     // stat time taken to discover impacted subjects for the given subject of change
                     $this->getStat()->timer(MONGO_QUEUE_DISCOVER_SUBJECT, $subjectTimer->result());
                 }
                 if (!empty($this->subjectsGroupedByQueue)) {
                     foreach ($this->subjectsGroupedByQueue as $queueName => $subjects) {
                         $this->getApplyOperation()->createJob($subjects, $queueName, $statsConfig);
                     }
                     $this->subjectsGroupedByQueue = array();
                 }
             }
         }
         // stat time taken to process item, from time it was created (queued)
         $timer->stop();
         $this->getStat()->timer(MONGO_QUEUE_DISCOVER_SUCCESS, $timer->result());
         $this->debugLog("[JOBID " . $this->job->payload['id'] . "] DiscoverImpactedSubjects::perform() done in {$timer->result()}ms");
         $this->getStat()->increment(MONGO_QUEUE_DISCOVER_JOB . '.' . SUBJECT_COUNT, $subjectCount);
     } catch (\Exception $e) {
         $this->getStat()->increment(MONGO_QUEUE_DISCOVER_FAIL);
         $this->errorLog("Caught exception in " . get_class($this) . ": " . $e->getMessage());
         throw $e;
     }
 }
예제 #7
0
파일: index.php 프로젝트: talis/tripod-php
         $tripod = new \Tripod\Mongo\Driver($podName, $storeName, $tripodOptions);
         $oldGraph = $tripod->describeResource(base64_decode($encodedFqUri));
         $tripod->saveChanges($oldGraph, new \Tripod\ExtendedGraph());
     });
     $app->post('/', function ($storeName, $podName) use($app, $tripodOptions) {
         $tripodOptions['statsConfig'] = getStat($app, $tripodOptions);
         $tripod = new \Tripod\Mongo\Driver($podName, $storeName, $tripodOptions);
         $rawGraphData = $app->request()->getBody();
         $graph = new \Tripod\Mongo\MongoGraph();
         $graph->add_rdf($rawGraphData);
         $tripod->saveChanges(new \Tripod\ExtendedGraph(), $graph);
     });
 });
 $app->group('/change', function () use($app, $tripodOptions) {
     $app->post('/', function ($storeName, $podName) use($app, $tripodOptions) {
         \Tripod\Mongo\Config::setConfig(json_decode(file_get_contents('./config/tripod-config-' . $storeName . '.json'), true));
         $app->response()->setStatus(500);
         $tripodOptions['statsConfig'] = getStat($app, $tripodOptions);
         $tripod = new \Tripod\Mongo\Driver($podName, $storeName, $tripodOptions);
         $rawChangeData = $app->request()->post('data');
         if ($rawChangeData) {
             $changeData = json_decode($rawChangeData, true);
             $from = new \Tripod\Mongo\MongoGraph();
             $to = new \Tripod\Mongo\MongoGraph();
             if (isset($changeData['originalCBDs'])) {
                 foreach ($changeData['originalCBDs'] as $change) {
                     if (is_array($change) && isset($change[_ID_KEY])) {
                         $from->add_tripod_array($change);
                     }
                 }
             }
예제 #8
0
<?php

require_once dirname(__FILE__) . '/common.inc.php';
require_once dirname(dirname(dirname(__FILE__))) . '/src/tripod.inc.php';
if ($argc != 2) {
    echo "usage: ./BSONToQuads.php tripodConfig.json < bsondata\n";
    echo "  When exporting bson data from Mongo use:  \n";
    echo "     mongoexport -d <dbname> -c <collectionName> > bsondata.txt \n";
    die;
}
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);
    $doc = json_decode($line, true);
    $context = $doc['_id']['c'];
    $graph = new \Tripod\Mongo\MongoGraph();
    $graph->add_tripod_array($doc);
    echo $graph->to_nquads($context);
}
 public function testManuallySpecifiedQueueWillOverrideQueuesDefinedInConfig()
 {
     $config = \Tripod\Mongo\Config::getConfig();
     // Create a bunch of specs on various queues
     $tableSpecs = array(array("_id" => "t_resource", "type" => "acorn:Resource", "from" => "CBD_testing", "ensureIndexes" => array("value.isbn" => 1), "fields" => array(array("fieldName" => "type", "predicates" => array("rdf:type")), array("fieldName" => "isbn", "predicates" => array("bibo:isbn13"))), "joins" => array("dct:isVersionOf" => array("fields" => array(array("fieldName" => "isbn13", "predicates" => array("bibo:isbn13")))))), array("_id" => "t_source_count", "type" => "acorn:Resource", "from" => "CBD_testing", "to_data_source" => "rs2", "queue" => "counts_and_other_non_essentials", "fields" => array(array("fieldName" => "type", "predicates" => array("rdf:type"))), "joins" => array("dct:isVersionOf" => array("fields" => array(array("fieldName" => "isbn13", "predicates" => array("bibo:isbn13"))))), "counts" => array(array("fieldName" => "source_count", "property" => "dct:isVersionOf"), array("fieldName" => "random_predicate_count", "property" => "dct:randomPredicate"))), array("_id" => "t_source_count_regex", "type" => "acorn:Resource", "from" => "CBD_testing", "queue" => "counts_and_other_non_essentials", "fields" => array(array("fieldName" => "type", "predicates" => array("rdf:type"))), "joins" => array("dct:isVersionOf" => array("fields" => array(array("fieldName" => "isbn13", "predicates" => array("bibo:isbn13"))))), "counts" => array(array("fieldName" => "source_count", "property" => "dct:isVersionOf"), array("fieldName" => "regex_source_count", "property" => "dct:isVersionOf", "regex" => "/foobar/"))), array("_id" => "t_join_source_count_regex", "type" => "acorn:Resource", "from" => "CBD_testing", "queue" => "MOST_IMPORTANT_QUEUE_EVER", "joins" => array("acorn:jacsUri" => array("counts" => array(array("fieldName" => "titles_count", "property" => "dct:title"))))));
     $config['stores']['tripod_php_testing']['table_specifications'] = $tableSpecs;
     \Tripod\Mongo\Config::setConfig($config);
     /** @var \Tripod\Mongo\Jobs\DiscoverImpactedSubjects|PHPUnit_Framework_MockObject_MockObject $discoverImpactedSubjects */
     $discoverImpactedSubjects = $this->getMockBuilder('\\Tripod\\Mongo\\Jobs\\DiscoverImpactedSubjects')->setMethods(array('getTripod', 'getApplyOperation'))->getMock();
     $this->setArgs();
     $args = $this->args;
     $args['operations'] = array(OP_TABLES);
     $args['queue'] = 'TRIPOD_TESTING_QUEUE_' . uniqid();
     $discoverImpactedSubjects->args = $args;
     $discoverImpactedSubjects->job->payload['id'] = uniqid();
     $tripod = $this->getMockBuilder('\\Tripod\\Mongo\\Driver')->setMethods(array('getComposite'))->setConstructorArgs(array('CBD_testing', 'tripod_php_testing'))->getMock();
     $tables = $this->getMockBuilder('\\Tripod\\Mongo\\Composites\\Tables')->setMethods(array('getImpactedSubjects'))->setConstructorArgs(array('tripod_php_testing', \Tripod\Mongo\Config::getInstance()->getCollectionForCBD('tripod_php_testing', 'CBD_testing'), 'http://talisaspire.com/'))->getMock();
     $applyOperation = $this->getMockBuilder('\\Tripod\\Mongo\\Jobs\\ApplyOperation')->setMethods(array('createJob'))->getMock();
     $tableSubjects = array(new \Tripod\Mongo\ImpactedSubject(array(_ID_RESOURCE => 'http://example.com/resources/foo2', _ID_CONTEXT => $this->args['contextAlias']), OP_TABLES, $this->args['storeName'], $this->args['podName'], array('t_resource', 't_source_count', 't_source_count_regex', 't_join_source_count_regex')), new \Tripod\Mongo\ImpactedSubject(array(_ID_RESOURCE => 'http://example.com/resources/foo3', _ID_CONTEXT => $this->args['contextAlias']), OP_TABLES, $this->args['storeName'], $this->args['podName'], array('t_distinct')));
     $tables->expects($this->once())->method('getImpactedSubjects')->with($this->args['changes'], $this->args['contextAlias'])->will($this->returnValue($tableSubjects));
     $tripod->expects($this->once())->method('getComposite')->with(OP_TABLES)->will($this->returnValue($tables));
     $discoverImpactedSubjects->expects($this->once())->method('getTripod')->will($this->returnValue($tripod));
     $discoverImpactedSubjects->expects($this->once())->method('getApplyOperation')->will($this->returnValue($applyOperation));
     $applyOperation->expects($this->once())->method('createJob')->withConsecutive(array($tableSubjects, $args['queue']));
     $discoverImpactedSubjects->perform();
 }
 public function testNestConditionalInArithmeticFunction()
 {
     $tableSpec = array("_id" => "t_arithmetic_with_nested_conditional", "type" => array("bibo:Book", "bibo:Document"), "from" => "CBD_testing", "fields" => array(array("fieldName" => "x", "predicates" => array("foo:wibble"))), "computed_fields" => array(array("fieldName" => "foobar", "value" => array("arithmetic" => array(array("conditional" => array("if" => array('$x'), "then" => '$x', "else" => 100)), "*", 3)))));
     $oldConfig = \Tripod\Mongo\Config::getConfig();
     $newConfig = \Tripod\Mongo\Config::getConfig();
     $newConfig['stores']['tripod_php_testing']['table_specifications'][] = $tableSpec;
     \Tripod\Mongo\Config::setConfig($newConfig);
     \Tripod\Mongo\Config::getInstance();
     $this->tripod = new \Tripod\Mongo\Driver('CBD_testing', 'tripod_php_testing');
     $this->loadResourceDataViaTripod();
     $this->tripod->generateTableRows('t_arithmetic_with_nested_conditional');
     $collection = \Tripod\Mongo\Config::getInstance()->getCollectionForTable('tripod_php_testing', 't_arithmetic_with_nested_conditional');
     $tableDoc = $collection->findOne(array('_id.type' => 't_arithmetic_with_nested_conditional'));
     $this->assertEquals(300, $tableDoc['value']['foobar']);
     \Tripod\Mongo\Config::setConfig($oldConfig);
     \Tripod\Mongo\Config::getInstance();
     $collection->drop();
 }
예제 #11
0
 public function testRemoveTableSpecDoesNotAffectInvalidation()
 {
     foreach (\Tripod\Mongo\Config::getInstance()->getTableSpecifications($this->tripod->getStoreName()) as $specId => $spec) {
         $this->generateTableRows($specId);
     }
     $context = 'http://talisaspire.com/';
     $uri = "http://talisaspire.com/works/4d101f63c10a6";
     $collection = \Tripod\Mongo\Config::getInstance()->getCollectionForTable('tripod_php_testing', 't_resource');
     $this->assertGreaterThan(0, $collection->count(array('_id.type' => 't_resource', 'value._impactIndex' => array(_ID_RESOURCE => $uri, _ID_CONTEXT => $context))));
     $config = \Tripod\Mongo\Config::getConfig();
     unset($config['stores']['tripod_php_testing']['table_specifications'][0]);
     \Tripod\Mongo\Config::setConfig($config);
     /** @var PHPUnit_Framework_MockObject_MockObject|\Tripod\Mongo\Driver $mockTripod */
     $mockTripod = $this->getMockBuilder('\\Tripod\\Mongo\\Driver')->setMethods(array('getComposite'))->setConstructorArgs(array('CBD_testing', 'tripod_php_testing', array('defaultContext' => $context, OP_ASYNC => array(OP_VIEWS => true, OP_TABLES => false, OP_SEARCH => true))))->getMock();
     $mockTables = $this->getMockBuilder('\\Tripod\\Mongo\\Composites\\Tables')->setMethods(array('update'))->setConstructorArgs(array('tripod_php_testing', \Tripod\Mongo\Config::getInstance()->getCollectionForCBD('tripod_php_testing', 'CBD_testing'), $context))->getMock();
     $labeller = new \Tripod\Mongo\Labeller();
     $mockTripod->expects($this->once())->method('getComposite')->with(OP_TABLES)->will($this->returnValue($mockTables));
     $mockTables->expects($this->never())->method('update');
     $originalGraph = $mockTripod->describeResource($uri);
     $updatedGraph = $originalGraph->get_subject_subgraph($uri);
     $updatedGraph->add_literal_triple($uri, $labeller->qname_to_uri('dct:description'), 'Physics textbook');
     $mockTripod->saveChanges($originalGraph, $updatedGraph);
     // The table row should still be there, even if the tablespec no longer exists
     $this->assertGreaterThan(0, $collection->count(array('_id.type' => 't_resource', 'value._impactIndex' => array(_ID_RESOURCE => $uri, _ID_CONTEXT => $context))));
 }
예제 #12
0
 public function testSaveChangesWithInvalidCardinality()
 {
     $this->setExpectedException('\\Tripod\\Exceptions\\CardinalityException', "Cardinality failed on http://foo/bar/1 for 'rdf:type' - should only have 1 value and has: http://foo/bar#Class1, http://foo/bar#Class2");
     $config = array();
     $config['namespaces'] = array('rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
     $config["defaultContext"] = "http://talisaspire.com/";
     $config["transaction_log"] = array("database" => "transactions", "collection" => "transaction_log", "data_source" => "tlog");
     $config["data_sources"] = array("db" => array("type" => "mongo", "connection" => "mongodb://localhost"), "tlog" => array("type" => "mongo", "connection" => "mongodb://*****:*****@localhost:27018"));
     $config["stores"] = array("tripod_php_testing" => array("data_source" => "db", "pods" => array("CBD_testing" => array("cardinality" => array("rdf:type" => 1)))));
     $config['queue'] = array("database" => "queue", "collection" => "q_queue", "data_source" => "db");
     // Override the config defined in base test class as we need specific config here.
     \Tripod\Mongo\Config::setConfig($config);
     $tripod = new \Tripod\Mongo\Driver('CBD_testing', 'tripod_php_testing', array('defaultContext' => 'http://talisaspire.com/'));
     $oldGraph = new \Tripod\ExtendedGraph();
     $newGraph = new \Tripod\ExtendedGraph();
     $newGraph->add_resource_triple('http://foo/bar/1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'http://foo/bar#Class1');
     $newGraph->add_resource_triple('http://foo/bar/1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'http://foo/bar#Class2');
     $tripod->saveChanges($oldGraph, $newGraph, "http://talisaspire.com/");
 }
예제 #13
0
 public function testArithmeticSpecValidationInvalidNestedOperator()
 {
     $newConfig = \Tripod\Mongo\Config::getConfig();
     \Tripod\Mongo\Config::setValidationLevel(\Tripod\Mongo\Config::VALIDATE_MAX);
     $arithmeticFunction = array('fieldName' => 'fooBar', 'value' => array('arithmetic' => array(array(101, '#', 100), '*', 3)));
     $newConfig['stores']['tripod_php_testing']['table_specifications'][0]['computed_fields'] = array($arithmeticFunction);
     \Tripod\Mongo\Config::setConfig($newConfig);
     $this->setExpectedException('\\Tripod\\Exceptions\\ConfigException', "Invalid arithmetic operator '#' in computed arithmetic spec");
     \Tripod\Mongo\Config::getInstance();
 }