1
0
Fork 0

Add TTL to query options to standardize usage across components. (#8203)

This commit is contained in:
Dan Larkin-York 2019-02-21 14:29:37 -05:00 committed by Jan
parent fcc1700d33
commit cd54271af0
13 changed files with 298 additions and 235 deletions

View File

@ -1,6 +1,9 @@
devel devel
----- -----
* `--query.registry-ttl` is now honored in single-server mode, and cursor TTLs
are now honored on DBServers in cluster mode
* add "TTL" index type, for optional auto-expiration of documents * add "TTL" index type, for optional auto-expiration of documents
* disable selection of index types "persistent" and "skiplist" in the web * disable selection of index types "persistent" and "skiplist" in the web
@ -24,7 +27,6 @@ devel
* fixed JS AQL query objects with empty query strings not being recognized as AQL queries * fixed JS AQL query objects with empty query strings not being recognized as AQL queries
>>>>>>> 492d05c1f1bd5cff4e067ae7d6593b9f03cebe37
* report run-time openssl version (for dynamically linked executables) * report run-time openssl version (for dynamically linked executables)

View File

@ -2163,9 +2163,9 @@
}, },
"query.registry-ttl" : { "query.registry-ttl" : {
"category" : "option", "category" : "option",
"default" : 600, "default" : 0,
"deprecatedIn" : null, "deprecatedIn" : null,
"description" : "default time-to-live of query snippets (in seconds)", "description" : "default time-to-live of cursors and query snippets (in seconds); if <= 0, value will default to 30 for single-server instances or 600 for cluster instances",
"dynamic" : false, "dynamic" : false,
"enterpriseOnly" : false, "enterpriseOnly" : false,
"hidden" : true, "hidden" : true,

View File

@ -21,7 +21,6 @@
/// @author Michael Hackstein /// @author Michael Hackstein
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include "EngineInfoContainerCoordinator.h"
#include "Aql/AqlItemBlock.h" #include "Aql/AqlItemBlock.h"
#include "Aql/AqlResult.h" #include "Aql/AqlResult.h"
#include "Aql/ClusterBlocks.h" #include "Aql/ClusterBlocks.h"
@ -31,6 +30,7 @@
#include "Aql/ExecutionNode.h" #include "Aql/ExecutionNode.h"
#include "Aql/Query.h" #include "Aql/Query.h"
#include "Aql/QueryRegistry.h" #include "Aql/QueryRegistry.h"
#include "EngineInfoContainerCoordinator.h"
#include "VocBase/ticks.h" #include "VocBase/ticks.h"
using namespace arangodb; using namespace arangodb;
@ -86,7 +86,7 @@ Result EngineInfoContainerCoordinator::EngineInfo::buildEngine(
// For _id == 0 this thread will always maintain the handle to // For _id == 0 this thread will always maintain the handle to
// the engine and will clean up. We do not keep track of it seperately // the engine and will clean up. We do not keep track of it seperately
if (_id != 0) { if (_id != 0) {
double ttl = queryRegistry->defaultTTL(); double ttl = query->queryOptions().ttl;
TRI_ASSERT(ttl > 0); TRI_ASSERT(ttl > 0);
try { try {
queryRegistry->insert(_id, query, ttl, true, false); queryRegistry->insert(_id, query, ttl, true, false);

View File

@ -21,7 +21,6 @@
/// @author Michael Hackstein /// @author Michael Hackstein
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include "EngineInfoContainerDBServer.h"
#include "Aql/AqlItemBlock.h" #include "Aql/AqlItemBlock.h"
#include "Aql/ClusterNodes.h" #include "Aql/ClusterNodes.h"
#include "Aql/Collection.h" #include "Aql/Collection.h"
@ -36,6 +35,7 @@
#include "Cluster/ClusterComm.h" #include "Cluster/ClusterComm.h"
#include "Cluster/ServerState.h" #include "Cluster/ServerState.h"
#include "Cluster/TraverserEngineRegistry.h" #include "Cluster/TraverserEngineRegistry.h"
#include "EngineInfoContainerDBServer.h"
#include "Graph/BaseOptions.h" #include "Graph/BaseOptions.h"
#include "RestServer/QueryRegistryFeature.h" #include "RestServer/QueryRegistryFeature.h"
#include "StorageEngine/TransactionState.h" #include "StorageEngine/TransactionState.h"
@ -98,7 +98,6 @@ GatherNode* findFirstGather(ExecutionNode const& root) {
return nullptr; return nullptr;
} }
ScatterNode* findFirstScatter(ExecutionNode const& root) { ScatterNode* findFirstScatter(ExecutionNode const& root) {
ExecutionNode* node = root.getFirstDependency(); ExecutionNode* node = root.getFirstDependency();
@ -153,9 +152,7 @@ EngineInfoContainerDBServer::EngineInfo::EngineInfo(EngineInfo&& other) noexcept
TRI_ASSERT(source.collection); TRI_ASSERT(source.collection);
} }
void operator()(ViewSource const& source) { void operator()(ViewSource const& source) { TRI_ASSERT(source.view); }
TRI_ASSERT(source.view);
}
} visitor; } visitor;
boost::apply_visitor(visitor, _source); boost::apply_visitor(visitor, _source);
@ -197,11 +194,8 @@ void EngineInfoContainerDBServer::EngineInfo::addNode(ExecutionNode* node) {
// can't do it on DB servers since only parts of the plan will be sent // can't do it on DB servers since only parts of the plan will be sent
viewNode.volatility(true); viewNode.volatility(true);
_source = ViewSource( _source = ViewSource(*viewNode.view().get(), findFirstGather(viewNode),
*viewNode.view().get(), findFirstScatter(viewNode));
findFirstGather(viewNode),
findFirstScatter(viewNode)
);
break; break;
} }
#endif #endif
@ -979,12 +973,7 @@ Result EngineInfoContainerDBServer::buildEngines(MapRemoteToSnippet& queryIds,
return {TRI_ERROR_SHUTTING_DOWN}; return {TRI_ERROR_SHUTTING_DOWN};
} }
double ttl = QueryRegistryFeature::DefaultQueryTTL; double ttl = _query->queryOptions().ttl;
auto* registry = QueryRegistryFeature::registry();
if (registry != nullptr) {
ttl = registry->defaultTTL();
}
TRI_ASSERT(ttl > 0);
std::string const url( std::string const url(
"/_db/" + arangodb::basics::StringUtils::urlEncode(_query->vocbase().name()) + "/_db/" + arangodb::basics::StringUtils::urlEncode(_query->vocbase().name()) +

View File

@ -21,9 +21,10 @@
/// @author Jan Steemann /// @author Jan Steemann
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include "QueryOptions.h"
#include "ApplicationFeatures/ApplicationServer.h" #include "ApplicationFeatures/ApplicationServer.h"
#include "Aql/QueryCache.h" #include "Aql/QueryCache.h"
#include "Aql/QueryRegistry.h"
#include "QueryOptions.h"
#include "RestServer/QueryRegistryFeature.h" #include "RestServer/QueryRegistryFeature.h"
#include <velocypack/Builder.h> #include <velocypack/Builder.h>
@ -39,6 +40,7 @@ QueryOptions::QueryOptions()
maxWarningCount(10), maxWarningCount(10),
literalSizeThreshold(-1), literalSizeThreshold(-1),
satelliteSyncWait(60.0), satelliteSyncWait(60.0),
ttl(0),
profile(PROFILE_LEVEL_NONE), profile(PROFILE_LEVEL_NONE),
allPlans(false), allPlans(false),
verbosePlans(false), verbosePlans(false),
@ -62,6 +64,9 @@ QueryOptions::QueryOptions()
memoryLimit = globalLimit; memoryLimit = globalLimit;
} }
// get global default ttl
ttl = q->registry()->defaultTTL();
// use global "failOnWarning" value // use global "failOnWarning" value
failOnWarning = q->failOnWarning(); failOnWarning = q->failOnWarning();
@ -111,6 +116,11 @@ void QueryOptions::fromVelocyPack(VPackSlice const& slice) {
satelliteSyncWait = value.getNumber<double>(); satelliteSyncWait = value.getNumber<double>();
} }
value = slice.get("ttl");
if (value.isNumber()) {
ttl = value.getNumber<double>();
}
// boolean options // boolean options
value = slice.get("profile"); value = slice.get("profile");
if (value.isBool()) { if (value.isBool()) {
@ -214,6 +224,7 @@ void QueryOptions::toVelocyPack(VPackBuilder& builder, bool disableOptimizerRule
builder.add("maxWarningCount", VPackValue(maxWarningCount)); builder.add("maxWarningCount", VPackValue(maxWarningCount));
builder.add("literalSizeThreshold", VPackValue(literalSizeThreshold)); builder.add("literalSizeThreshold", VPackValue(literalSizeThreshold));
builder.add("satelliteSyncWait", VPackValue(satelliteSyncWait)); builder.add("satelliteSyncWait", VPackValue(satelliteSyncWait));
builder.add("ttl", VPackValue(ttl));
builder.add("profile", VPackValue(static_cast<uint32_t>(profile))); builder.add("profile", VPackValue(static_cast<uint32_t>(profile)));
builder.add("allPlans", VPackValue(allPlans)); builder.add("allPlans", VPackValue(allPlans));
builder.add("verbosePlans", VPackValue(verbosePlans)); builder.add("verbosePlans", VPackValue(verbosePlans));

View File

@ -54,13 +54,14 @@ struct QueryOptions {
void fromVelocyPack(arangodb::velocypack::Slice const&); void fromVelocyPack(arangodb::velocypack::Slice const&);
void toVelocyPack(arangodb::velocypack::Builder&, bool disableOptimizerRules) const; void toVelocyPack(arangodb::velocypack::Builder&, bool disableOptimizerRules) const;
TEST_VIRTUAL ProfileLevel getProfileLevel () {return profile; }; TEST_VIRTUAL ProfileLevel getProfileLevel() { return profile; };
size_t memoryLimit; size_t memoryLimit;
size_t maxNumberOfPlans; size_t maxNumberOfPlans;
size_t maxWarningCount; size_t maxWarningCount;
int64_t literalSizeThreshold; int64_t literalSizeThreshold;
double satelliteSyncWait; double satelliteSyncWait;
double ttl;
/// Level 0 nothing, Level 1 profile, Level 2,3 log tracing info /// Level 0 nothing, Level 1 profile, Level 2,3 log tracing info
ProfileLevel profile; ProfileLevel profile;
bool allPlans; bool allPlans;

View File

@ -93,6 +93,29 @@ RestAqlHandler::RestAqlHandler(GeneralRequest* request, GeneralResponse* respons
// variables: [ <variables> ] // variables: [ <variables> ]
// } // }
std::pair<double, std::shared_ptr<VPackBuilder>> RestAqlHandler::getPatchedOptionsWithTTL(
VPackSlice const& optionsSlice) const {
auto options = std::make_shared<VPackBuilder>();
double ttl = _queryRegistry->defaultTTL();
{
VPackObjectBuilder guard(options.get());
TRI_ASSERT(optionsSlice.isObject());
for (auto const& pair : VPackObjectIterator(optionsSlice)) {
if (pair.key.isEqualString("ttl")) {
ttl = VelocyPackHelper::getNumericValue<double>(optionsSlice, "ttl", ttl);
ttl = _request->parsedValue<double>("ttl", ttl);
if (ttl <= 0) {
ttl = _queryRegistry->defaultTTL();
}
options->add("ttl", VPackValue(ttl));
} else {
options->add(pair.key.stringRef(), pair.value);
}
}
}
return std::make_pair(ttl, options);
}
void RestAqlHandler::setupClusterQuery() { void RestAqlHandler::setupClusterQuery() {
// We should not intentionally call this method // We should not intentionally call this method
// on the wrong server. So fail during maintanence. // on the wrong server. So fail during maintanence.
@ -175,7 +198,9 @@ void RestAqlHandler::setupClusterQuery() {
// variables: <variables slice> // variables: <variables slice>
// } // }
auto options = std::make_shared<VPackBuilder>(VPackBuilder::clone(optionsSlice)); std::shared_ptr<VPackBuilder> options;
double ttl;
std::tie(ttl, options) = getPatchedOptionsWithTTL(optionsSlice);
// Build the collection information // Build the collection information
VPackBuilder collectionBuilder; VPackBuilder collectionBuilder;
@ -210,12 +235,6 @@ void RestAqlHandler::setupClusterQuery() {
} }
collectionBuilder.close(); collectionBuilder.close();
// Now the query is ready to go, store it in the registry and return:
double ttl = _request->parsedValue<double>("ttl", _queryRegistry->defaultTTL());
if (ttl <= 0) {
ttl = _queryRegistry->defaultTTL();
}
// creates a StandaloneContext or a leasing context // creates a StandaloneContext or a leasing context
auto ctx = transaction::SmartContext::Create(_vocbase); auto ctx = transaction::SmartContext::Create(_vocbase);
@ -396,8 +415,9 @@ void RestAqlHandler::createQueryFromVelocyPack() {
return; return;
} }
auto options = std::make_shared<VPackBuilder>( std::shared_ptr<VPackBuilder> options;
VPackBuilder::clone(querySlice.get("options"))); double ttl;
std::tie(ttl, options) = getPatchedOptionsWithTTL(querySlice.get("options"));
std::string const part = std::string const part =
VelocyPackHelper::getStringValue(querySlice, "part", ""); VelocyPackHelper::getStringValue(querySlice, "part", "");
@ -420,9 +440,6 @@ void RestAqlHandler::createQueryFromVelocyPack() {
return; return;
} }
// Now the query is ready to go, store it in the registry and return:
double ttl = _request->parsedValue<double>("ttl", _queryRegistry->defaultTTL());
_qId = TRI_NewTickServer(); _qId = TRI_NewTickServer();
try { try {
_queryRegistry->insert(_qId, query.get(), ttl, true, false); _queryRegistry->insert(_qId, query.get(), ttl, true, false);

View File

@ -135,6 +135,9 @@ class RestAqlHandler : public RestVocbaseBaseHandler {
// dig out vocbase from context and query from ID, handle errors // dig out vocbase from context and query from ID, handle errors
bool findQuery(std::string const& idString, Query*& query); bool findQuery(std::string const& idString, Query*& query);
// generate patched options with TTL extracted from request
std::pair<double, std::shared_ptr<VPackBuilder>> getPatchedOptionsWithTTL(VPackSlice const& optionsSlice) const;
// our query registry // our query registry
QueryRegistry* _queryRegistry; QueryRegistry* _queryRegistry;

View File

@ -21,7 +21,6 @@
/// @author Jan Steemann /// @author Jan Steemann
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include "RestCursorHandler.h"
#include "Aql/Query.h" #include "Aql/Query.h"
#include "Aql/QueryRegistry.h" #include "Aql/QueryRegistry.h"
#include "Basics/Exceptions.h" #include "Basics/Exceptions.h"
@ -29,6 +28,7 @@
#include "Basics/StaticStrings.h" #include "Basics/StaticStrings.h"
#include "Basics/VelocyPackHelper.h" #include "Basics/VelocyPackHelper.h"
#include "Cluster/ServerState.h" #include "Cluster/ServerState.h"
#include "RestCursorHandler.h"
#include "Transaction/Context.h" #include "Transaction/Context.h"
#include "Utils/Cursor.h" #include "Utils/Cursor.h"
#include "Utils/CursorRepository.h" #include "Utils/CursorRepository.h"
@ -151,7 +151,8 @@ RestStatus RestCursorHandler::registerQueryOrCursor(VPackSlice const& slice) {
bool stream = VelocyPackHelper::getBooleanValue(opts, "stream", false); bool stream = VelocyPackHelper::getBooleanValue(opts, "stream", false);
size_t batchSize = VelocyPackHelper::getNumericValue<size_t>(opts, "batchSize", 1000); size_t batchSize = VelocyPackHelper::getNumericValue<size_t>(opts, "batchSize", 1000);
double ttl = VelocyPackHelper::getNumericValue<double>(opts, "ttl", 30); double ttl = VelocyPackHelper::getNumericValue<double>(opts, "ttl",
_queryRegistry->defaultTTL());
bool count = VelocyPackHelper::getBooleanValue(opts, "count", false); bool count = VelocyPackHelper::getBooleanValue(opts, "count", false);
if (stream) { if (stream) {
@ -444,7 +445,9 @@ void RestCursorHandler::buildOptions(VPackSlice const& slice) {
} }
VPackSlice ttl = slice.get("ttl"); VPackSlice ttl = slice.get("ttl");
_options->add("ttl", VPackValue(ttl.isNumber() ? ttl.getNumber<double>() : 30)); _options->add("ttl", VPackValue(ttl.isNumber() && ttl.getNumber<double>() > 0
? ttl.getNumber<double>()
: _queryRegistry->defaultTTL()));
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////

View File

@ -51,7 +51,7 @@ QueryRegistryFeature::QueryRegistryFeature(application_features::ApplicationServ
_queryCacheMaxResultsSize(0), _queryCacheMaxResultsSize(0),
_queryCacheMaxEntrySize(0), _queryCacheMaxEntrySize(0),
_queryCacheIncludeSystem(false), _queryCacheIncludeSystem(false),
_queryRegistryTTL(DefaultQueryTTL) { _queryRegistryTTL(0) {
setOptional(false); setOptional(false);
startsAfter("V8Phase"); startsAfter("V8Phase");
@ -123,7 +123,9 @@ void QueryRegistryFeature::collectOptions(std::shared_ptr<ProgramOptions> option
new UInt64Parameter(&_maxQueryPlans)); new UInt64Parameter(&_maxQueryPlans));
options->addOption("--query.registry-ttl", options->addOption("--query.registry-ttl",
"default time-to-live of query snippets (in seconds)", "default time-to-live of cursors and query snippets (in "
"seconds); if <= 0, value will default to 30 for "
"single-server instances or 600 for cluster instances",
new DoubleParameter(&_queryRegistryTTL), new DoubleParameter(&_queryRegistryTTL),
arangodb::options::makeFlags(arangodb::options::Flags::Hidden)); arangodb::options::makeFlags(arangodb::options::Flags::Hidden));
} }
@ -157,7 +159,8 @@ void QueryRegistryFeature::prepare() {
arangodb::aql::QueryCache::instance()->properties(properties); arangodb::aql::QueryCache::instance()->properties(properties);
if (_queryRegistryTTL <= 0) { if (_queryRegistryTTL <= 0) {
_queryRegistryTTL = DefaultQueryTTL; // set to default value based on instance type
_queryRegistryTTL = ServerState::instance()->isSingleServer() ? 30 : 600;
} }
// create the query registery // create the query registery

View File

@ -38,8 +38,6 @@ class QueryRegistryFeature final : public application_features::ApplicationFeatu
return QUERY_REGISTRY.load(std::memory_order_acquire); return QUERY_REGISTRY.load(std::memory_order_acquire);
} }
static constexpr double DefaultQueryTTL = 600.0;
explicit QueryRegistryFeature(application_features::ApplicationServer& server); explicit QueryRegistryFeature(application_features::ApplicationServer& server);
void collectOptions(std::shared_ptr<options::ProgramOptions>) override final; void collectOptions(std::shared_ptr<options::ProgramOptions>) override final;

View File

@ -45,7 +45,6 @@ namespace tests {
namespace engine_info_container_coordinator_test { namespace engine_info_container_coordinator_test {
TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") { TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
SECTION("it should always start with an open snippet, with queryID 0") { SECTION("it should always start with an open snippet, with queryID 0") {
EngineInfoContainerCoordinator testee; EngineInfoContainerCoordinator testee;
QueryId res = testee.closeSnippet(); QueryId res = testee.closeSnippet();
@ -88,7 +87,6 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
// 3. query->engine(); // 3. query->engine();
SECTION("it should create an ExecutionEngine for the first snippet") { SECTION("it should create an ExecutionEngine for the first snippet") {
std::unordered_set<std::string> const restrictToShards; std::unordered_set<std::string> const restrictToShards;
MapRemoteToSnippet queryIds; MapRemoteToSnippet queryIds;
std::unordered_set<ShardID> lockedShards; std::unordered_set<ShardID> lockedShards;
@ -121,7 +119,6 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
// Section: Mock Functions // Section: Mock Functions
// ------------------------------ // ------------------------------
fakeit::When(Method(mockQuery, setEngine)).Do([&](ExecutionEngine* eng) -> void { fakeit::When(Method(mockQuery, setEngine)).Do([&](ExecutionEngine* eng) -> void {
// We expect that the snippet injects a new engine into our // We expect that the snippet injects a new engine into our
// query. // query.
@ -133,12 +130,12 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
fakeit::When(Method(mockQuery, trx)).Return(&trx); fakeit::When(Method(mockQuery, trx)).Return(&trx);
fakeit::When(Method(mockQuery, engine)).Return(&myEngine).Return(&myEngine); fakeit::When(Method(mockQuery, engine)).Return(&myEngine).Return(&myEngine);
fakeit::When(Method(mockTrx, setLockedShards)).AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) { fakeit::When(Method(mockTrx, setLockedShards))
return; .AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) {
}); return;
});
fakeit::When(Method(mockEngine, createBlocks)).Return(Result{TRI_ERROR_NO_ERROR}); fakeit::When(Method(mockEngine, createBlocks)).Return(Result{TRI_ERROR_NO_ERROR});
fakeit::When(ConstOverloadedMethod(mockEngine, root, ExecutionBlock* ())) fakeit::When(ConstOverloadedMethod(mockEngine, root, ExecutionBlock * ())).AlwaysReturn(&rootBlock);
.AlwaysReturn(&rootBlock);
// ------------------------------ // ------------------------------
// Section: Run the test // Section: Run the test
@ -147,9 +144,8 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
EngineInfoContainerCoordinator testee; EngineInfoContainerCoordinator testee;
testee.addNode(&sNode); testee.addNode(&sNode);
ExecutionEngineResult result = testee.buildEngines( ExecutionEngineResult result =
&query, &registry, dbname, restrictToShards, queryIds, lockedShards testee.buildEngines(&query, &registry, dbname, restrictToShards, queryIds, lockedShards);
);
REQUIRE(result.ok()); REQUIRE(result.ok());
ExecutionEngine* engine = result.engine(); ExecutionEngine* engine = result.engine();
@ -199,30 +195,39 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
fakeit::Mock<ExecutionEngine> mockSecondEngine; fakeit::Mock<ExecutionEngine> mockSecondEngine;
ExecutionEngine& mySecondEngine = mockSecondEngine.get(); ExecutionEngine& mySecondEngine = mockSecondEngine.get();
fakeit::Mock<Query> mockQuery;
Query& query = mockQuery.get();
fakeit::Mock<Query> mockQueryClone;
Query& queryClone = mockQueryClone.get();
fakeit::Mock<QueryRegistry> mockRegistry; fakeit::Mock<QueryRegistry> mockRegistry;
fakeit::When(Method(mockRegistry, defaultTTL)).AlwaysReturn(600.0); fakeit::When(Method(mockRegistry, defaultTTL)).AlwaysReturn(600.0);
QueryRegistry& registry = mockRegistry.get(); QueryRegistry& registry = mockRegistry.get();
fakeit::Mock<QueryOptions> mockQueryOptions;
QueryOptions& lqueryOptions = mockQueryOptions.get();
lqueryOptions.ttl = 600;
fakeit::Mock<Query> mockQuery;
Query& query = mockQuery.get();
fakeit::When(ConstOverloadedMethod(mockQuery, queryOptions, QueryOptions const&()))
.AlwaysDo([&]() -> QueryOptions const& { return lqueryOptions; });
fakeit::When(OverloadedMethod(mockQuery, queryOptions, QueryOptions & ()))
.AlwaysDo([&]() -> QueryOptions& { return lqueryOptions; });
fakeit::Mock<Query> mockQueryClone;
Query& queryClone = mockQueryClone.get();
fakeit::When(ConstOverloadedMethod(mockQueryClone, queryOptions, QueryOptions const&()))
.AlwaysDo([&]() -> QueryOptions const& { return lqueryOptions; });
fakeit::When(OverloadedMethod(mockQueryClone, queryOptions, QueryOptions & ()))
.AlwaysDo([&]() -> QueryOptions& { return lqueryOptions; });
fakeit::Mock<transaction::Methods> mockTrx; fakeit::Mock<transaction::Methods> mockTrx;
transaction::Methods& trx = mockTrx.get(); transaction::Methods& trx = mockTrx.get();
fakeit::Mock<transaction::Methods> mockSecondTrx; fakeit::Mock<transaction::Methods> mockSecondTrx;
transaction::Methods& secondTrx = mockSecondTrx.get(); transaction::Methods& secondTrx = mockSecondTrx.get();
// ------------------------------ // ------------------------------
// Section: Mock Functions // Section: Mock Functions
// ------------------------------ // ------------------------------
fakeit::When(Method(mockQuery, setEngine)).Do([&](ExecutionEngine* eng) -> void { fakeit::When(Method(mockQuery, setEngine)).Do([&](ExecutionEngine* eng) -> void {
// We expect that the snippet injects a new engine into our // We expect that the snippet injects a new engine into our
// query. // query.
// However we have to return a mocked engine later // However we have to return a mocked engine later
@ -233,19 +238,18 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
fakeit::When(Method(mockQuery, trx)).Return(&trx); fakeit::When(Method(mockQuery, trx)).Return(&trx);
fakeit::When(Method(mockQuery, engine)).Return(&myEngine).Return(&myEngine); fakeit::When(Method(mockQuery, engine)).Return(&myEngine).Return(&myEngine);
fakeit::When(Method(mockTrx, setLockedShards)).AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) { fakeit::When(Method(mockTrx, setLockedShards))
return; .AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) {
}); return;
fakeit::When(Method(mockEngine, createBlocks)).Do([&]( });
std::vector<ExecutionNode*> const& nodes, fakeit::When(Method(mockEngine, createBlocks))
std::unordered_set<std::string> const&, .Do([&](std::vector<ExecutionNode*> const& nodes,
MapRemoteToSnippet const&) { std::unordered_set<std::string> const&, MapRemoteToSnippet const&) {
REQUIRE(nodes.size() == 1); REQUIRE(nodes.size() == 1);
REQUIRE(nodes[0] == &fNode); REQUIRE(nodes[0] == &fNode);
return Result{TRI_ERROR_NO_ERROR}; return Result{TRI_ERROR_NO_ERROR};
}); });
fakeit::When(ConstOverloadedMethod(mockEngine, root, ExecutionBlock* ())) fakeit::When(ConstOverloadedMethod(mockEngine, root, ExecutionBlock * ())).AlwaysReturn(&block);
.AlwaysReturn(&block);
// Mock query clone // Mock query clone
fakeit::When(Method(mockQuery, clone)).Do([&](QueryPart part, bool withPlan) -> Query* { fakeit::When(Method(mockQuery, clone)).Do([&](QueryPart part, bool withPlan) -> Query* {
@ -265,32 +269,32 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
fakeit::When(Method(mockQueryClone, trx)).Return(&secondTrx); fakeit::When(Method(mockQueryClone, trx)).Return(&secondTrx);
fakeit::When(Method(mockQueryClone, engine)).Return(&mySecondEngine); fakeit::When(Method(mockQueryClone, engine)).Return(&mySecondEngine);
fakeit::When(Method(mockSecondTrx, setLockedShards)).AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) { fakeit::When(Method(mockSecondTrx, setLockedShards))
return; .AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) {
}); return;
});
fakeit::When(Method(mockSecondEngine, createBlocks)).Do([&]( fakeit::When(Method(mockSecondEngine, createBlocks))
std::vector<ExecutionNode*> const& nodes, .Do([&](std::vector<ExecutionNode*> const& nodes,
std::unordered_set<std::string> const&, std::unordered_set<std::string> const&, MapRemoteToSnippet const&) {
MapRemoteToSnippet const&) { REQUIRE(nodes.size() == 1);
REQUIRE(nodes.size() == 1); REQUIRE(nodes[0] == &sNode);
REQUIRE(nodes[0] == &sNode); return Result{TRI_ERROR_NO_ERROR};
return Result{TRI_ERROR_NO_ERROR}; });
}); fakeit::When(ConstOverloadedMethod(mockSecondEngine, root, ExecutionBlock * ()))
fakeit::When(ConstOverloadedMethod(mockSecondEngine, root, ExecutionBlock* ()))
.AlwaysReturn(&block); .AlwaysReturn(&block);
// Mock the Registry // Mock the Registry
fakeit::When(Method(mockRegistry, insert)).Do([&] (QueryId id, Query* query, double timeout, bool isPrepared, bool keepLease) { fakeit::When(Method(mockRegistry, insert))
REQUIRE(id != 0); .Do([&](QueryId id, Query* query, double timeout, bool isPrepared, bool keepLease) {
REQUIRE(query != nullptr); REQUIRE(id != 0);
REQUIRE(isPrepared == true); REQUIRE(query != nullptr);
REQUIRE(keepLease == false); REQUIRE(isPrepared == true);
REQUIRE(timeout == 600.0); REQUIRE(keepLease == false);
REQUIRE(query == &queryClone); REQUIRE(timeout == 600.0);
secondId = id; REQUIRE(query == &queryClone);
}); secondId = id;
});
// ------------------------------ // ------------------------------
// Section: Run the test // Section: Run the test
@ -306,9 +310,8 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
// Close the second snippet // Close the second snippet
testee.closeSnippet(); testee.closeSnippet();
ExecutionEngineResult result = testee.buildEngines( ExecutionEngineResult result =
&query, &registry, dbname, restrictToShards, queryIds, lockedShards testee.buildEngines(&query, &registry, dbname, restrictToShards, queryIds, lockedShards);
);
REQUIRE(result.ok()); REQUIRE(result.ok());
ExecutionEngine* engine = result.engine(); ExecutionEngine* engine = result.engine();
@ -345,7 +348,7 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
QueryId thirdId = 0; QueryId thirdId = 0;
std::string dbname = "TestDB"; std::string dbname = "TestDB";
auto setEngineCallback = [] (ExecutionEngine* eng) -> void { auto setEngineCallback = [](ExecutionEngine* eng) -> void {
// We expect that the snippet injects a new engine into our // We expect that the snippet injects a new engine into our
// query. // query.
// However we have to return a mocked engine later // However we have to return a mocked engine later
@ -406,15 +409,32 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
fakeit::Mock<ExecutionEngine> mockThirdEngine; fakeit::Mock<ExecutionEngine> mockThirdEngine;
ExecutionEngine& myThirdEngine = mockThirdEngine.get(); ExecutionEngine& myThirdEngine = mockThirdEngine.get();
fakeit::Mock<QueryOptions> mockQueryOptions;
QueryOptions& lqueryOptions = mockQueryOptions.get();
lqueryOptions.ttl = 600;
fakeit::Mock<Query> mockQuery; fakeit::Mock<Query> mockQuery;
Query& query = mockQuery.get(); Query& query = mockQuery.get();
fakeit::When(ConstOverloadedMethod(mockQuery, queryOptions, QueryOptions const&()))
.AlwaysDo([&]() -> QueryOptions const& { return lqueryOptions; });
fakeit::When(OverloadedMethod(mockQuery, queryOptions, QueryOptions & ()))
.AlwaysDo([&]() -> QueryOptions& { return lqueryOptions; });
// We need two query clones // We need two query clones
fakeit::Mock<Query> mockQueryClone; fakeit::Mock<Query> mockQueryClone;
Query& queryClone = mockQueryClone.get(); Query& queryClone = mockQueryClone.get();
fakeit::When(ConstOverloadedMethod(mockQueryClone, queryOptions, QueryOptions const&()))
.AlwaysDo([&]() -> QueryOptions const& { return lqueryOptions; });
fakeit::When(OverloadedMethod(mockQueryClone, queryOptions, QueryOptions & ()))
.AlwaysDo([&]() -> QueryOptions& { return lqueryOptions; });
fakeit::Mock<Query> mockQuerySecondClone; fakeit::Mock<Query> mockQuerySecondClone;
Query& querySecondClone = mockQuerySecondClone.get(); Query& querySecondClone = mockQuerySecondClone.get();
fakeit::When(ConstOverloadedMethod(mockQuerySecondClone, queryOptions,
QueryOptions const&()))
.AlwaysDo([&]() -> QueryOptions const& { return lqueryOptions; });
fakeit::When(OverloadedMethod(mockQuerySecondClone, queryOptions, QueryOptions & ()))
.AlwaysDo([&]() -> QueryOptions& { return lqueryOptions; });
fakeit::Mock<QueryRegistry> mockRegistry; fakeit::Mock<QueryRegistry> mockRegistry;
fakeit::When(Method(mockRegistry, defaultTTL)).AlwaysReturn(600.0); fakeit::When(Method(mockRegistry, defaultTTL)).AlwaysReturn(600.0);
@ -436,91 +456,91 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
fakeit::When(Method(mockQuery, setEngine)).Do(setEngineCallback); fakeit::When(Method(mockQuery, setEngine)).Do(setEngineCallback);
fakeit::When(Method(mockQuery, trx)).Return(&trx); fakeit::When(Method(mockQuery, trx)).Return(&trx);
fakeit::When(Method(mockQuery, engine)).Return(&myEngine).Return(&myEngine); fakeit::When(Method(mockQuery, engine)).Return(&myEngine).Return(&myEngine);
fakeit::When(Method(mockTrx, setLockedShards)).AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) { fakeit::When(Method(mockTrx, setLockedShards))
return; .AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) {
}); return;
fakeit::When(Method(mockEngine, createBlocks)).Do([&]( });
std::vector<ExecutionNode*> const& nodes, fakeit::When(Method(mockEngine, createBlocks))
std::unordered_set<std::string> const&, .Do([&](std::vector<ExecutionNode*> const& nodes,
MapRemoteToSnippet const&) { std::unordered_set<std::string> const&, MapRemoteToSnippet const&) {
REQUIRE(nodes.size() == 3); REQUIRE(nodes.size() == 3);
REQUIRE(nodes[0] == &fbNode); REQUIRE(nodes[0] == &fbNode);
REQUIRE(nodes[1] == &sbNode); REQUIRE(nodes[1] == &sbNode);
REQUIRE(nodes[2] == &tbNode); REQUIRE(nodes[2] == &tbNode);
return Result{TRI_ERROR_NO_ERROR}; return Result{TRI_ERROR_NO_ERROR};
}); });
fakeit::When(ConstOverloadedMethod(mockEngine, root, ExecutionBlock* ())) fakeit::When(ConstOverloadedMethod(mockEngine, root, ExecutionBlock * ())).AlwaysReturn(&block);
.AlwaysReturn(&block);
fakeit::When(Method(mockQuery, clone)).Do([&](QueryPart part, bool withPlan) -> Query* {
REQUIRE(part == PART_DEPENDENT);
REQUIRE(withPlan == false);
return &queryClone;
}).Do([&](QueryPart part, bool withPlan) -> Query* {
REQUIRE(part == PART_DEPENDENT);
REQUIRE(withPlan == false);
return &querySecondClone;
});
fakeit::When(Method(mockQuery, clone))
.Do([&](QueryPart part, bool withPlan) -> Query* {
REQUIRE(part == PART_DEPENDENT);
REQUIRE(withPlan == false);
return &queryClone;
})
.Do([&](QueryPart part, bool withPlan) -> Query* {
REQUIRE(part == PART_DEPENDENT);
REQUIRE(withPlan == false);
return &querySecondClone;
});
// Mock first clone // Mock first clone
fakeit::When(Method(mockQueryClone, setEngine)).Do(setEngineCallback); fakeit::When(Method(mockQueryClone, setEngine)).Do(setEngineCallback);
fakeit::When(Method(mockQueryClone, engine)).Return(&mySecondEngine); fakeit::When(Method(mockQueryClone, engine)).Return(&mySecondEngine);
fakeit::When(Method(mockQueryClone, trx)).Return(&secondTrx); fakeit::When(Method(mockQueryClone, trx)).Return(&secondTrx);
fakeit::When(Method(mockSecondTrx, setLockedShards)).AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) { fakeit::When(Method(mockSecondTrx, setLockedShards))
return; .AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) {
}); return;
fakeit::When(Method(mockSecondEngine, createBlocks)).Do([&]( });
std::vector<ExecutionNode*> const& nodes, fakeit::When(Method(mockSecondEngine, createBlocks))
std::unordered_set<std::string> const&, .Do([&](std::vector<ExecutionNode*> const& nodes,
MapRemoteToSnippet const&) { std::unordered_set<std::string> const&, MapRemoteToSnippet const&) {
REQUIRE(nodes.size() == 1); REQUIRE(nodes.size() == 1);
REQUIRE(nodes[0] == &aNode); REQUIRE(nodes[0] == &aNode);
return Result{TRI_ERROR_NO_ERROR}; return Result{TRI_ERROR_NO_ERROR};
}); });
fakeit::When(ConstOverloadedMethod(mockSecondEngine, root, ExecutionBlock* ())) fakeit::When(ConstOverloadedMethod(mockSecondEngine, root, ExecutionBlock * ()))
.AlwaysReturn(&block); .AlwaysReturn(&block);
// Mock second clone // Mock second clone
fakeit::When(Method(mockQuerySecondClone, setEngine)).Do(setEngineCallback); fakeit::When(Method(mockQuerySecondClone, setEngine)).Do(setEngineCallback);
fakeit::When(Method(mockQuerySecondClone, engine)).Return(&myThirdEngine); fakeit::When(Method(mockQuerySecondClone, engine)).Return(&myThirdEngine);
fakeit::When(Method(mockQuerySecondClone, trx)).Return(&thirdTrx); fakeit::When(Method(mockQuerySecondClone, trx)).Return(&thirdTrx);
fakeit::When(Method(mockThirdTrx, setLockedShards)).AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) { fakeit::When(Method(mockThirdTrx, setLockedShards))
return; .AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) {
}); return;
fakeit::When(Method(mockThirdEngine, createBlocks)).Do([&]( });
std::vector<ExecutionNode*> const& nodes, fakeit::When(Method(mockThirdEngine, createBlocks))
std::unordered_set<std::string> const&, .Do([&](std::vector<ExecutionNode*> const& nodes,
MapRemoteToSnippet const&) { std::unordered_set<std::string> const&, MapRemoteToSnippet const&) {
REQUIRE(nodes.size() == 1); REQUIRE(nodes.size() == 1);
REQUIRE(nodes[0] == &bNode); REQUIRE(nodes[0] == &bNode);
return Result{TRI_ERROR_NO_ERROR}; return Result{TRI_ERROR_NO_ERROR};
}); });
fakeit::When(ConstOverloadedMethod(mockThirdEngine, root, ExecutionBlock* ())) fakeit::When(ConstOverloadedMethod(mockThirdEngine, root, ExecutionBlock * ()))
.AlwaysReturn(&block); .AlwaysReturn(&block);
// Mock the Registry // Mock the Registry
// NOTE: This expects an ordering of the engines first of the stack will be handled // NOTE: This expects an ordering of the engines first of the stack will be
// first. With same fakeit magic we could make this ordering independent which is // handled first. With same fakeit magic we could make this ordering
// is fine as well for the production code. // independent which is is fine as well for the production code.
fakeit::When(Method(mockRegistry, insert)).Do([&] (QueryId id, Query* query, double timeout, bool isPrepared, bool keepLease) { fakeit::When(Method(mockRegistry, insert))
REQUIRE(id != 0); .Do([&](QueryId id, Query* query, double timeout, bool isPrepared, bool keepLease) {
REQUIRE(query != nullptr); REQUIRE(id != 0);
REQUIRE(isPrepared == true); REQUIRE(query != nullptr);
REQUIRE(keepLease == false); REQUIRE(isPrepared == true);
REQUIRE(timeout == 600.0); REQUIRE(keepLease == false);
REQUIRE(query == &queryClone); REQUIRE(timeout == 600.0);
secondId = id; REQUIRE(query == &queryClone);
}).Do([&] (QueryId id, Query* query, double timeout, bool isPrepared, bool keepLease) { secondId = id;
})
REQUIRE(id != 0); .Do([&](QueryId id, Query* query, double timeout, bool isPrepared, bool keepLease) {
REQUIRE(query != nullptr); REQUIRE(id != 0);
REQUIRE(timeout == 600.0); REQUIRE(query != nullptr);
REQUIRE(keepLease == false); REQUIRE(timeout == 600.0);
REQUIRE(query == &querySecondClone); REQUIRE(keepLease == false);
thirdId = id; REQUIRE(query == &querySecondClone);
}); thirdId = id;
});
// ------------------------------ // ------------------------------
// Section: Run the test // Section: Run the test
@ -541,9 +561,8 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
testee.addNode(&tbNode); testee.addNode(&tbNode);
ExecutionEngineResult result = testee.buildEngines( ExecutionEngineResult result =
&query, &registry, dbname, restrictToShards, queryIds, lockedShards testee.buildEngines(&query, &registry, dbname, restrictToShards, queryIds, lockedShards);
);
REQUIRE(result.ok()); REQUIRE(result.ok());
ExecutionEngine* engine = result.engine(); ExecutionEngine* engine = result.engine();
@ -602,11 +621,23 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
fakeit::Mock<ExecutionEngine> mockSecondEngine; fakeit::Mock<ExecutionEngine> mockSecondEngine;
ExecutionEngine& mySecondEngine = mockSecondEngine.get(); ExecutionEngine& mySecondEngine = mockSecondEngine.get();
fakeit::Mock<QueryOptions> mockQueryOptions;
QueryOptions& lqueryOptions = mockQueryOptions.get();
lqueryOptions.ttl = 600;
fakeit::Mock<Query> mockQuery; fakeit::Mock<Query> mockQuery;
Query& query = mockQuery.get(); Query& query = mockQuery.get();
fakeit::When(ConstOverloadedMethod(mockQuery, queryOptions, QueryOptions const&()))
.AlwaysDo([&]() -> QueryOptions const& { return lqueryOptions; });
fakeit::When(OverloadedMethod(mockQuery, queryOptions, QueryOptions & ()))
.AlwaysDo([&]() -> QueryOptions& { return lqueryOptions; });
fakeit::Mock<Query> mockQueryClone; fakeit::Mock<Query> mockQueryClone;
Query& queryClone = mockQueryClone.get(); Query& queryClone = mockQueryClone.get();
fakeit::When(ConstOverloadedMethod(mockQueryClone, queryOptions, QueryOptions const&()))
.AlwaysDo([&]() -> QueryOptions const& { return lqueryOptions; });
fakeit::When(OverloadedMethod(mockQueryClone, queryOptions, QueryOptions & ()))
.AlwaysDo([&]() -> QueryOptions& { return lqueryOptions; });
fakeit::Mock<QueryRegistry> mockRegistry; fakeit::Mock<QueryRegistry> mockRegistry;
fakeit::When(Method(mockRegistry, defaultTTL)).AlwaysReturn(600.0); fakeit::When(Method(mockRegistry, defaultTTL)).AlwaysReturn(600.0);
@ -622,9 +653,7 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
// Section: Mock Functions // Section: Mock Functions
// ------------------------------ // ------------------------------
fakeit::When(Method(mockQuery, setEngine)).Do([&](ExecutionEngine* eng) -> void { fakeit::When(Method(mockQuery, setEngine)).Do([&](ExecutionEngine* eng) -> void {
// We expect that the snippet injects a new engine into our // We expect that the snippet injects a new engine into our
// query. // query.
// However we have to return a mocked engine later // However we have to return a mocked engine later
@ -634,12 +663,12 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
}); });
fakeit::When(Method(mockQuery, engine)).Return(&myEngine).Return(&myEngine); fakeit::When(Method(mockQuery, engine)).Return(&myEngine).Return(&myEngine);
fakeit::When(Method(mockQuery, trx)).Return(&trx); fakeit::When(Method(mockQuery, trx)).Return(&trx);
fakeit::When(Method(mockTrx, setLockedShards)).AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) { fakeit::When(Method(mockTrx, setLockedShards))
return; .AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) {
}); return;
});
fakeit::When(Method(mockEngine, createBlocks)).AlwaysReturn(Result{TRI_ERROR_NO_ERROR}); fakeit::When(Method(mockEngine, createBlocks)).AlwaysReturn(Result{TRI_ERROR_NO_ERROR});
fakeit::When(ConstOverloadedMethod(mockEngine, root, ExecutionBlock* ())) fakeit::When(ConstOverloadedMethod(mockEngine, root, ExecutionBlock * ())).AlwaysReturn(&block);
.AlwaysReturn(&block);
fakeit::When(Method(mockQueryClone, setEngine)).Do([&](ExecutionEngine* eng) -> void { fakeit::When(Method(mockQueryClone, setEngine)).Do([&](ExecutionEngine* eng) -> void {
// We expect that the snippet injects a new engine into our // We expect that the snippet injects a new engine into our
@ -652,19 +681,21 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
fakeit::When(Method(mockQueryClone, engine)).Return(&mySecondEngine); fakeit::When(Method(mockQueryClone, engine)).Return(&mySecondEngine);
fakeit::When(Method(mockQueryClone, trx)).Return(&secondTrx); fakeit::When(Method(mockQueryClone, trx)).Return(&secondTrx);
fakeit::When(Method(mockSecondTrx, setLockedShards)).AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) { fakeit::When(Method(mockSecondTrx, setLockedShards))
return; .AlwaysDo([&](std::unordered_set<std::string> const& lockedShards) {
}); return;
});
fakeit::When(Method(mockSecondEngine, createBlocks)).AlwaysReturn(Result{TRI_ERROR_NO_ERROR}); fakeit::When(Method(mockSecondEngine, createBlocks)).AlwaysReturn(Result{TRI_ERROR_NO_ERROR});
fakeit::When(ConstOverloadedMethod(mockSecondEngine, root, ExecutionBlock* ())) fakeit::When(ConstOverloadedMethod(mockSecondEngine, root, ExecutionBlock * ()))
.AlwaysReturn(&block); .AlwaysReturn(&block);
fakeit::When(OverloadedMethod(mockRegistry, destroy, void(std::string const&, QueryId, int))).Do([&] fakeit::When(OverloadedMethod(mockRegistry, destroy,
(std::string const& vocbase, QueryId id, int errorCode) { void(std::string const&, QueryId, int)))
REQUIRE(vocbase == dbname); .Do([&](std::string const& vocbase, QueryId id, int errorCode) {
REQUIRE(id == secondId); REQUIRE(vocbase == dbname);
REQUIRE(errorCode == TRI_ERROR_INTERNAL); REQUIRE(id == secondId);
}); REQUIRE(errorCode == TRI_ERROR_INTERNAL);
});
// ------------------------------ // ------------------------------
// Section: Run the test // Section: Run the test
@ -690,27 +721,30 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
SECTION("cloning of a query fails") { SECTION("cloning of a query fails") {
// Mock the Registry // Mock the Registry
fakeit::When(Method(mockRegistry, insert)).Do([&] (QueryId id, Query* query, double timeout, bool isPrepared, bool keepLease) { fakeit::When(Method(mockRegistry, insert))
REQUIRE(id != 0); .Do([&](QueryId id, Query* query, double timeout, bool isPrepared, bool keepLease) {
REQUIRE(query != nullptr); REQUIRE(id != 0);
REQUIRE(timeout == 600.0); REQUIRE(query != nullptr);
REQUIRE(isPrepared == true); REQUIRE(timeout == 600.0);
REQUIRE(keepLease == false); REQUIRE(isPrepared == true);
REQUIRE(query == &queryClone); REQUIRE(keepLease == false);
secondId = id; REQUIRE(query == &queryClone);
}); secondId = id;
});
SECTION("it throws an error") { SECTION("it throws an error") {
// Mock query clone // Mock query clone
fakeit::When(Method(mockQuery, clone)).Do([&](QueryPart part, bool withPlan) -> Query* { fakeit::When(Method(mockQuery, clone))
REQUIRE(part == PART_DEPENDENT); .Do([&](QueryPart part, bool withPlan) -> Query* {
REQUIRE(withPlan == false); REQUIRE(part == PART_DEPENDENT);
return &queryClone; REQUIRE(withPlan == false);
}).Throw(arangodb::basics::Exception(TRI_ERROR_DEBUG, __FILE__, __LINE__)); return &queryClone;
})
.Throw(arangodb::basics::Exception(TRI_ERROR_DEBUG, __FILE__, __LINE__));
ExecutionEngineResult result = testee.buildEngines( ExecutionEngineResult result =
&query, &registry, dbname, restrictToShards, queryIds, lockedShards testee.buildEngines(&query, &registry, dbname, restrictToShards,
); queryIds, lockedShards);
REQUIRE(!result.ok()); REQUIRE(!result.ok());
// Make sure we check the right thing here // Make sure we check the right thing here
REQUIRE(result.errorNumber() == TRI_ERROR_DEBUG); REQUIRE(result.errorNumber() == TRI_ERROR_DEBUG);
@ -718,20 +752,21 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
SECTION("it returns nullptr") { SECTION("it returns nullptr") {
// Mock query clone // Mock query clone
fakeit::When(Method(mockQuery, clone)).Do([&](QueryPart part, bool withPlan) -> Query* { fakeit::When(Method(mockQuery, clone))
REQUIRE(part == PART_DEPENDENT); .Do([&](QueryPart part, bool withPlan) -> Query* {
REQUIRE(withPlan == false); REQUIRE(part == PART_DEPENDENT);
return &queryClone; REQUIRE(withPlan == false);
}).Do([&](QueryPart part, bool withPlan) -> Query* { return &queryClone;
REQUIRE(part == PART_DEPENDENT); })
REQUIRE(withPlan == false); .Do([&](QueryPart part, bool withPlan) -> Query* {
return nullptr; REQUIRE(part == PART_DEPENDENT);
}); REQUIRE(withPlan == false);
return nullptr;
});
ExecutionEngineResult result =
ExecutionEngineResult result = testee.buildEngines( testee.buildEngines(&query, &registry, dbname, restrictToShards,
&query, &registry, dbname, restrictToShards, queryIds, lockedShards queryIds, lockedShards);
);
REQUIRE(!result.ok()); REQUIRE(!result.ok());
// Make sure we check the right thing here // Make sure we check the right thing here
REQUIRE(result.errorNumber() == TRI_ERROR_INTERNAL); REQUIRE(result.errorNumber() == TRI_ERROR_INTERNAL);
@ -753,7 +788,9 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
fakeit::Verify(Method(mockRegistry, insert)).Exactly(1); fakeit::Verify(Method(mockRegistry, insert)).Exactly(1);
// Assert unregister of second engine. // Assert unregister of second engine.
fakeit::Verify(OverloadedMethod(mockRegistry, destroy, void(std::string const&, QueryId, int))).Exactly(1); fakeit::Verify(OverloadedMethod(mockRegistry, destroy,
void(std::string const&, QueryId, int)))
.Exactly(1);
} }
/* /*
@ -805,8 +842,7 @@ TEST_CASE("EngineInfoContainerCoordinator", "[aql][cluster][coordinator]") {
} }
*/ */
} }
} }
} // test } // namespace engine_info_container_coordinator_test
} // aql } // namespace tests
} // arangodb } // namespace arangodb

View File

@ -499,7 +499,7 @@ describe ArangoDB do
it "creates a cursor that will expire" do it "creates a cursor that will expire" do
cmd = api cmd = api
body = "{ \"query\" : \"FOR u IN #{@cn} LIMIT 5 RETURN u.n\", \"count\" : true, \"batchSize\" : 1, \"ttl\" : 10 }" body = "{ \"query\" : \"FOR u IN #{@cn} LIMIT 5 RETURN u.n\", \"count\" : true, \"batchSize\" : 1, \"ttl\" : 2 }"
doc = ArangoDB.log_post("#{prefix}-create-ttl", cmd, :body => body) doc = ArangoDB.log_post("#{prefix}-create-ttl", cmd, :body => body)
doc.code.should eq(201) doc.code.should eq(201)
@ -550,13 +550,13 @@ describe ArangoDB do
# when it really vanishes, as this depends on thread scheduling, state # when it really vanishes, as this depends on thread scheduling, state
# of the cleanup thread etc. # of the cleanup thread etc.
# sleep 10 # this should delete the cursor on the server sleep 10 # this should delete the cursor on the server
# doc = ArangoDB.log_put("#{prefix}-create-ttl", cmd) doc = ArangoDB.log_put("#{prefix}-create-ttl", cmd)
# doc.code.should eq(404) doc.code.should eq(404)
# doc.headers['content-type'].should eq("application/json; charset=utf-8") doc.headers['content-type'].should eq("application/json; charset=utf-8")
# doc.parsed_response['error'].should eq(true) doc.parsed_response['error'].should eq(true)
# doc.parsed_response['errorNum'].should eq(1600) doc.parsed_response['errorNum'].should eq(1600)
# doc.parsed_response['code'].should eq(404) doc.parsed_response['code'].should eq(404)
end end
it "creates a cursor that will not expire" do it "creates a cursor that will not expire" do