mirror of https://gitee.com/bigwinds/arangodb
added test, not done yet
This commit is contained in:
parent
05216b3249
commit
81069293bc
|
@ -0,0 +1,289 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// DISCLAIMER
|
||||||
|
///
|
||||||
|
/// Copyright 2018 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 Goedderz
|
||||||
|
/// @author Michael Hackstein
|
||||||
|
/// @author Heiko Kernbach
|
||||||
|
/// @author Jan Christoph Uhde
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#include "Aql/AqlCall.h"
|
||||||
|
#include "AqlItemBlockHelper.h"
|
||||||
|
#include "IResearch/common.h"
|
||||||
|
#include "Mocks/Servers.h"
|
||||||
|
#include "QueryHelper.h"
|
||||||
|
#include "RowFetcherHelper.h"
|
||||||
|
|
||||||
|
#include "Aql/AqlItemBlock.h"
|
||||||
|
#include "Aql/Ast.h"
|
||||||
|
#include "Aql/Collection.h"
|
||||||
|
#include "Aql/ExecutionBlockImpl.h"
|
||||||
|
#include "Aql/ExecutionEngine.h"
|
||||||
|
#include "Aql/Expression.h"
|
||||||
|
#include "Aql/IndexExecutor.h"
|
||||||
|
#include "Aql/IndexNode.h"
|
||||||
|
#include "Aql/OutputAqlItemRow.h"
|
||||||
|
#include "Aql/ResourceUsage.h"
|
||||||
|
#include "Aql/Stats.h"
|
||||||
|
#include "Aql/Variable.h"
|
||||||
|
#include "RestServer/QueryRegistryFeature.h"
|
||||||
|
#include "Sharding/ShardingFeature.h"
|
||||||
|
#include "StorageEngine/EngineSelectorFeature.h"
|
||||||
|
#include "Transaction/Context.h"
|
||||||
|
#include "Transaction/Methods.h"
|
||||||
|
#include "VocBase/AccessMode.h"
|
||||||
|
#include "VocBase/LogicalCollection.h"
|
||||||
|
|
||||||
|
#include <Aql/Condition.h>
|
||||||
|
#include <velocypack/velocypack-aliases.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
using namespace arangodb;
|
||||||
|
using namespace arangodb::aql;
|
||||||
|
|
||||||
|
namespace arangodb {
|
||||||
|
namespace tests {
|
||||||
|
namespace aql {
|
||||||
|
|
||||||
|
static const std::string GetAllDocs =
|
||||||
|
R"aql(FOR doc IN UnitTestCollection SORT doc.sortValue RETURN doc.value)aql";
|
||||||
|
|
||||||
|
using CursorType = arangodb::transaction::Methods::CursorType;
|
||||||
|
|
||||||
|
class IndexExecutorTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
ExecutionState state;
|
||||||
|
ResourceMonitor monitor;
|
||||||
|
AqlItemBlockManager itemBlockManager;
|
||||||
|
arangodb::tests::mocks::MockAqlServer server;
|
||||||
|
TRI_vocbase_t& vocbase;
|
||||||
|
std::shared_ptr<VPackBuilder> json;
|
||||||
|
std::shared_ptr<LogicalCollection> collection;
|
||||||
|
|
||||||
|
std::unique_ptr<arangodb::aql::Query> fakedQuery;
|
||||||
|
Ast ast;
|
||||||
|
Ast* astPtr = *
|
||||||
|
// AstNode* astNode = ast.createNodeReference("a");
|
||||||
|
|
||||||
|
Variable outVariable;
|
||||||
|
bool produceResult;
|
||||||
|
std::unordered_set<RegisterId> const regToClear;
|
||||||
|
std::unordered_set<RegisterId> const regToKeep;
|
||||||
|
ExecutionEngine* engine;
|
||||||
|
Collection aqlCollection;
|
||||||
|
std::vector<std::string> const projections;
|
||||||
|
std::vector<size_t> const coveringIndexAttributePositions;
|
||||||
|
std::vector<Variable const*> inVars;
|
||||||
|
std::vector<RegisterId> inRegs;
|
||||||
|
std::unique_ptr<Condition> condition;
|
||||||
|
std::vector<transaction::Methods::IndexHandle> indexes;
|
||||||
|
IndexIteratorOptions options;
|
||||||
|
std::vector<std::unique_ptr<NonConstExpression>> nonConstExpressions;
|
||||||
|
bool useRawPointers;
|
||||||
|
bool hasV8Expression;
|
||||||
|
IndexExecutorInfos infos;
|
||||||
|
|
||||||
|
SharedAqlItemBlockPtr block;
|
||||||
|
VPackBuilder input;
|
||||||
|
|
||||||
|
IndexExecutorTest()
|
||||||
|
: itemBlockManager(&monitor, SerializationFormat::SHADOWROWS),
|
||||||
|
server(),
|
||||||
|
vocbase(server.getSystemDatabase()),
|
||||||
|
json(VPackParser::fromJson(R"({"name":"UnitTestCollection"})")),
|
||||||
|
collection(vocbase.createCollection(json->slice())),
|
||||||
|
fakedQuery(server.createFakeQuery("return 1")),
|
||||||
|
ast(fakedQuery.get()),
|
||||||
|
outVariable("name", 1),
|
||||||
|
produceResult(false),
|
||||||
|
engine(fakedQuery.get()->engine()),
|
||||||
|
aqlCollection("UnitTestCollection", &vocbase, arangodb::AccessMode::Type::READ),
|
||||||
|
useRawPointers(false),
|
||||||
|
hasV8Expression(false),
|
||||||
|
infos(0 /*outReg*/, 1 /*nrIn*/, 1 /*nrOut*/, regToClear, regToKeep,
|
||||||
|
engine, &aqlCollection, &outVariable, produceResult, nullptr,
|
||||||
|
projections, coveringIndexAttributePositions, useRawPointers,
|
||||||
|
std::move(nonConstExpressions), std::move(inVars), std::move(inRegs),
|
||||||
|
hasV8Expression, nullptr, indexes, astPtr, options),
|
||||||
|
block(new AqlItemBlock(itemBlockManager, 1000, 2)) {
|
||||||
|
auto node = fakedQuery.get()->plan()->root();
|
||||||
|
auto canUseIndex = condition->findIndexes(node, indexes, nullptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(IndexExecutorTest, the_producer_does_not_wait) {
|
||||||
|
SingleRowFetcherHelper<::arangodb::aql::BlockPassthrough::Disable> fetcher(
|
||||||
|
itemBlockManager, input.steal(), false);
|
||||||
|
IndexExecutor testee(fetcher, infos);
|
||||||
|
// Use this instead of std::ignore, so the tests will be noticed and
|
||||||
|
// updated when someone changes the stats type in the return value of
|
||||||
|
// IndexExecutor::produceRows().
|
||||||
|
IndexStats stats{};
|
||||||
|
|
||||||
|
OutputAqlItemRow result(std::move(block), infos.getOutputRegisters(),
|
||||||
|
infos.registersToKeep(), infos.registersToClear());
|
||||||
|
std::tie(state, stats) = testee.produceRows(result);
|
||||||
|
ASSERT_EQ(state, ExecutionState::DONE);
|
||||||
|
ASSERT_FALSE(result.produced());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IndexExecutorTest, the_producer_waits) {
|
||||||
|
SingleRowFetcherHelper<::arangodb::aql::BlockPassthrough::Disable> fetcher(
|
||||||
|
itemBlockManager, input.steal(), true);
|
||||||
|
IndexExecutor testee(fetcher, infos);
|
||||||
|
// Use this instead of std::ignore, so the tests will be noticed and
|
||||||
|
// updated when someone changes the stats type in the return value of
|
||||||
|
// IndexExecutor::produceRows().
|
||||||
|
IndexStats stats{};
|
||||||
|
|
||||||
|
OutputAqlItemRow result(std::move(block), infos.getOutputRegisters(),
|
||||||
|
infos.registersToKeep(), infos.registersToClear());
|
||||||
|
std::tie(state, stats) = testee.produceRows(result);
|
||||||
|
ASSERT_EQ(state, ExecutionState::WAITING);
|
||||||
|
ASSERT_FALSE(result.produced());
|
||||||
|
|
||||||
|
std::tie(state, stats) = testee.produceRows(result);
|
||||||
|
ASSERT_EQ(state, ExecutionState::DONE);
|
||||||
|
ASSERT_FALSE(result.produced());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IndexExecutorTest, the_produce_datarange_empty) {
|
||||||
|
SingleRowFetcherHelper<::arangodb::aql::BlockPassthrough::Disable> fetcher(
|
||||||
|
itemBlockManager, input.steal(), false);
|
||||||
|
IndexExecutor testee(fetcher, infos);
|
||||||
|
// Use this instead of std::ignore, so the tests will be noticed and
|
||||||
|
// updated when someone changes the stats type in the return value of
|
||||||
|
// IndexExecutor::produceRows().
|
||||||
|
|
||||||
|
SharedAqlItemBlockPtr inBlock = buildBlock<1>(itemBlockManager, {{}});
|
||||||
|
|
||||||
|
AqlItemBlockInputRange inputRange{ExecutorState::DONE, inBlock, 0, inBlock->size()};
|
||||||
|
OutputAqlItemRow output(std::move(block), infos.getOutputRegisters(),
|
||||||
|
infos.registersToKeep(), infos.registersToClear());
|
||||||
|
|
||||||
|
auto const [state, stats, call] = testee.produceRows(1000, inputRange, output);
|
||||||
|
ASSERT_EQ(state, ExecutorState::DONE);
|
||||||
|
ASSERT_FALSE(output.produced());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IndexExecutorTest, the_skip_datarange_empty) {
|
||||||
|
SingleRowFetcherHelper<::arangodb::aql::BlockPassthrough::Disable> fetcher(
|
||||||
|
itemBlockManager, input.steal(), false);
|
||||||
|
IndexExecutor testee(fetcher, infos);
|
||||||
|
// Use this instead of std::ignore, so the tests will be noticed and
|
||||||
|
// updated when someone changes the stats type in the return value of
|
||||||
|
// IndexExecutor::produceRows().
|
||||||
|
|
||||||
|
SharedAqlItemBlockPtr inBlock = buildBlock<1>(itemBlockManager, {{}});
|
||||||
|
|
||||||
|
AqlItemBlockInputRange inputRange{ExecutorState::DONE, inBlock, 0, inBlock->size()};
|
||||||
|
OutputAqlItemRow output(std::move(block), infos.getOutputRegisters(),
|
||||||
|
infos.registersToKeep(), infos.registersToClear());
|
||||||
|
auto const [state, skipped, call] = testee.skipRowsRange(1000, inputRange);
|
||||||
|
ASSERT_EQ(state, ExecutorState::DONE);
|
||||||
|
ASSERT_EQ(skipped, 0);
|
||||||
|
ASSERT_FALSE(output.produced());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IndexExecutorTest, the_produce_datarange) {
|
||||||
|
SingleRowFetcherHelper<::arangodb::aql::BlockPassthrough::Disable> fetcher(
|
||||||
|
itemBlockManager, input.steal(), false);
|
||||||
|
IndexExecutor testee(fetcher, infos);
|
||||||
|
// Use this instead of std::ignore, so the tests will be noticed and
|
||||||
|
// updated when someone changes the stats type in the return value of
|
||||||
|
// IndexExecutor::produceRows().
|
||||||
|
|
||||||
|
SharedAqlItemBlockPtr inBlock =
|
||||||
|
buildBlock<1>(itemBlockManager,
|
||||||
|
{{R"({ "cid" : "1337", "name": "UnitTestCollection" })"}});
|
||||||
|
|
||||||
|
// insert 3x documents
|
||||||
|
std::string insertQuery =
|
||||||
|
R"aql(INSERT {_key: "testee", value: 1, sortValue: 1, nestedObject: {value: 1} } INTO UnitTestCollection)aql";
|
||||||
|
SCOPED_TRACE(insertQuery);
|
||||||
|
AssertQueryHasResult(vocbase, insertQuery, VPackSlice::emptyArraySlice());
|
||||||
|
auto expected = VPackParser::fromJson(R"([1])");
|
||||||
|
AssertQueryHasResult(vocbase, GetAllDocs, expected->slice());
|
||||||
|
|
||||||
|
std::string insertQueryB =
|
||||||
|
R"aql(INSERT {_key: "testeeB", value: 1, sortValue: 1, nestedObject: {value: 1} } INTO UnitTestCollection)aql";
|
||||||
|
SCOPED_TRACE(insertQueryB);
|
||||||
|
AssertQueryHasResult(vocbase, insertQueryB, VPackSlice::emptyArraySlice());
|
||||||
|
|
||||||
|
std::string insertQueryC =
|
||||||
|
R"aql(INSERT {_key: "testeeC", value: 1, sortValue: 1, nestedObject: {value: 1} } INTO UnitTestCollection)aql";
|
||||||
|
SCOPED_TRACE(insertQueryC);
|
||||||
|
AssertQueryHasResult(vocbase, insertQueryC, VPackSlice::emptyArraySlice());
|
||||||
|
|
||||||
|
AqlItemBlockInputRange inputRange{ExecutorState::DONE, inBlock, 0, inBlock->size()};
|
||||||
|
OutputAqlItemRow output(std::move(block), infos.getOutputRegisters(),
|
||||||
|
infos.registersToKeep(), infos.registersToClear());
|
||||||
|
|
||||||
|
auto const [state, stats, call] = testee.produceRows(1000, inputRange, output);
|
||||||
|
ASSERT_EQ(state, ExecutorState::DONE);
|
||||||
|
ASSERT_EQ(stats.getFiltered(), 0);
|
||||||
|
ASSERT_EQ(stats.getScanned(), 3);
|
||||||
|
ASSERT_FALSE(output.produced());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IndexExecutorTest, the_skip_datarange) {
|
||||||
|
SingleRowFetcherHelper<::arangodb::aql::BlockPassthrough::Disable> fetcher(
|
||||||
|
itemBlockManager, input.steal(), false);
|
||||||
|
IndexExecutor testee(fetcher, infos);
|
||||||
|
// Use this instead of std::ignore, so the tests will be noticed and
|
||||||
|
// updated when someone changes the stats type in the return value of
|
||||||
|
// IndexExecutor::produceRows().
|
||||||
|
|
||||||
|
SharedAqlItemBlockPtr inBlock =
|
||||||
|
buildBlock<1>(itemBlockManager,
|
||||||
|
{{R"({ "cid" : "1337", "name": "UnitTestCollection" })"}});
|
||||||
|
|
||||||
|
// insert 3x documents
|
||||||
|
std::string insertQuery =
|
||||||
|
R"aql(INSERT {_key: "testee", value: 1, sortValue: 1, nestedObject: {value: 1} } INTO UnitTestCollection)aql";
|
||||||
|
SCOPED_TRACE(insertQuery);
|
||||||
|
AssertQueryHasResult(vocbase, insertQuery, VPackSlice::emptyArraySlice());
|
||||||
|
auto expected = VPackParser::fromJson(R"([1])");
|
||||||
|
AssertQueryHasResult(vocbase, GetAllDocs, expected->slice());
|
||||||
|
|
||||||
|
std::string insertQueryB =
|
||||||
|
R"aql(INSERT {_key: "testeeB", value: 1, sortValue: 1, nestedObject: {value: 1} } INTO UnitTestCollection)aql";
|
||||||
|
SCOPED_TRACE(insertQueryB);
|
||||||
|
AssertQueryHasResult(vocbase, insertQueryB, VPackSlice::emptyArraySlice());
|
||||||
|
|
||||||
|
std::string insertQueryC =
|
||||||
|
R"aql(INSERT {_key: "testeeC", value: 1, sortValue: 1, nestedObject: {value: 1} } INTO UnitTestCollection)aql";
|
||||||
|
SCOPED_TRACE(insertQueryC);
|
||||||
|
AssertQueryHasResult(vocbase, insertQueryC, VPackSlice::emptyArraySlice());
|
||||||
|
|
||||||
|
AqlItemBlockInputRange inputRange{ExecutorState::DONE, inBlock, 0, inBlock->size()};
|
||||||
|
OutputAqlItemRow output(std::move(block), infos.getOutputRegisters(),
|
||||||
|
infos.registersToKeep(), infos.registersToClear());
|
||||||
|
|
||||||
|
auto const [state, skipped, call] = testee.skipRowsRange(1000, inputRange);
|
||||||
|
ASSERT_EQ(state, ExecutorState::DONE);
|
||||||
|
ASSERT_EQ(skipped, 3);
|
||||||
|
ASSERT_FALSE(output.produced());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace aql
|
||||||
|
} // namespace tests
|
||||||
|
} // namespace arangodb
|
Loading…
Reference in New Issue