1
0
Fork 0

Bugfix of DFS path uniqueness implementation (#9041)

* Began work on generic traversal testing framework

* Translate shard ids to smart attributes

* Minor fixes

* Added a TODO note

* fixed tests

* cleanup

* first tests inside new traversal framework working

* added single server diamond tests

* Enable sharding in aql-graph-traversal-generic-graphs.js

* Tried to fix smart sharding

* Fixed smart graph name clashes, some cleanup

* Added meta tests

* Added TODO note

* Fixed single server

* Added a BFS order check

* Renamed test

* added more dfs and bfs tests for the openDiamond graph

* Added new graph "largeBinTree"

* Fix Map usage

* added smallCircle graph, added three dfs tests

* added smallCircle graph, added three dfs tests

* more smallCircle dfs tests

* Fixed largeBinTree shardings, and long graph names

* Fix long suffixes

* Provided names for shardings

* Added a log message

* more bfs smallCircle tests

* more bfs smallCircle tests - global

* smallCircle picture

* added completeGraph to graph test suite

* added more dfs tests for the complete graph up to depth 3

* Removed duplicate function definitions

* added depth 2 dfs complete graph test, added missing test to the exports

* Added test for largeBinTree

* added three path graphs, easy, advanced and more advanced

* Added a working check for bfs with global uniqueness

* Fixed usage of bfs checks

* Fixed expected input for two tests

* Added some static assertions to largeBinTree

* Oops

* added more advancedPath dfs tests

* better formatting of the visual graph

* more dfs advanced graph tests

* Implemented all easy path test combinations

* Fixed testAqlGraphQuery

* Fix in bfs check error reports

* Removed duplicate test

* Added advancedPath BFS tests

* Updated comments

* Fixed new tests

* Fixed graph description

* added more complete graph bfs tests

* added more complete graph bfs tests

* added testCompleteGraphBfsUniqueEdgesNoneD1 and testCompleteGraphBfsUniqueEdgesNoneD2

* added testCompleteGraphBfsUniqueVerticesUniqueEdgesPathD3 test

* added a few more complete graph bfs checks

* Extended a comment
This commit is contained in:
Tobias Gödderz 2019-05-27 12:57:02 +02:00 committed by Michael Hackstein
parent 3d697d8584
commit 5da9fcb0ce
8 changed files with 4438 additions and 22 deletions

View File

@ -1,6 +1,11 @@
devel
-----
* Bugfix for smart graph traversals with uniqueVertices: path, which could
sometimes lead to erroneous traversal results
* updated ArangoDB Starter 0.14.4
* fix a race in TTL thread deactivation/shutdown
* updated ArangoDB starter to 0.14.4

View File

@ -0,0 +1,760 @@
/*jshint globalstrict:true, strict:true, esnext: true */
"use strict";
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2019 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Tobias Gödderz
////////////////////////////////////////////////////////////////////////////////
const internal = require("internal");
const db = internal.db;
const sgm = require("@arangodb/smart-graph");
const cgm = require("@arangodb/general-graph");
const _ = require("lodash");
const assert = require("jsunity").jsUnity.assertions;
const TestVariants = Object.freeze({
SingleServer: 1,
GeneralGraph: 2,
SmartGraph: 3,
});
class TestGraph {
constructor (graphName, edges, eRel, vn, en, protoSmartSharding, testVariant, numberOfShards) {
this.graphName = graphName;
this.edges = edges;
this.eRel = eRel;
this.vn = vn;
this.en = en;
this.protoSmartSharding = protoSmartSharding;
this.testVariant = testVariant;
this.numberOfShards = numberOfShards;
}
create() {
switch (this.testVariant) {
case TestVariants.SingleServer: {
cgm._create(this.name(), [this.eRel], [], {});
break;
}
case TestVariants.GeneralGraph: {
const options = {numberOfShards: this.numberOfShards};
cgm._create(this.name(), [this.eRel], [], options);
break;
}
case TestVariants.SmartGraph: {
const options = {
numberOfShards: this.numberOfShards,
smartGraphAttribute: ProtoGraph.smartAttr(),
isSmart: true
};
sgm._create(this.name(), [this.eRel], [], options);
break;
}
}
if (this.testVariant === TestVariants.SingleServer) {
this.verticesByName = TestGraph._fillGraph(this.graphName, this.edges, db[this.vn], db[this.en]);
} else {
const shardAttrsByShardIndex = this._shardAttrPerShard(db[this.vn]);
const vertexSharding = this.protoSmartSharding.map(([v, i]) => [v, shardAttrsByShardIndex[i]]);
this.verticesByName = TestGraph._fillGraph(this.graphName, this.edges, db[this.vn], db[this.en], vertexSharding);
}
}
name() {
return this.graphName;
}
vertex(name) {
return this.verticesByName[name];
}
drop() {
cgm._drop(this.name(), true);
}
/**
* @param gn Graph Name
* @param edges Array of pairs of strings, e.g. [["A", "B"], ["B", "C"]]
* @param vc Vertex collection
* @param ec Edge collection
* @param vertexSharding Array of pairs, where the first element is the vertex
* key and the second the smart attribute.
* @private
*/
static _fillGraph(gn, edges, vc, ec, vertexSharding = []) {
const vertices = new Map(vertexSharding);
for (const edge of edges) {
if (!vertices.has(edge[0])) {
vertices.set(edge[0], null);
}
if (!vertices.has(edge[1])) {
vertices.set(edge[1], null);
}
}
const verticesByName = {};
for (const [vertexKey, smart] of vertices) {
const doc = {key: vertexKey};
if (smart !== null) {
doc[ProtoGraph.smartAttr()] = smart;
}
verticesByName[vertexKey] = vc.save(doc)._id;
}
for (const edge of edges) {
let v = verticesByName[edge[0]];
let w = verticesByName[edge[1]];
ec.save(v, w, {});
}
return verticesByName;
}
_shardAttrPerShard(col) {
const shards = col.shards();
// Create an array of size numberOfShards, each entry null.
const exampleAttributeByShard = _.fromPairs(shards.map(id => [id, null]));
const done = () => !
_.values(exampleAttributeByShard)
.includes(null);
let i = 0;
// const key = this.enterprise ? ProtoGraph.smartAttr() : "_key";
const key = "_key";
while (!done()) {
const value = this.enterprise ? i.toString() + ":" : i.toString() ;
const doc = {[key]: value};
let shard;
try {
shard = col.getResponsibleShard(doc);
} catch (e) {
throw new Error('Tried to get shard for ' + JSON.stringify(doc) + ', original error: ' + e);
}
if (exampleAttributeByShard[shard] === null) {
exampleAttributeByShard[shard] = value;
}
++i;
}
return _.values(exampleAttributeByShard);
}
}
class ProtoGraph {
static smartAttr() { return "smart"; }
constructor (name, edges, generalShardings, smartShardings) {
this.protoGraphName = name;
this.edges = edges;
this.generalShardings = generalShardings;
this.smartShardings = smartShardings;
}
name() {
return this.protoGraphName;
}
prepareSingleServerGraph() {
const vn = this.protoGraphName + '_Vertex';
const en = this.protoGraphName + '_Edge';
const gn = this.protoGraphName + '_Graph';
const eRel = cgm._relation(en, vn, vn);
return [new TestGraph(gn, this.edges, eRel, vn, en, [], TestVariants.SingleServer)];
}
prepareGeneralGraphs() {
return this.generalShardings.map(numberOfShards => {
const suffix = `_${numberOfShards}shards`;
const vn = this.protoGraphName + '_Vertex' + suffix;
const en = this.protoGraphName + '_Edge' + suffix;
const gn = this.protoGraphName + '_Graph' + suffix;
const eRel = cgm._relation(en, vn, vn);
return new TestGraph(gn, this.edges, eRel, vn, en, [], TestVariants.GeneralGraph, numberOfShards);
});
}
prepareSmartGraphs() {
return this.smartShardings.map((sharding, idx) => {
const {numberOfShards, vertexSharding} = sharding;
const suffix = ProtoGraph._buildSmartSuffix(sharding, idx);
const vn = this.protoGraphName + '_Vertex' + suffix;
const en = this.protoGraphName + '_Edge' + suffix;
const gn = this.protoGraphName + '_Graph' + suffix;
const eRel = sgm._relation(en, vn, vn);
return new TestGraph(gn, this.edges, eRel, vn, en, vertexSharding, TestVariants.SmartGraph, numberOfShards);
});
}
static _buildSmartSuffix({numberOfShards, vertexSharding, name}, shardingIndex) {
if (name) {
return `_${name}`;
}
// vertexSharding is an array of pairs, each pair holding a vertex (string)
// and a shard (index), e.g. [["A", 0], ["B", 0], ["C", 1]].
// For this (with 2 shards) this will return the string
// "_2shards_s0-AB_s1-C"
let suffix = `_${numberOfShards}shards_` +
_.toPairs(
_.groupBy(vertexSharding, ([,s]) => s)
).map(
([s, vs]) => 's' + s + '-' + vs.map(([v,]) => v).join('')
).join('_');
// Override long suffixes
if (suffix.length > 40) {
suffix = `_shardingNr${shardingIndex}`;
}
return suffix;
}
}
const protoGraphs = {};
/*
* B E
*
* A D
*
* C F
*/
protoGraphs.openDiamond = new ProtoGraph("openDiamond", [
["A", "B"],
["A", "C"],
["B", "D"],
["C", "D"],
["D", "E"],
["D", "F"],
],
[1, 2, 5],
[
{
numberOfShards: 1,
vertexSharding:
[
["A", 0],
["B", 0],
["C", 0],
["D", 0],
["E", 0],
["F", 0],
],
},
{
numberOfShards: 2,
vertexSharding:
[
["A", 0],
["B", 1],
["C", 0],
["D", 0],
["E", 0],
["F", 0],
],
},
{
numberOfShards: 2,
vertexSharding:
[
["A", 0],
["B", 0],
["C", 0],
["D", 1],
["E", 0],
["F", 0],
],
},
{
numberOfShards: 2,
vertexSharding:
[
["A", 0],
["B", 0],
["C", 0],
["D", 0],
["E", 1],
["F", 1],
],
},
{
numberOfShards: 6,
vertexSharding:
[
["A", 0],
["B", 1],
["C", 2],
["D", 3],
["E", 4],
["F", 5],
],
},
]
);
/*
* B
*
* A C
*
* D
*/
protoGraphs.smallCircle = new ProtoGraph("smallCircle", [
["A", "B"],
["B", "C"],
["C", "D"],
["D", "A"]
],
[1, 2, 5],
[
{
numberOfShards: 1,
vertexSharding:
[
["A", 0],
["B", 0],
["C", 0],
["D", 0]
]
},
{
numberOfShards: 2,
vertexSharding:
[
["A", 0],
["B", 1],
["C", 0],
["D", 0]
]
},
{
numberOfShards: 4,
vertexSharding:
[
["A", 0],
["B", 1],
["C", 2],
["D", 3]
]
},
]
);
/*
* B
*
* A C // Same rules as in the picture for Node: "E"
*
* D
*/
protoGraphs.completeGraph = new ProtoGraph("completeGraph", [
["A", "B"],
["A", "C"],
["A", "D"],
["A", "E"],
["B", "A"],
["B", "C"],
["B", "D"],
["B", "E"],
["C", "A"],
["C", "B"],
["C", "D"],
["C", "E"],
["D", "A"],
["D", "B"],
["D", "C"],
["D", "E"],
["E", "A"],
["E", "B"],
["E", "C"],
["E", "D"]
],
[1, 2, 5],
[
{
numberOfShards: 1,
vertexSharding:
[
["A", 0],
["B", 0],
["C", 0],
["D", 0],
["E", 0],
]
},
{
numberOfShards: 2,
vertexSharding:
[
["A", 0],
["B", 1],
["C", 0],
["D", 1],
["E", 0]
]
},
{
numberOfShards: 5,
vertexSharding:
[
["A", 0],
["B", 1],
["C", 2],
["D", 3],
["E", 4]
]
},
]
);
/*
*
*
* A B C D E F G H I J
*
*
*/
protoGraphs.easyPath = new ProtoGraph("easyPath", [
["A", "B"],
["B", "C"],
["C", "D"],
["D", "E"],
["E", "F"],
["F", "G"],
["G", "H"],
["H", "I"],
["I", "J"]
],
[1, 2, 5],
[
{
numberOfShards: 1,
vertexSharding:
[
["A", 0],
["B", 0],
["C", 0],
["D", 0],
["E", 0],
["F", 0],
["G", 0],
["H", 0],
["I", 0],
["J", 0]
]
},
{
numberOfShards: 2,
vertexSharding:
[
["A", 0],
["B", 1],
["C", 0],
["D", 1],
["E", 0],
["F", 1],
["G", 0],
["H", 1],
["I", 0],
["J", 1]
]
},
{
numberOfShards: 4,
vertexSharding:
[
["A", 0],
["B", 1],
["C", 2],
["D", 3],
["E", 0],
["F", 1],
["G", 2],
["H", 3],
["I", 0],
["J", 1]
]
},
{
numberOfShards: 2,
vertexSharding:
[
["A", 0],
["B", 0],
["C", 0],
["D", 0],
["E", 1],
["F", 1],
["G", 1],
["H", 1],
["I", 0],
["J", 0]
]
},
]
);
/*
*
*
* A B C D E F G H I
*
*
*/
protoGraphs.advancedPath = new ProtoGraph("advancedPath", [
["A", "B"],
["A", "D"],
["B", "C"],
["C", "D"],
["D", "E"],
["E", "F"],
["E", "H"],
["F", "G"],
["G", "H"],
["H", "I"],
],
[1, 2, 5],
[
{
numberOfShards: 1,
vertexSharding:
[
["A", 0],
["B", 0],
["C", 0],
["D", 0],
["E", 0],
["F", 0],
["G", 0],
["H", 0],
["I", 0]
]
},
{
numberOfShards: 2,
vertexSharding:
[
["A", 0],
["B", 0],
["C", 0],
["D", 1],
["E", 0],
["F", 0],
["G", 0],
["H", 1],
["I", 0],
["J", 0]
]
},
{
numberOfShards: 4,
vertexSharding:
[
["A", 0],
["B", 1],
["C", 2],
["D", 3],
["E", 0],
["F", 1],
["G", 2],
["H", 3],
["I", 0],
["J", 1]
]
},
]
);
/*
* (to G)
*
* A B C D E F G H I
*
*
*/
protoGraphs.moreAdvancedPath = new ProtoGraph("moreAdvancedPath", [
["A", "B"],
["A", "D"],
["A", "G"],
["B", "C"],
["C", "D"],
["D", "E"],
["E", "F"],
["E", "H"],
["F", "G"],
["G", "H"],
["H", "I"],
],
[1, 2, 5],
[
{
numberOfShards: 1,
vertexSharding:
[
["A", 0],
["B", 0],
["C", 0],
["D", 0],
["E", 0],
["F", 0],
["G", 0],
["H", 0],
["I", 0]
]
},
{
numberOfShards: 2,
vertexSharding:
[
["A", 0],
["B", 0],
["C", 0],
["D", 1],
["E", 0],
["F", 0],
["G", 0],
["H", 1],
["I", 0],
["J", 0]
]
},
{
numberOfShards: 4,
vertexSharding:
[
["A", 0],
["B", 1],
["C", 2],
["D", 3],
["E", 0],
["F", 1],
["G", 2],
["H", 3],
["I", 0],
["J", 1]
]
},
]
);
/*
* Perfect binary tree of depth 8 (i.e. 9 levels).
* Vertices get the names "v0", "v1", ..., "v510".
* v0 is the root vertex. Edges are (v0, v1), (v0, v2), (v1, v3), ...
* Contains 511 vertices and 510 edges.
*/
{ // scope for largeBinTree-local variables
const numVertices = Math.pow(2, 9) - 1;
const parentIdx = (i) => _.floor((i - 1) / 2);
const vertices = _.range(0, numVertices)
.map(i => `v${i}`);
const edges = _.range(1, numVertices)
.map(i => [`v${parentIdx(i)}`, `v${i}`]);
assert.assertEqual(511, vertices.length);
assert.assertEqual(510, edges.length);
assert.assertEqual('v0', vertices[0]);
assert.assertEqual('v510', vertices[vertices.length - 1]);
const vi = (v) => Number(v.match(/^v(\d+)$/)[1]);
const vertexLevel = (v) => Math.floor(Math.log2(vi(v)+1));
const parent = (v) => 'v' + parentIdx(vi(v));
const ancestor = (v, i) => i === 0 ? v : ancestor(parent(v), i-1);
// when splitting the tree into perfect subtrees of depth 3 (this is
// non-ambiguous), these helper functions return, for a given vertex,
// the level inside its subtree, and its subtrees root, respectively.
const subTreeD3Level = (v) => vertexLevel(v) % 3;
const subTreeD3Root = (v) => ancestor(v, subTreeD3Level(v));
// The subtree roots are all at (2^3)^n-1..2*(2^3)^n-1 (not including the last)
// all together 73 subtrees (1 + 8 + 64)
const subTreeD3Roots = [0, ..._.range(7, 15), ..._.range(63, 127)].map(i => `v${i}`);
const subTreeD3RootToShardIdx = new Map(subTreeD3Roots.map((v, i) => [v, i]));
assert.assertEqual(73, subTreeD3Roots.length);
protoGraphs.largeBinTree = new ProtoGraph("largeBinTree",
edges,
[1, 2, 5],
[
{ // one shard
name: "oneShard",
numberOfShards: 1,
vertexSharding: vertices.map(v => [v, 0]),
},
{ // one shard per three levels
name: "oneShardPerThreeLevels",
numberOfShards: 3,
vertexSharding: vertices.map(v => [v, Math.floor(vertexLevel(v)/3)]),
},
{ // one shard per level
name: "oneShardPerLevel",
numberOfShards: 9,
vertexSharding: vertices.map(v => [v, vertexLevel(v)]),
},
{ // alternating distribution of vertices
name: "alternatingSharding",
numberOfShards: 5,
vertexSharding: vertices.map(v => [v, vi(v) % 5]),
},
{ // alternating sequence distribution of vertices
name: "alternatingSequenceSharding",
numberOfShards: 5,
vertexSharding: vertices.map(v => [v, Math.floor(vi(v) / 11) % 5]),
},
{ // most vertices in 0, but for a diagonal cut through the tree:
// v0
// v1 (v2)
// v3 (v4) v5 v6
// v7 (v8) v9 v10 v11 v12 v13 v14
// ...
name: "diagonalCutSharding",
numberOfShards: 2,
vertexSharding: vertices.map(v => [v, [2,4,8,16,32,64,128,256].includes(vi(v)) ? 1 : 0]),},
{ // perfect subtrees of depth 3, each in different shards
name: "perfectSubtreeSharding",
numberOfShards: 73,
vertexSharding: vertices.map(v => [v, subTreeD3RootToShardIdx.get(subTreeD3Root(v))]),
},
{ // perfect subtrees of depth 3 as above, but divided in fewer shards
name: "perfectSubtreeShardingWithFewShards",
numberOfShards: 5,
vertexSharding: vertices.map(v => [v, subTreeD3RootToShardIdx.get(subTreeD3Root(v)) % 5]),
},
]
);
}
exports.ProtoGraph = ProtoGraph;
exports.protoGraphs = protoGraphs;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,94 @@
/*jshint globalstrict:true, strict:true, esnext: true */
"use strict";
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2019 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Tobias Gödderz
////////////////////////////////////////////////////////////////////////////////
const {protoGraphs} = require('@arangodb/aql-graph-traversal-generic-graphs.js');
const {testsByGraph, metaTests} = require('@arangodb/aql-graph-traversal-generic-tests.js');
const jsunity = require('jsunity');
const console = require('console');
const _ = require("lodash");
function graphTraversalGenericGeneralGraphClusterSuite() {
let testGraphs = _.fromPairs(_.keys(protoGraphs).map(x => [x, {}]));
_.each(protoGraphs, function (protoGraph) {
_.each(protoGraph.prepareGeneralGraphs(), function (testGraph) {
testGraphs[protoGraph.name()][testGraph.name()] = testGraph;
});
});
const suite = {
setUpAll: function () {
try {
const numGraphs = _.sumBy(_.values(testGraphs), g => _.keys(g).length);
console.info(`Creating ${numGraphs} graphs, this might take a few seconds.`);
_.each(testGraphs, function (graphs) {
_.each(graphs, function (graph) {
graph.create();
});
});
} catch (e) {
console.error(e);
console.error(e.stack);
throw(e);
}
},
tearDownAll: function () {
try {
_.each(testGraphs, function (graphs) {
_.each(graphs, function (graph) {
graph.drop();
});
});
} catch (e) {
console.error(e);
console.error(e.stack);
throw(e);
}
}
};
_.each(metaTests, (test, testName) => {
suite[testName] = test;
});
_.each(testsByGraph, function (localTests, graphName) {
let graphs = testGraphs[graphName];
_.each(localTests, function (test, testName) {
_.each(graphs, function (graph){
suite[testName + '_' + graph.name()] = function () {
test(graph);
};
});
});
});
return suite;
}
jsunity.run(graphTraversalGenericGeneralGraphClusterSuite);
return jsunity.done();

View File

@ -0,0 +1,94 @@
/*jshint globalstrict:true, strict:true, esnext: true */
"use strict";
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2019 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Tobias Gödderz
/// @author Heiko Kernbach
////////////////////////////////////////////////////////////////////////////////
const {protoGraphs} = require('@arangodb/aql-graph-traversal-generic-graphs.js');
const {testsByGraph, metaTests} = require('@arangodb/aql-graph-traversal-generic-tests.js');
const jsunity = require("jsunity");
const _ = require("lodash");
function graphTraversalGenericGeneralGraphStandaloneSuite() {
let testGraphs = _.fromPairs(_.keys(protoGraphs).map(x => [x, {}]));
_.each(protoGraphs, function (protoGraph) {
_.each(protoGraph.prepareSingleServerGraph(), function (testGraph) {
testGraphs[protoGraph.name()][testGraph.name()] = testGraph;
});
});
const suite = {
setUpAll: function () {
try {
const numGraphs = _.sumBy(_.values(testGraphs), g => _.keys(g).length);
console.info(`Creating ${numGraphs} graphs, this might take a few seconds.`);
_.each(testGraphs, function (graphs) {
_.each(graphs, function (graph) {
graph.create();
});
});
} catch (e) {
console.error(e);
console.error(e.stack);
throw(e);
}
},
tearDownAll: function () {
try {
_.each(testGraphs, function (graphs) {
_.each(graphs, function (graph) {
graph.drop();
});
});
} catch (e) {
console.error(e);
console.error(e.stack);
throw(e);
}
}
};
_.each(metaTests, (test, testName) => {
suite[testName] = test;
});
_.each(testsByGraph, function (localTests, graphName) {
let graphs = testGraphs[graphName];
_.each(localTests, function (test, testName) {
_.each(graphs, function (graph){
suite[testName + '_' + graph.name()] = function () {
test(graph);
};
});
});
});
return suite;
}
jsunity.run(graphTraversalGenericGeneralGraphStandaloneSuite);
return jsunity.done();

View File

@ -626,28 +626,29 @@ function dumpTestEnterpriseSuite () {
assertEqual(300, c.count());
},
testAqlGraphQuery: function() {
testAqlGraphQueryOutbound: function() {
// Precondition
let c = db[edges];
const c = db[edges];
assertEqual(300, c.count());
// We first need the vertices
let vC = db[vertices];
const vC = db[vertices];
assertEqual(100, vC.count());
let vertexQuery = `FOR x IN ${vertices} FILTER x.value == "10" RETURN x._id`;
let vertex = db._query(vertexQuery).toArray();
const vertexQuery = `FOR x IN ${vertices} FILTER x.value == "10" RETURN x._id`;
const vertex = db._query(vertexQuery).toArray();
assertEqual(1, vertex.length);
let q = `FOR v IN 1..2 ANY "${vertex[0]}" GRAPH "${smartGraphName}" OPTIONS {uniqueVertices: 'path'} SORT TO_NUMBER(v.value) RETURN v`;
/* We expect the following result:
* 10 <- 9 <- 8
const q = `FOR v IN 1..2 OUTBOUND "${vertex[0]}" GRAPH "${smartGraphName}" OPTIONS {uniqueVertices: 'path'}
SORT TO_NUMBER(v.value) RETURN v`;
/* We expect the following paths:
* 10 -> 9 -> 8
* 10 <- 9
* 10 -> 11
* 10 -> 11 -> 12
*/
//Validate that everything is wired to a smart graph correctly
let res = db._query(q).toArray();
const res = db._query(q).toArray();
assertEqual(4, res.length);
assertEqual("8", res[0].value);
assertEqual("9", res[1].value);
@ -655,6 +656,40 @@ function dumpTestEnterpriseSuite () {
assertEqual("12", res[3].value);
},
testAqlGraphQueryAny: function() {
// Precondition
const c = db[edges];
assertEqual(300, c.count());
// We first need the vertices
const vC = db[vertices];
assertEqual(100, vC.count());
const vertexQuery = `FOR x IN ${vertices} FILTER x.value == "10" RETURN x._id`;
const vertex = db._query(vertexQuery).toArray();
assertEqual(1, vertex.length);
const q = `FOR v IN 1..2 ANY "${vertex[0]}" GRAPH "${smartGraphName}" OPTIONS {uniqueVertices: 'path'}
SORT TO_NUMBER(v.value) RETURN v.value`;
/* We expect the following paths:
* 10 -> 9 -> 8
* 10 -> 9 <- 8
* 10 <- 9 -> 8
* 10 <- 9 <- 8
* 10 <- 9
* 10 -> 9
* 10 -> 11
* 10 <- 11
* 10 -> 11 -> 12
* 10 -> 11 <- 12
* 10 <- 11 -> 12
* 10 <- 11 <- 12
*/
//Validate that everything is wired to a smart graph correctly
const res = db._query(q).toArray();
assertEqual('8 8 8 8 9 9 11 11 12 12 12 12'.split(' '), res);
},
testSmartGraphSharding: function () {
const eCol = db._collection(edges);
const eProp = eCol.properties();

View File

@ -607,28 +607,29 @@ function dumpTestEnterpriseSuite () {
assertEqual(300, c.count());
},
testAqlGraphQuery: function() {
testAqlGraphQueryOutbound: function() {
// Precondition
let c = db[edges];
const c = db[edges];
assertEqual(300, c.count());
// We first need the vertices
let vC = db[vertices];
const vC = db[vertices];
assertEqual(100, vC.count());
let vertexQuery = `FOR x IN ${vertices} FILTER x.value == "10" RETURN x._id`;
let vertex = db._query(vertexQuery).toArray();
const vertexQuery = `FOR x IN ${vertices} FILTER x.value == "10" RETURN x._id`;
const vertex = db._query(vertexQuery).toArray();
assertEqual(1, vertex.length);
let q = `FOR v IN 1..2 ANY "${vertex[0]}" GRAPH "${smartGraphName}" OPTIONS {uniqueVertices: 'path'} SORT TO_NUMBER(v.value) RETURN v`;
/* We expect the following result:
* 10 <- 9 <- 8
const q = `FOR v IN 1..2 OUTBOUND "${vertex[0]}" GRAPH "${smartGraphName}" OPTIONS {uniqueVertices: 'path'}
SORT TO_NUMBER(v.value) RETURN v`;
/* We expect the following paths:
* 10 -> 9 -> 8
* 10 <- 9
* 10 -> 11
* 10 -> 11 -> 12
*/
//Validate that everything is wired to a smart graph correctly
let res = db._query(q).toArray();
const res = db._query(q).toArray();
assertEqual(4, res.length);
assertEqual("8", res[0].value);
assertEqual("9", res[1].value);
@ -636,6 +637,40 @@ function dumpTestEnterpriseSuite () {
assertEqual("12", res[3].value);
},
testAqlGraphQueryAny: function() {
// Precondition
const c = db[edges];
assertEqual(300, c.count());
// We first need the vertices
const vC = db[vertices];
assertEqual(100, vC.count());
const vertexQuery = `FOR x IN ${vertices} FILTER x.value == "10" RETURN x._id`;
const vertex = db._query(vertexQuery).toArray();
assertEqual(1, vertex.length);
const q = `FOR v IN 1..2 ANY "${vertex[0]}" GRAPH "${smartGraphName}" OPTIONS {uniqueVertices: 'path'}
SORT TO_NUMBER(v.value) RETURN v.value`;
/* We expect the following paths:
* 10 -> 9 -> 8
* 10 -> 9 <- 8
* 10 <- 9 -> 8
* 10 <- 9 <- 8
* 10 <- 9
* 10 -> 9
* 10 -> 11
* 10 <- 11
* 10 -> 11 -> 12
* 10 -> 11 <- 12
* 10 <- 11 -> 12
* 10 <- 11 <- 12
*/
//Validate that everything is wired to a smart graph correctly
const res = db._query(q).toArray();
assertEqual('8 8 8 8 9 9 11 11 12 12 12 12'.split(' '), res);
},
testSmartGraphSharding: function () {
const eCol = db._collection(edges);
const eProp = eCol.properties();

View File

@ -38,7 +38,7 @@ const isEnterprise = require("internal").isEnterprise();
* That has 100 orphans (value 0 -> 99)
* That has 300 edges, for each value i:
* Connect i -> i
* Connect i - 1 -> i
* Connect i - 1 <- i
* Connect i -> i + 1
*/
const setupSmartGraph = function () {