1
0
Fork 0
arangodb/js/server/tests/aql/aql-graph.js

1187 lines
42 KiB
JavaScript

/*jshint globalstrict:false, strict:false, sub: true, maxlen: 500 */
/*global assertEqual, assertTrue, fail */
////////////////////////////////////////////////////////////////////////////////
/// @brief tests for query language, graph functions
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens 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 triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var jsunity = require("jsunity");
var db = require("@arangodb").db;
var internal = require("internal");
var errors = internal.errors;
var helper = require("@arangodb/aql-helper");
var cluster = require("@arangodb/cluster");
var getQueryResults = helper.getQueryResults;
var getRawQueryResults = helper.getRawQueryResults;
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite for graph features
////////////////////////////////////////////////////////////////////////////////
function ahuacatlQueryEdgesTestSuite () {
var vertex = null;
var edge = null;
var vn = "UnitTestsAhuacatlVertex";
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUpAll : function () {
db._drop(vn);
db._drop("UnitTestsAhuacatlEdge");
vertex = db._create(vn, {numberOfShards: 4});
edge = db._createEdgeCollection("UnitTestsAhuacatlEdge", {numberOfShards: 4});
vertex.save({ _key: "v1", name: "v1" });
vertex.save({ _key: "v2", name: "v2" });
vertex.save({ _key: "v3", name: "v3" });
vertex.save({ _key: "v4", name: "v4" });
vertex.save({ _key: "v5", name: "v5" });
vertex.save({ _key: "v6", name: "v6" });
vertex.save({ _key: "v7", name: "v7" });
function makeEdge (from, to) {
edge.save(vn + "/" + from, vn + "/" + to, { _key: from + "" + to, what: from + "->" + to });
}
makeEdge("v1", "v2");
makeEdge("v1", "v3");
makeEdge("v2", "v3");
makeEdge("v3", "v4");
makeEdge("v3", "v6");
makeEdge("v3", "v7");
makeEdge("v4", "v2");
makeEdge("v7", "v3");
makeEdge("v6", "v3");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDownAll : function () {
db._drop("UnitTestsAhuacatlVertex");
db._drop("UnitTestsAhuacatlEdge");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief checks edges ANY
////////////////////////////////////////////////////////////////////////////////
testEdgesAny : function () {
var q = `WITH ${vn} FOR v, e IN ANY @start UnitTestsAhuacatlEdge SORT e.what RETURN e.what`;
var actual;
actual = getQueryResults(q, {start: "UnitTestsAhuacatlVertex/v1"});
assertEqual(actual, [ "v1->v2", "v1->v3" ]);
actual = getQueryResults(q, {start: "UnitTestsAhuacatlVertex/v2"});
assertEqual(actual, [ "v1->v2", "v2->v3", "v4->v2" ]);
actual = getQueryResults(q, {start: "UnitTestsAhuacatlVertex/v3"});
assertEqual(actual, [ "v1->v3", "v2->v3", "v3->v4", "v3->v6", "v3->v7", "v6->v3", "v7->v3" ]);
actual = getQueryResults(q, {start: "UnitTestsAhuacatlVertex/v8"});
assertEqual(actual, [ ]);
actual = getQueryResults(q, {start: "UnitTestsAhuacatlVertex/thefox"});
assertEqual(actual, [ ]);
actual = getQueryResults(q, {start: "thefox/thefox"});
assertEqual(actual, [ ]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief checks edges INBOUND
////////////////////////////////////////////////////////////////////////////////
testEdgesIn : function () {
var q = `WITH ${vn} FOR v, e IN INBOUND @start UnitTestsAhuacatlEdge SORT e.what RETURN e.what`;
var actual;
actual = getQueryResults(q, {start: "UnitTestsAhuacatlVertex/v1"});
assertEqual(actual, [ ]);
actual = getQueryResults(q, {start: "UnitTestsAhuacatlVertex/v2"});
assertEqual(actual, [ "v1->v2", "v4->v2" ]);
actual = getQueryResults(q, {start: "UnitTestsAhuacatlVertex/v3"});
assertEqual(actual, [ "v1->v3", "v2->v3", "v6->v3", "v7->v3" ]);
actual = getQueryResults(q, {start: "UnitTestsAhuacatlVertex/v8"});
assertEqual(actual, [ ]);
actual = getQueryResults(q, {start: "UnitTestsAhuacatlVertex/thefox"});
assertEqual(actual, [ ]);
actual = getQueryResults(q, {start: "thefox/thefox"});
assertEqual(actual, [ ]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief checks edges OUTBOUND
////////////////////////////////////////////////////////////////////////////////
testEdgesOut : function () {
var q = `WITH ${vn} FOR v, e IN OUTBOUND @start UnitTestsAhuacatlEdge SORT e.what RETURN e.what`;
var actual;
actual = getQueryResults(q, {start: "UnitTestsAhuacatlVertex/v1"});
assertEqual(actual, [ "v1->v2", "v1->v3" ]);
actual = getQueryResults(q, {start: "UnitTestsAhuacatlVertex/v2"});
assertEqual(actual, [ "v2->v3" ]);
actual = getQueryResults(q, {start: "UnitTestsAhuacatlVertex/v3"});
assertEqual(actual, [ "v3->v4", "v3->v6", "v3->v7" ]);
actual = getQueryResults(q, {start: "UnitTestsAhuacatlVertex/v8"});
assertEqual(actual, [ ]);
actual = getQueryResults(q, {start: "UnitTestsAhuacatlVertex/thefox"});
assertEqual(actual, [ ]);
actual = getQueryResults(q, {start: "thefox/thefox"});
assertEqual(actual, [ ]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief checks edges / vertex combination
////////////////////////////////////////////////////////////////////////////////
testEdgesAnyInclVertices : function () {
"use strict";
let actual;
var query = `WITH ${vn} FOR v, e IN ANY @start @@col SORT e.what RETURN v._key`;
let bindVars = {
"@col": "UnitTestsAhuacatlEdge"
};
bindVars.start = "UnitTestsAhuacatlVertex/v1";
actual = getQueryResults(query, bindVars);
assertEqual(actual, ["v2", "v3"]);
bindVars.start = "UnitTestsAhuacatlVertex/v2";
actual = getQueryResults(query, bindVars);
assertEqual(actual, ["v1", "v3", "v4"]);
bindVars.start = "UnitTestsAhuacatlVertex/v3";
actual = getQueryResults(query, bindVars);
assertEqual(actual, ["v1", "v2", "v4", "v6", "v7", "v6", "v7"]);
bindVars.start = "UnitTestsAhuacatlVertex/v8";
actual = getQueryResults(query, bindVars);
assertEqual(actual, [ ]);
bindVars.start = "UnitTestsAhuacatlVertex/thefox";
actual = getQueryResults(query, bindVars);
assertEqual(actual, [ ]);
bindVars.start = "thefox/thefox";
actual = getQueryResults(query, bindVars);
assertEqual(actual, [ ]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief checks edges / vertex combination
////////////////////////////////////////////////////////////////////////////////
testEdgesInInclVertices : function () {
"use strict";
let actual;
let query = `WITH ${vn} FOR v, e IN INBOUND @start @@col SORT e.what RETURN v._key`;
let bindVars = {
"@col": "UnitTestsAhuacatlEdge",
};
bindVars.start = "UnitTestsAhuacatlVertex/v1";
actual = getQueryResults(query, bindVars);
assertEqual(actual, []);
bindVars.start = "UnitTestsAhuacatlVertex/v2";
actual = getQueryResults(query, bindVars);
assertEqual(actual, ["v1", "v4"]);
bindVars.start = "UnitTestsAhuacatlVertex/v3";
actual = getQueryResults(query, bindVars);
assertEqual(actual, ["v1", "v2", "v6", "v7"]);
bindVars.start = "UnitTestsAhuacatlVertex/v8";
actual = getQueryResults(query, bindVars);
assertEqual(actual, [ ]);
bindVars.start = "UnitTestsAhuacatlVertex/thefox";
actual = getQueryResults(query, bindVars);
assertEqual(actual, [ ]);
bindVars.start = "thefox/thefox";
actual = getQueryResults(query, bindVars);
assertEqual(actual, [ ]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief checks edges / vertex combination
////////////////////////////////////////////////////////////////////////////////
testEdgesOutInclVertices : function () {
"use strict";
let actual;
let query = `WITH ${vn} FOR v, e IN OUTBOUND @start @@col SORT e.what RETURN v._key`;
let bindVars = {
"@col": "UnitTestsAhuacatlEdge",
};
bindVars.start = "UnitTestsAhuacatlVertex/v1";
actual = getQueryResults(query, bindVars);
assertEqual(actual, ["v2", "v3"]);
bindVars.start = "UnitTestsAhuacatlVertex/v2";
actual = getQueryResults(query, bindVars);
assertEqual(actual, ["v3"]);
bindVars.start = "UnitTestsAhuacatlVertex/v3";
actual = getQueryResults(query, bindVars);
assertEqual(actual, ["v4", "v6", "v7"]);
bindVars.start = "UnitTestsAhuacatlVertex/v8";
actual = getQueryResults(query, bindVars);
assertEqual(actual, [ ]);
bindVars.start = "UnitTestsAhuacatlVertex/v5";
actual = getQueryResults(query, bindVars);
assertEqual(actual, [ ]);
bindVars.start = "UnitTestsAhuacatlVertex/thefox";
actual = getQueryResults(query, bindVars);
assertEqual(actual, [ ]);
bindVars.start = "thefox/thefox";
actual = getQueryResults(query, bindVars);
assertEqual(actual, [ ]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief checks edges with filter
////////////////////////////////////////////////////////////////////////////////
testEdgesFilterExample : function () {
var q;
var bindVars = {start: "UnitTestsAhuacatlVertex/v3"};
var actual;
q = `WITH ${vn} FOR v, e IN ANY @start UnitTestsAhuacatlEdge
FILTER e.what == "v1->v3"
SORT e.what RETURN e.what`;
actual = getQueryResults(q, bindVars);
assertEqual(actual, [ "v1->v3" ]);
q = `WITH ${vn} FOR v, e IN ANY @start UnitTestsAhuacatlEdge
FILTER e.what == "v1->v3" OR e.what == "v3->v6"
SORT e.what RETURN e.what`;
actual = getQueryResults(q, bindVars);
assertEqual(actual, [ "v1->v3", "v3->v6"]);
q = `WITH ${vn} FOR v, e IN ANY @start UnitTestsAhuacatlEdge
SORT e.what RETURN e.what`;
actual = getQueryResults(q, bindVars);
assertEqual(actual, [ "v1->v3", "v2->v3", "v3->v4", "v3->v6", "v3->v7", "v6->v3", "v7->v3" ]);
q = `WITH ${vn} FOR v, e IN ANY @start UnitTestsAhuacatlEdge
FILTER e.non == "matchable"
SORT e.what RETURN e.what`;
actual = getQueryResults(q, bindVars);
assertEqual(actual, [ ]);
q = `WITH ${vn} FOR v, e IN ANY @start UnitTestsAhuacatlEdge
FILTER e.what == "v1->v3" OR e.non == "matchable"
SORT e.what RETURN e.what`;
actual = getQueryResults(q, bindVars);
assertEqual(actual, [ "v1->v3" ]);
q = `WITH ${vn} FOR v, e IN ANY @start UnitTestsAhuacatlEdge
FILTER e.what == "v3->v6"
SORT e.what RETURN e.what`;
actual = getQueryResults(q, bindVars);
assertEqual(actual, [ "v3->v6" ]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief checks edges when starting with an array
////////////////////////////////////////////////////////////////////////////////
testEdgesStartVertexArray : function () {
var q = `WITH ${vn} FOR s IN @start FOR v, e IN OUTBOUND s UnitTestsAhuacatlEdge SORT e.what RETURN e.what`;
var actual;
actual = getQueryResults(q, {start: [ "UnitTestsAhuacatlVertex/v1", "UnitTestsAhuacatlVertex/v2" ]});
assertEqual(actual, [ "v1->v2", "v1->v3", "v2->v3" ]);
actual = getQueryResults(q, {start: [ {_id: "UnitTestsAhuacatlVertex/v1"}, {_id: "UnitTestsAhuacatlVertex/v2"} ]});
assertEqual(actual, [ "v1->v2", "v1->v3", "v2->v3" ]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief checks edges when starting on an object
////////////////////////////////////////////////////////////////////////////////
testEdgesStartVertexObject : function () {
var q = `WITH ${vn} FOR v, e IN OUTBOUND @start UnitTestsAhuacatlEdge SORT e.what RETURN e.what`;
var actual;
actual = getQueryResults(q, {start: { _id: "UnitTestsAhuacatlVertex/v1" }});
assertEqual(actual, [ "v1->v2", "v1->v3" ]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief checks edges with illegal start
////////////////////////////////////////////////////////////////////////////////
testEdgesStartVertexIllegal : function () {
var q = `WITH ${vn} FOR v, e IN OUTBOUND @start UnitTestsAhuacatlEdge SORT e.what RETURN e.what`;
var qArray = `WITH ${vn} FOR s IN @start FOR v, e IN OUTBOUND s UnitTestsAhuacatlEdge SORT e.what RETURN e.what`;
var actual;
var bindVars = {start: {_id: "v1"}}; // No collection
actual = getQueryResults(q, bindVars);
assertEqual(actual, [ ]);
bindVars = {start: "UnitTestTheFuxx/v1"}; // Non existing collection
actual = getQueryResults(q, bindVars);
assertEqual(actual, [ ]);
bindVars = {start: { id: "UnitTestTheFuxx/v1"}}; // No _id attribute
actual = getQueryResults(q, bindVars);
assertEqual(actual, [ ]);
bindVars = {start: [{ id: "UnitTestTheFuxx/v1" }] }; // Error in Array
actual = getQueryResults(qArray, bindVars);
// No Error thrown here
assertEqual(actual, [ ]);
bindVars = {start: ["UnitTestTheFuxx/v1"] }; // Error in Array
actual = getQueryResults(qArray, bindVars);
// No Error thrown here
assertEqual(actual, [ ]);
bindVars = {start: ["v1"] }; // Error in Array
actual = getQueryResults(qArray, bindVars);
// No Error thrown here
assertEqual(actual, [ ]);
}
};
}
function ahuacatlQueryNeighborsTestSuite () {
var vertex = null;
var edge = null;
var vn = "UnitTestsAhuacatlVertex";
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUpAll : function () {
db._drop(vn);
db._drop("UnitTestsAhuacatlEdge");
vertex = db._create(vn, {numberOfShards: 4});
edge = db._createEdgeCollection("UnitTestsAhuacatlEdge", {numberOfShards: 4});
vertex.save({ _key: "v1", name: "v1" });
vertex.save({ _key: "v2", name: "v2" });
vertex.save({ _key: "v3", name: "v3" });
vertex.save({ _key: "v4", name: "v4" });
vertex.save({ _key: "v5", name: "v5" });
vertex.save({ _key: "v6", name: "v6" });
vertex.save({ _key: "v7", name: "v7" });
function makeEdge (from, to) {
edge.save(vn + "/" + from, vn + "/" + to, { what: from + "->" + to, _key: from + "_" + to });
}
makeEdge("v1", "v2");
makeEdge("v1", "v3");
makeEdge("v2", "v3");
makeEdge("v3", "v4");
makeEdge("v3", "v6");
makeEdge("v3", "v7");
makeEdge("v4", "v2");
makeEdge("v7", "v3");
makeEdge("v6", "v3");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDownAll : function () {
db._drop(vn);
db._drop("UnitTestsAhuacatlEdge");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief checks neighbors
////////////////////////////////////////////////////////////////////////////////
testNeighborsAny : function () {
var actual;
var v1 = "UnitTestsAhuacatlVertex/v1";
var v2 = "UnitTestsAhuacatlVertex/v2";
var v3 = "UnitTestsAhuacatlVertex/v3";
var v4 = "UnitTestsAhuacatlVertex/v4";
var v5 = "UnitTestsAhuacatlVertex/v5";
var v6 = "UnitTestsAhuacatlVertex/v6";
var v7 = "UnitTestsAhuacatlVertex/v7";
var v8 = "UnitTestsAhuacatlVertex/v8";
var theFox = "UnitTestsAhuacatlVertex/thefox";
var queryStart = `WITH ${vn} FOR n IN ANY "`;
var queryEnd = `" UnitTestsAhuacatlEdge OPTIONS {bfs: true, uniqueVertices: "global"} SORT n._id RETURN n._id`;
var queryEndData = `" UnitTestsAhuacatlEdge OPTIONS {bfs: true, uniqueVertices: "global"} SORT n RETURN n`;
actual = getQueryResults(queryStart + v1 + queryEnd);
assertEqual(actual, [ v2, v3 ]);
actual = getQueryResults(queryStart + v2 + queryEnd);
assertEqual(actual, [ v1, v3, v4 ]);
// v6 and v7 are neighbors twice
actual = getQueryResults(queryStart + v3 + queryEnd);
assertEqual(actual, [ v1, v2, v4, v6, v7 ]);
actual = getQueryResults(queryStart + v8 + queryEnd);
assertEqual(actual, [ ]);
actual = getQueryResults(queryStart + v5 + queryEnd);
assertEqual(actual, [ ]);
actual = getQueryResults(queryStart + theFox + queryEnd);
assertEqual(actual, [ ]);
actual = getQueryResults(queryStart + "thefox/thefox" + queryEnd);
assertEqual(actual, [ ]);
// Including Data
actual = getRawQueryResults(queryStart + v3 + queryEndData);
actual = actual.map(function(x) {
assertTrue(x.hasOwnProperty("_key"), "Neighbor has a _key");
assertTrue(x.hasOwnProperty("_rev"), "Neighbor has a _rev");
assertTrue(x.hasOwnProperty("_id"), "Neighbor has a _id");
assertTrue(x.hasOwnProperty("name"), "Neighbor has a custom attribute");
return x.name;
});
assertEqual(actual, ["v1", "v2", "v4", "v6", "v7"]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief checks neighbors inbound
////////////////////////////////////////////////////////////////////////////////
testNeighborsIn : function () {
var actual;
var v1 = "UnitTestsAhuacatlVertex/v1";
var v2 = "UnitTestsAhuacatlVertex/v2";
var v3 = "UnitTestsAhuacatlVertex/v3";
var v4 = "UnitTestsAhuacatlVertex/v4";
var v5 = "UnitTestsAhuacatlVertex/v5";
var v6 = "UnitTestsAhuacatlVertex/v6";
var v7 = "UnitTestsAhuacatlVertex/v7";
var v8 = "UnitTestsAhuacatlVertex/v8";
var theFox = "UnitTestsAhuacatlVertex/thefox";
var queryStart = `WITH ${vn} FOR n IN INBOUND "`;
var queryEnd = `" UnitTestsAhuacatlEdge OPTIONS {bfs: true, uniqueVertices: "global"} SORT n._id RETURN n._id`;
var queryEndData = `" UnitTestsAhuacatlEdge OPTIONS {bfs: true, uniqueVertices: "global"} SORT n RETURN n`;
actual = getQueryResults(queryStart + v1 + queryEnd);
assertEqual(actual, [ ]);
actual = getQueryResults(queryStart + v2 + queryEnd);
assertEqual(actual, [v1, v4]);
actual = getQueryResults(queryStart + v3 + queryEnd);
assertEqual(actual, [v1, v2, v6, v7]);
actual = getQueryResults(queryStart + v8 + queryEnd);
assertEqual(actual, [ ]);
actual = getQueryResults(queryStart + v5 + queryEnd);
assertEqual(actual, [ ]);
actual = getQueryResults(queryStart + theFox + queryEnd);
assertEqual(actual, [ ]);
actual = getQueryResults(queryStart + "thefox/thefox" + queryEnd);
assertEqual(actual, [ ]);
// Inclunding Data
actual = getRawQueryResults(queryStart + v3 + queryEndData);
actual = actual.map(function(x) {
assertTrue(x.hasOwnProperty("_key"), "Neighbor has a _key");
assertTrue(x.hasOwnProperty("_rev"), "Neighbor has a _rev");
assertTrue(x.hasOwnProperty("_id"), "Neighbor has a _id");
assertTrue(x.hasOwnProperty("name"), "Neighbor has a custom attribute");
return x.name;
});
assertEqual(actual, ["v1", "v2", "v6", "v7"]);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief checks outbound neighbors
////////////////////////////////////////////////////////////////////////////////
testNeighborsOut : function () {
var actual;
var v1 = "UnitTestsAhuacatlVertex/v1";
var v2 = "UnitTestsAhuacatlVertex/v2";
var v3 = "UnitTestsAhuacatlVertex/v3";
var v4 = "UnitTestsAhuacatlVertex/v4";
var v5 = "UnitTestsAhuacatlVertex/v5";
var v6 = "UnitTestsAhuacatlVertex/v6";
var v7 = "UnitTestsAhuacatlVertex/v7";
var v8 = "UnitTestsAhuacatlVertex/v8";
var theFox = "UnitTestsAhuacatlVertex/thefox";
var queryStart = `WITH ${vn} FOR n IN OUTBOUND "`;
var queryEnd = `" UnitTestsAhuacatlEdge OPTIONS {bfs: true, uniqueVertices: "global"} SORT n._id RETURN n._id`;
var queryEndData = `" UnitTestsAhuacatlEdge OPTIONS {bfs: true, uniqueVertices: "global"} SORT n RETURN n`;
actual = getQueryResults(queryStart + v1 + queryEnd);
assertEqual(actual, [ v2, v3 ]);
actual = getQueryResults(queryStart + v2 + queryEnd);
assertEqual(actual, [ v3 ]);
actual = getQueryResults(queryStart + v3 + queryEnd);
assertEqual(actual, [ v4, v6, v7 ]);
actual = getQueryResults(queryStart + v8 + queryEnd);
assertEqual(actual, [ ]);
actual = getQueryResults(queryStart + v5 + queryEnd);
assertEqual(actual, [ ]);
actual = getQueryResults(queryStart + theFox + queryEnd);
assertEqual(actual, [ ]);
actual = getQueryResults(queryStart + "thefox/thefox" + queryEnd);
assertEqual(actual, [ ]);
// Inclunding Data
actual = getRawQueryResults(queryStart + v3 + queryEndData);
actual = actual.map(function(x) {
assertTrue(x.hasOwnProperty("_key"), "Neighbor has a _key");
assertTrue(x.hasOwnProperty("_rev"), "Neighbor has a _rev");
assertTrue(x.hasOwnProperty("_id"), "Neighbor has a _id");
assertTrue(x.hasOwnProperty("name"), "Neighbor has a custom attribute");
return x.name;
});
assertEqual(actual, ["v4", "v6", "v7"]);
},
testNeighborsEdgeExamples : function () {
var actual;
var v3 = "UnitTestsAhuacatlVertex/v3";
var v4 = "UnitTestsAhuacatlVertex/v4";
var v6 = "UnitTestsAhuacatlVertex/v6";
var v7 = "UnitTestsAhuacatlVertex/v7";
var createQuery = function (start, filter) {
return `WITH ${vn} FOR n, e IN OUTBOUND "${start}" UnitTestsAhuacatlEdge OPTIONS {bfs: true} ${filter} SORT n._id RETURN n._id`;
};
// An empty filter should let all edges through
actual = getQueryResults(createQuery(v3, ""));
assertEqual(actual, [ v4, v6, v7 ]);
// Should be able to handle exactly one object
actual = getQueryResults(createQuery(v3, 'FILTER e.what == "v3->v4"'));
assertEqual(actual, [ v4 ]);
// Should be able to handle a list of objects
actual = getQueryResults(createQuery(v3, 'FILTER e.what == "v3->v4" OR e.what == "v3->v6"'));
assertEqual(actual, [ v4, v6 ]);
// Should be able to handle an id as string
actual = getQueryResults(createQuery(v3, 'FILTER e._id == "UnitTestsAhuacatlEdge/v3_v6"'));
assertEqual(actual, [ v6 ]);
// Should be able to handle a mix of id and objects
actual = getQueryResults(createQuery(v3, 'FILTER e._id == "UnitTestsAhuacatlEdge/v3_v6" OR e.what == "v3->v4"'));
assertEqual(actual, [ v4, v6 ]);
// Should be able to handle internal attributes
actual = getQueryResults(createQuery(v3, `FILTER e._to == "${v4}"`));
assertEqual(actual, [ v4 ]);
}
};
}
function ahuacatlQueryBreadthFirstTestSuite () {
let vertex = null;
let edge = null;
const vn = "UnitTestsAhuacatlVertex";
const en = "UnitTestsAhuacatlEdge";
const center = vn + "/A";
let cleanUp = function () {
db._drop(vn);
db._drop(en);
};
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
///
///
/// Graph Under Test:
/// +---------+---------+
/// \|/ | \|/
/// D <- B <- A -> E -> F
/// | /|\ |
/// | | |
/// +--> C <--+
////////////////////////////////////////////////////////////////////////////////
setUpAll : function () {
cleanUp();
vertex = db._create(vn, {numberOfShards: 4});
edge = db._createEdgeCollection(en, {numberOfShards: 4});
vertex.save({_key: "A"});
vertex.save({_key: "B"});
vertex.save({_key: "C"});
vertex.save({_key: "D"});
vertex.save({_key: "E"});
vertex.save({_key: "F"});
let makeEdge = function(from, to, type) {
edge.save({
_from: vn + "/" + from,
_to: vn + "/" + to,
_key: from + "" + to,
type: type
});
};
makeEdge("A", "B","friend");
makeEdge("A", "D","friend");
makeEdge("A", "E","enemy");
makeEdge("A", "F","enemy");
makeEdge("B", "C","enemy");
makeEdge("B", "D","friend");
makeEdge("E", "C","enemy");
makeEdge("E", "F","friend");
makeEdge("C","A","friend");
},
tearDownAll : cleanUp,
testNonUniqueVerticesDefaultDepth : function() {
var query = `WITH ${vn}
FOR v IN OUTBOUND "${center}" ${en}
OPTIONS {bfs: true}
SORT v._key RETURN v._key`;
var actual = getQueryResults(query);
assertEqual(actual.length, 4);
assertEqual(actual, [ "B","D","E","F" ]);
},
testNonUniqueVerticesMaxDepth2 : function() {
var query = `WITH ${vn}
FOR v IN 1..2 OUTBOUND "${center}" ${en}
OPTIONS {bfs: true}
SORT v._key RETURN v._key`;
var actual = getQueryResults(query);
assertEqual(actual.length, 8);
assertEqual(actual, [ "B","C","C","D","D","E","F","F" ]);
},
testNonUniqueVerticesMinDepth0 : function() {
var query = `WITH ${vn}
FOR v IN 0..2 OUTBOUND "${center}" ${en}
OPTIONS {bfs: true}
SORT v._key RETURN v._key`;
var actual = getQueryResults(query);
assertEqual(actual.length, 9);
assertEqual(actual, [ "A","B","C","C","D","D","E","F","F" ]);
},
testNonUniqueVerticesMinDepth2 : function() {
var query = `WITH ${vn}
FOR v IN 2..2 OUTBOUND "${center}" ${en}
OPTIONS {bfs: true}
SORT v._key RETURN v._key`;
var actual = getQueryResults(query);
assertEqual(actual.length, 4);
assertEqual(actual, [ "C","C","D","F" ]);
},
testUniqueVerticesMaxDepth2 : function () {
var query = `WITH ${vn}
FOR v IN 1..2 OUTBOUND "${center}" ${en}
OPTIONS {bfs: true, uniqueVertices: 'global'}
SORT v._key RETURN v._key`;
var actual = getQueryResults(query);
assertEqual(actual.length, 5);
assertEqual(actual, [ "B","C","D","E","F" ]);
},
testUniqueVerticesMinDepth0 : function () {
var query = `WITH ${vn}
FOR v IN 0..3 OUTBOUND "${center}" ${en}
OPTIONS {bfs: true, uniqueVertices: 'global'}
SORT v._key RETURN v._key`;
var actual = getQueryResults(query);
assertEqual(actual.length, 6);
assertEqual(actual, [ "A","B","C","D","E","F" ]);
},
testUniqueVerticesMinDepth2 : function () {
var query = `WITH ${vn}
FOR v IN 2..2 OUTBOUND "${center}" ${en}
OPTIONS {bfs: true, uniqueVertices: 'global'}
SORT v._key RETURN v._key`;
var actual;
// A is directly connected to every other vertex accept "C"
// So we expect only C to be returned.
actual = getQueryResults(query);
assertEqual(actual.length, 1);
assertEqual(actual, [ "C" ]);
},
testNonUniqueEdgesDefaultDepth : function() {
var query = `WITH ${vn}
FOR v,e IN OUTBOUND "${center}" ${en}
OPTIONS {bfs: true}
SORT e._key RETURN e._key`;
var actual = getQueryResults(query);
assertEqual(actual.length, 4);
assertEqual(actual, [ "AB","AD","AE","AF" ]);
},
testNonUniqueEdgesMaxDepth2 : function() {
var query = `WITH ${vn}
FOR v,e IN 1..3 OUTBOUND "${center}" ${en}
OPTIONS {bfs: true}
SORT e._key RETURN e._key`;
var actual = getQueryResults(query);
assertEqual(actual.length, 10);
assertEqual(actual, [ "AB","AD","AE","AF","BC","BD","CA","CA","EC","EF" ]);
},
testNonUniqueEdgesMinDepth0 : function() {
var query = `WITH ${vn}
FOR v,e IN 0..3 OUTBOUND "${center}" ${en}
OPTIONS {bfs: false}
SORT e._key RETURN e._key`;
var actual = getQueryResults(query);
assertEqual(actual.length, 11);
assertEqual(actual, [ null,"AB","AD","AE","AF","BC","BD","CA","CA","EC","EF" ]);
},
testNonUniqueEdgesMinDepth2 : function() {
var query = `WITH ${vn}
FOR v,e IN 2..3 OUTBOUND "${center}" ${en}
OPTIONS {bfs: true}
SORT e._key RETURN e._key`;
var actual = getQueryResults(query);
assertEqual(actual.length, 6);
assertEqual(actual, [ "BC","BD","CA","CA","EC","EF" ]);
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite for SHORTEST_PATH
////////////////////////////////////////////////////////////////////////////////
function ahuacatlQueryShortestPathTestSuite () {
var vn = "UnitTestsTraversalVertices";
var en = "UnitTestsTraversalEdges";
var vertexCollection;
var edgeCollection;
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUpAll : function () {
db._drop(vn);
db._drop(en);
vertexCollection = db._create(vn, {numberOfShards: 4});
edgeCollection = db._createEdgeCollection(en, {numberOfShards: 4});
[ "A", "B", "C", "D", "E", "F", "G", "H" ].forEach(function (item) {
vertexCollection.save({ _key: item, name: item });
});
[ [ "A", "B", 1 ], [ "B", "C", 5 ], [ "C", "D", 1 ], [ "A", "D", 12 ], [ "D", "C", 3 ], [ "C", "B", 2 ], [ "D", "E", 6 ], [ "B", "F", 1 ], [ "E", "G", 5 ], [ "G", "H", 2 ] ].forEach(function (item) {
var l = item[0];
var r = item[1];
var w = item[2];
edgeCollection.save(vn + "/" + l, vn + "/" + r, { _key: l + r, what : l + "->" + r, weight: w });
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDownAll : function () {
db._drop(vn);
db._drop(en);
vertexCollection = null;
edgeCollection = null;
},
////////////////////////////////////////////////////////////////////////////////
/// @brief shortest path using dijkstra default config
////////////////////////////////////////////////////////////////////////////////
testShortestPathDijkstraOutbound : function () {
var query = `WITH ${vn}
LET p = (FOR v, e IN OUTBOUND SHORTEST_PATH "${vn}/A" TO "${vn}/H" ${en} RETURN {v: v._id, e: e._id})
LET edges = (FOR e IN p[*].e FILTER e != null RETURN e)
LET vertices = p[*].v
LET distance = LENGTH(edges)
RETURN {edges, vertices, distance}`;
var actual = getQueryResults(query);
assertEqual([
{
vertices: [
vn + "/A",
vn + "/D",
vn + "/E",
vn + "/G",
vn + "/H"
],
edges: [
en + "/AD",
en + "/DE",
en + "/EG",
en + "/GH"
],
distance: 4
}
], actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief shortest path using dijkstra with includeData: true
////////////////////////////////////////////////////////////////////////////////
testShortestPathDijkstraOutboundIncludeData : function () {
var query = `WITH ${vn}
LET p = (FOR v, e IN OUTBOUND SHORTEST_PATH "${vn}/A" TO "${vn}/H" ${en} RETURN {v, e})
LET edges = (FOR e IN p[*].e FILTER e != null RETURN e)
LET vertices = p[*].v
LET distance = LENGTH(edges)
RETURN {edges, vertices, distance}`;
var actual = getQueryResults(query);
assertEqual(actual.length, 1);
assertTrue(actual[0].hasOwnProperty("vertices"));
assertTrue(actual[0].hasOwnProperty("edges"));
var vertices = actual[0].vertices;
var edges = actual[0].edges;
assertEqual(vertices.length, edges.length + 1);
var correct = ["A", "D", "E", "G", "H"];
for (var i = 0; i < edges.length; ++i) {
assertEqual(vertices[i]._key, correct[i]);
assertEqual(vertices[i].name, correct[i]);
assertEqual(vertices[i + 1].name, correct[i + 1]);
assertEqual(edges[i]._key, correct[i] + correct[i + 1]);
assertEqual(edges[i].what, correct[i] + "->" + correct[i + 1]);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief shortest path using dijkstra
////////////////////////////////////////////////////////////////////////////////
testShortestPathDijkstraInbound : function () {
var query = `WITH ${vn} FOR v IN INBOUND SHORTEST_PATH "${vn}/H" TO "${vn}/A" ${en} RETURN v._id`;
var actual = getQueryResults(query);
assertEqual([ vn + "/H", vn + "/G", vn + "/E", vn + "/D", vn + "/A" ], actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief shortest path with custom distance function
////////////////////////////////////////////////////////////////////////////////
testShortestPathDijkstraDistance : function () {
var query = `WITH ${vn} FOR v IN OUTBOUND SHORTEST_PATH "${vn}/A" TO "${vn}/H" ${en} OPTIONS {weightAttribute: "weight"} RETURN v._key`;
var actual = getQueryResults(query);
assertEqual([ "A", "B", "C", "D", "E", "G", "H" ], actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief shortest path, with cycles
////////////////////////////////////////////////////////////////////////////////
testShortestPathDijkstraCycles : function () {
[ [ "B", "A" ], [ "C", "A" ], [ "D", "B" ] ].forEach(function (item) {
var l = item[0];
var r = item[1];
edgeCollection.save(vn + "/" + l, vn + "/" + r, { _key: l + r, what : l + "->" + r });
});
var query = `WITH ${vn} FOR v IN OUTBOUND SHORTEST_PATH "${vn}/A" TO "${vn}/H" ${en} RETURN v._key`;
var actual = getQueryResults(query);
assertEqual(["A","D","E","G","H"], actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief shortest path, non-connected vertices
////////////////////////////////////////////////////////////////////////////////
testShortestPathDijkstraNotConnected : function () {
// this item is not connected to any other
vertexCollection.save({ _key: "J", name: "J" });
var query = `FOR v IN OUTBOUND SHORTEST_PATH "${vn}/A" TO "${vn}/J" ${en} RETURN v._key`;
var actual = getQueryResults(query);
assertEqual([ ], actual);
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite for Neighbors with intentional failures
////////////////////////////////////////////////////////////////////////////////
function ahuacatlQueryNeighborsErrorsSuite () {
var vn = "UnitTestsTraversalVertices";
var en = "UnitTestsTraversalEdges";
var vertexCollection;
var edgeCollection;
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUpAll : function () {
db._drop(vn);
db._drop(en);
internal.debugClearFailAt();
vertexCollection = db._create(vn, {numberOfShards: 4});
edgeCollection = db._createEdgeCollection(en, {numberOfShards: 4});
[ "A", "B", "C", "D" ].forEach(function (item) {
vertexCollection.save({ _key: item, name: item });
});
[ [ "A", "B" ], [ "B", "C" ], [ "A", "D" ], [ "D", "C" ], [ "C", "A" ] ].forEach(function (item) {
var l = item[0];
var r = item[1];
edgeCollection.save(vn + "/" + l, vn + "/" + r, { _key: l + r, what : l + "->" + r });
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDownAll : function () {
db._drop(vn);
db._drop(en);
internal.debugClearFailAt();
},
////////////////////////////////////////////////////////////////////////////////
/// @brief checks error handling for neighbors
////////////////////////////////////////////////////////////////////////////////
/* CodePath does not exist any more
testNeighborsDitchesOOM : function () {
var v1 = vn + "/A";
var v2 = vn + "/B";
var v3 = vn + "/D";
var queryStart = `FOR n IN OUTBOUND "`;
var queryEnd = `" ${en} SORT n._id RETURN n._id`;
var actual = getQueryResults(queryStart + v1 + queryEnd);
// Positive Check
assertEqual(actual, [ v2, v3 ]);
internal.debugClearFailAt();
internal.debugSetFailAt("EdgeCollectionInfoOOM1");
// Negative Check
try {
actual = getQueryResults(queryStart + v1 + queryEnd);
fail();
} catch (e) {
assertEqual(e.errorNum, errors.ERROR_DEBUG.code);
}
internal.debugClearFailAt();
internal.debugSetFailAt("EdgeCollectionInfoOOM2");
// Negative Check
try {
actual = getQueryResults(queryStart + v1 + queryEnd);
fail();
} catch (e) {
assertEqual(e.errorNum, errors.ERROR_DEBUG.code);
}
internal.debugClearFailAt();
}
*/
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite for ShortestPath with intentional failures
////////////////////////////////////////////////////////////////////////////////
function ahuacatlQueryShortestpathErrorsSuite () {
var vn = "UnitTestsTraversalVertices";
var en = "UnitTestsTraversalEdges";
var vertexCollection;
var edgeCollection;
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUpAll : function () {
db._drop(vn);
db._drop(en);
internal.debugClearFailAt();
vertexCollection = db._create(vn, {numberOfShards: 4});
edgeCollection = db._createEdgeCollection(en, {numberOfShards: 4});
[ "A", "B", "C", "D", "E"].forEach(function (item) {
vertexCollection.save({ _key: item, name: item });
});
[ [ "A", "B" ], [ "B", "C" ], [ "A", "D" ], [ "D", "E" ], [ "E", "C"], [ "C", "A" ] ].forEach(function (item) {
var l = item[0];
var r = item[1];
edgeCollection.save(vn + "/" + l, vn + "/" + r, { _key: l + r, what : l + "->" + r });
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDownAll : function () {
db._drop(vn);
db._drop(en);
internal.debugClearFailAt();
},
////////////////////////////////////////////////////////////////////////////////
/// @brief checks error handling in SHORTEST_PATH
////////////////////////////////////////////////////////////////////////////////
testShortestPathOOM : function () {
var s = vn + "/A";
var m = vn + "/B";
var t = vn + "/C";
var query = `FOR v IN OUTBOUND SHORTEST_PATH "${s}" TO "${t}" ${en} RETURN v._id`;
var actual = getQueryResults(query);
// Positive Check
assertEqual(actual, [s, m, t]);
internal.debugSetFailAt("TraversalOOMInitialize");
// Negative Check
try {
actual = getQueryResults(query);
fail();
} catch (e) {
assertEqual(e.errorNum, errors.ERROR_DEBUG.code);
}
internal.debugClearFailAt();
// Redo the positive check. Make sure the former fail is gone
actual = getQueryResults(query);
assertEqual(actual, [s, m, t]);
internal.debugSetFailAt("TraversalOOMPath");
// Negative Check
try {
actual = getQueryResults(query);
fail();
} catch (e) {
assertEqual(e.errorNum, errors.ERROR_DEBUG.code);
}
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////
jsunity.run(ahuacatlQueryEdgesTestSuite);
jsunity.run(ahuacatlQueryNeighborsTestSuite);
jsunity.run(ahuacatlQueryBreadthFirstTestSuite);
jsunity.run(ahuacatlQueryShortestPathTestSuite);
if (internal.debugCanUseFailAt() && ! cluster.isCluster()) {
jsunity.run(ahuacatlQueryNeighborsErrorsSuite);
jsunity.run(ahuacatlQueryShortestpathErrorsSuite);
}
return jsunity.done();