1
0
Fork 0

Merge pull request #4899 from arangodb/bug-fix/internal-issue-#344.8.1

manually-merge: add more tests, backport some miscellaneous fixes
This commit is contained in:
Andrey Abramov 2018-03-20 18:22:51 +03:00 committed by GitHub
commit 5d78cf8aa8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 729 additions and 59 deletions

View File

@ -153,6 +153,7 @@ if (USE_IRESEARCH)
set(IRESEARCH_EXCLUDE_STATIC_THIRD_PARTY_LIBS TRUE) # disable linking in of 3rd party libraries automatically set(IRESEARCH_EXCLUDE_STATIC_THIRD_PARTY_LIBS TRUE) # disable linking in of 3rd party libraries automatically
find_package(IResearch REQUIRED) # set IRESEARCH_BUILD_DIR find_package(IResearch REQUIRED) # set IRESEARCH_BUILD_DIR
set(CMAKE_MACOSX_RPATH ON) # suppress cmake warning (use same value as cmake default)
set(CMAKE_MODULE_PATH_ORIGINAL ${CMAKE_MODULE_PATH}) # remember CMAKE_MODULE_PATH set(CMAKE_MODULE_PATH_ORIGINAL ${CMAKE_MODULE_PATH}) # remember CMAKE_MODULE_PATH
list(APPEND CMAKE_MODULE_PATH list(APPEND CMAKE_MODULE_PATH
"${CMAKE_CURRENT_SOURCE_DIR}/cmake" # cmake overrides (must be first) "${CMAKE_CURRENT_SOURCE_DIR}/cmake" # cmake overrides (must be first)

View File

@ -289,7 +289,7 @@ if(MSVC)
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy
COMMAND ${CMAKE_COMMAND} -E make_directory iql COMMAND ${CMAKE_COMMAND} -E make_directory iql
COMMAND ${CMAKE_COMMAND} -E compare_files ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy iql/parser.yy || bison --graph --report=all -o iql/parser.cc ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy COMMAND ${CMAKE_COMMAND} -E compare_files ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy iql/parser.yy || bison --graph --report=all -Wnone -o iql/parser.cc ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy iql/parser.yy COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy iql/parser.yy
) )
else() else()
@ -298,7 +298,7 @@ else()
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy
COMMAND ${CMAKE_COMMAND} -E make_directory iql COMMAND ${CMAKE_COMMAND} -E make_directory iql
COMMAND bison --graph --report=all -o iql/parser.cc ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy COMMAND bison --graph --report=all -Wnone -o iql/parser.cc ${CMAKE_CURRENT_SOURCE_DIR}/iql/parser.yy
) )
endif() endif()

View File

@ -256,18 +256,25 @@ irs::analysis::analyzer::ptr construct(
} }
} }
// interpret the cache_key as a locale name try {
std::string locale_name(cache_key.c_str(), cache_key.size()); // interpret the cache_key as a locale name
auto locale = irs::locale_utils::locale(locale_name); std::string locale_name(cache_key.c_str(), cache_key.size());
ignored_words_t buf; auto locale = irs::locale_utils::locale(locale_name);
ignored_words_t buf;
if (!get_ignored_words(buf, locale)) { if (!get_ignored_words(buf, locale)) {
IR_FRMT_WARN("Failed to retrieve 'ignored_words' while constructing text_token_stream with cache key: %s", cache_key.c_str()); IR_FRMT_WARN("Failed to retrieve 'ignored_words' while constructing text_token_stream with cache key: %s", cache_key.c_str());
return nullptr; return nullptr;
}
return construct(cache_key, locale, std::move(buf));
} catch (...) {
IR_FRMT_ERROR("Caught error while constructing text_token_stream cache key: %s", cache_key.c_str());
IR_LOG_EXCEPTION();
} }
return construct(cache_key, locale, std::move(buf)); return nullptr;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -409,34 +416,41 @@ irs::analysis::analyzer::ptr make_json(const irs::string_ref& args) {
return nullptr; return nullptr;
} }
static const rapidjson::Value empty; try {
auto locale = irs::locale_utils::locale(json["locale"].GetString()); static const rapidjson::Value empty;
auto& ignored_words = json.HasMember("ignored_words") ? json["ignored_words"] : empty; auto locale = irs::locale_utils::locale(json["locale"].GetString());
auto& ignored_words_path = json.HasMember("ignored_words_path") ? json["ignored_words_path"] : empty; auto& ignored_words = json.HasMember("ignored_words") ? json["ignored_words"] : empty;
auto& ignored_words_path = json.HasMember("ignored_words_path") ? json["ignored_words_path"] : empty;
if (!ignored_words.IsArray()) { if (!ignored_words.IsArray()) {
return ignored_words_path.IsString() return ignored_words_path.IsString()
? construct(args, locale, ignored_words_path.GetString()) ? construct(args, locale, ignored_words_path.GetString())
: construct(args, locale) : construct(args, locale)
; ;
}
ignored_words_t buf;
for (auto itr = ignored_words.Begin(), end = ignored_words.End(); itr != end; ++itr) {
if (!itr->IsString()) {
IR_FRMT_WARN("Non-string value in 'ignored_words' while constructing text_token_stream from jSON arguments: %s", args.c_str());
return nullptr;
} }
buf.emplace(itr->GetString()); ignored_words_t buf;
for (auto itr = ignored_words.Begin(), end = ignored_words.End(); itr != end; ++itr) {
if (!itr->IsString()) {
IR_FRMT_WARN("Non-string value in 'ignored_words' while constructing text_token_stream from jSON arguments: %s", args.c_str());
return nullptr;
}
buf.emplace(itr->GetString());
}
return ignored_words_path.IsString()
? construct(args, locale, ignored_words_path.GetString(), std::move(buf))
: construct(args, locale, std::move(buf))
;
} catch (...) {
IR_FRMT_ERROR("Caught error while constructing text_token_stream from jSON arguments: %s", args.c_str());
IR_LOG_EXCEPTION();
} }
return ignored_words_path.IsString() return nullptr;
? construct(args, locale, ignored_words_path.GetString(), std::move(buf))
: construct(args, locale, std::move(buf))
;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -78,7 +78,7 @@ inline int path_stats(file_stat_t& info, const file_path_t path) {
auto parts = irs::file_utils::path_parts(path); auto parts = irs::file_utils::path_parts(path);
return file_stat( return file_stat(
parts.basename.null() ? std::wstring(parts.dirname).c_str() : path, parts.basename.empty() ? std::wstring(parts.dirname).c_str() : path,
&info &info
); );
#else #else
@ -517,7 +517,7 @@ bool exists(bool& result, const file_path_t file) NOEXCEPT {
result = 0 == path_stats(info, file); result = 0 == path_stats(info, file);
if (!result) { if (!result && ENOENT != errno) {
auto path = boost::locale::conv::utf_to_utf<char>(file); auto path = boost::locale::conv::utf_to_utf<char>(file);
IR_FRMT_ERROR("Failed to get stat, error %d path: %s", errno, path.c_str()); IR_FRMT_ERROR("Failed to get stat, error %d path: %s", errno, path.c_str());
@ -532,16 +532,16 @@ bool exists_directory(bool& result, const file_path_t name) NOEXCEPT {
result = 0 == path_stats(info, name); result = 0 == path_stats(info, name);
if (!result) { if (result) {
auto path = boost::locale::conv::utf_to_utf<char>(name);
IR_FRMT_ERROR("Failed to get stat, error %d path: %s", errno, path.c_str());
} else {
#ifdef _WIN32 #ifdef _WIN32
result = (info.st_mode & _S_IFDIR) > 0; result = (info.st_mode & _S_IFDIR) > 0;
#else #else
result = (info.st_mode & S_IFDIR) > 0; result = (info.st_mode & S_IFDIR) > 0;
#endif #endif
} else if (ENOENT != errno) {
auto path = boost::locale::conv::utf_to_utf<char>(name);
IR_FRMT_ERROR("Failed to get stat, error %d path: %s", errno, path.c_str());
} }
return true; return true;
@ -553,16 +553,16 @@ bool exists_file(bool& result, const file_path_t name) NOEXCEPT {
result = 0 == path_stats(info, name); result = 0 == path_stats(info, name);
if (!result) { if (result) {
auto path = boost::locale::conv::utf_to_utf<char>(name);
IR_FRMT_ERROR("Failed to get stat, error %d path: %s", errno, path.c_str());
} else {
#ifdef _WIN32 #ifdef _WIN32
result = (info.st_mode & _S_IFREG) > 0; result = (info.st_mode & _S_IFREG) > 0;
#else #else
result = (info.st_mode & S_IFREG) > 0; result = (info.st_mode & S_IFREG) > 0;
#endif #endif
} else if (ENOENT != errno) {
auto path = boost::locale::conv::utf_to_utf<char>(name);
IR_FRMT_ERROR("Failed to get stat, error %d path: %s", errno, path.c_str());
} }
return true; return true;

View File

@ -7,7 +7,7 @@
@RESTURLPARAMETERS @RESTURLPARAMETERS
@RESTDESCRIPTION @RESTDESCRIPTION
TBD Returns an object containing the definition of the view identified by *view-name*.
@RESTURLPARAM{view-name,string,required} @RESTURLPARAM{view-name,string,required}
The name of the view. The name of the view.

View File

@ -48,7 +48,9 @@ if (USE_IRESEARCH)
IResearch/ExpressionContextMock.cpp IResearch/ExpressionContextMock.cpp
IResearch/VelocyPackHelper-test.cpp IResearch/VelocyPackHelper-test.cpp
IResearch/ExecutionBlockMock-test.cpp IResearch/ExecutionBlockMock-test.cpp
Utils/CollectionNameResolver-test.cpp
VocBase/LogicalDataSource-test.cpp VocBase/LogicalDataSource-test.cpp
VocBase/vocbase-test.cpp
) )
endif () endif ()

View File

@ -374,12 +374,19 @@ SECTION("test_async_index") {
// populate collections asynchronously // populate collections asynchronously
{ {
std::thread thread0([collection0, &resThread0]()->void { std::thread thread0([collection0, &resThread0]()->void {
irs::utf8_path resource; arangodb::velocypack::Builder builder;
resource/=irs::string_ref(IResearch_test_resource_dir);
resource/=irs::string_ref("simple_sequential.json"); try {
irs::utf8_path resource;
resource/=irs::string_ref(IResearch_test_resource_dir);
resource/=irs::string_ref("simple_sequential.json");
builder = arangodb::basics::VelocyPackHelper::velocyPackFromFile(resource.utf8());
} catch (...) {
return; // velocyPackFromFile(...) may throw exception
}
auto doc = arangodb::velocypack::Parser::fromJson("{ \"seq\": 40, \"same\": \"xyz\", \"duplicated\": \"abcd\" }"); auto doc = arangodb::velocypack::Parser::fromJson("{ \"seq\": 40, \"same\": \"xyz\", \"duplicated\": \"abcd\" }");
auto builder = arangodb::basics::VelocyPackHelper::velocyPackFromFile(resource.utf8());
auto slice = builder.slice(); auto slice = builder.slice();
resThread0 = slice.isArray(); resThread0 = slice.isArray();
if (!resThread0) return; if (!resThread0) return;
@ -405,12 +412,19 @@ SECTION("test_async_index") {
}); });
std::thread thread1([collection1, &resThread1]()->void { std::thread thread1([collection1, &resThread1]()->void {
irs::utf8_path resource; arangodb::velocypack::Builder builder;
resource/=irs::string_ref(IResearch_test_resource_dir);
resource/=irs::string_ref("simple_sequential.json"); try {
irs::utf8_path resource;
resource/=irs::string_ref(IResearch_test_resource_dir);
resource/=irs::string_ref("simple_sequential.json");
builder = arangodb::basics::VelocyPackHelper::velocyPackFromFile(resource.utf8());
} catch (...) {
return; // velocyPackFromFile(...) may throw exception
}
auto doc = arangodb::velocypack::Parser::fromJson("{ \"seq\": 50, \"same\": \"xyz\", \"duplicated\": \"abcd\" }"); auto doc = arangodb::velocypack::Parser::fromJson("{ \"seq\": 50, \"same\": \"xyz\", \"duplicated\": \"abcd\" }");
auto builder = arangodb::basics::VelocyPackHelper::velocyPackFromFile(resource.utf8());
auto slice = builder.slice(); auto slice = builder.slice();
resThread1 = slice.isArray(); resThread1 = slice.isArray();
if (!resThread1) return; if (!resThread1) return;
@ -627,4 +641,4 @@ SECTION("test_fields") {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE // --SECTION-- END-OF-FILE
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -188,12 +188,12 @@ SECTION("test_inheritDefaults") {
analyzers.start(); analyzers.start();
defaults._fields["abc"] = std::move(arangodb::iresearch::IResearchLinkMeta()); defaults._fields["abc"] = arangodb::iresearch::IResearchLinkMeta();
defaults._includeAllFields = true; defaults._includeAllFields = true;
defaults._trackListPositions = true; defaults._trackListPositions = true;
defaults._analyzers.clear(); defaults._analyzers.clear();
defaults._analyzers.emplace_back(analyzers.ensure("empty")); defaults._analyzers.emplace_back(analyzers.ensure("empty"));
defaults._fields["abc"]->_fields["xyz"] = std::move(arangodb::iresearch::IResearchLinkMeta()); defaults._fields["abc"]->_fields["xyz"] = arangodb::iresearch::IResearchLinkMeta();
auto json = arangodb::velocypack::Parser::fromJson("{}"); auto json = arangodb::velocypack::Parser::fromJson("{}");
CHECK(true == meta.init(json->slice(), tmpString, defaults)); CHECK(true == meta.init(json->slice(), tmpString, defaults));
@ -410,8 +410,8 @@ SECTION("test_writeCustomizedValues") {
auto& overrideNone = *(meta._fields["c"]->_fields["none"]); auto& overrideNone = *(meta._fields["c"]->_fields["none"]);
overrideAll._fields.clear(); // do not inherit fields to match jSon inheritance overrideAll._fields.clear(); // do not inherit fields to match jSon inheritance
overrideAll._fields["x"] = std::move(arangodb::iresearch::IResearchLinkMeta()); overrideAll._fields["x"] = arangodb::iresearch::IResearchLinkMeta();
overrideAll._fields["y"] = std::move(arangodb::iresearch::IResearchLinkMeta()); overrideAll._fields["y"] = arangodb::iresearch::IResearchLinkMeta();
overrideAll._includeAllFields = false; overrideAll._includeAllFields = false;
overrideAll._trackListPositions = false; overrideAll._trackListPositions = false;
overrideAll._analyzers.clear(); overrideAll._analyzers.clear();

View File

@ -30,6 +30,7 @@
#include "Enterprise/Ldap/LdapFeature.h" #include "Enterprise/Ldap/LdapFeature.h"
#endif #endif
#include "Basics/files.h"
#include "V8/v8-globals.h" #include "V8/v8-globals.h"
#include "VocBase/LogicalCollection.h" #include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h" #include "VocBase/LogicalView.h"
@ -132,6 +133,13 @@ struct IResearchQuerySetup {
analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer analyzers->emplace("test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer analyzers->emplace("test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
irs::utf8_path testFilesystemPath;
testFilesystemPath /= TRI_GetTempPath();
testFilesystemPath /= std::string("arangodb_tests.") + std::to_string(TRI_microtime());
const_cast<std::string&>(dbPathFeature->directory()) = testFilesystemPath.utf8();
// suppress log messages since tests check error conditions // suppress log messages since tests check error conditions
arangodb::LogTopic::setLogLevel(arangodb::Logger::FIXME.name(), arangodb::LogLevel::ERR); // suppress WARNING DefaultCustomTypeHandler called arangodb::LogTopic::setLogLevel(arangodb::Logger::FIXME.name(), arangodb::LogLevel::ERR); // suppress WARNING DefaultCustomTypeHandler called
arangodb::LogTopic::setLogLevel(arangodb::iresearch::IResearchFeature::IRESEARCH.name(), arangodb::LogLevel::FATAL); arangodb::LogTopic::setLogLevel(arangodb::iresearch::IResearchFeature::IRESEARCH.name(), arangodb::LogLevel::FATAL);

View File

@ -0,0 +1,263 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Andrey Abramov
/// @author Vasiliy Nabatchikov
////////////////////////////////////////////////////////////////////////////////
#include "catch.hpp"
#include "../IResearch/common.h"
#include "../IResearch/StorageEngineMock.h"
#include "IResearch/ApplicationServerHelper.h"
#include "RestServer/DatabaseFeature.h"
#include "RestServer/QueryRegistryFeature.h"
#include "RestServer/ViewTypesFeature.h"
#include "StorageEngine/EngineSelectorFeature.h"
#include "Utils/CollectionNameResolver.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "velocypack/Parser.h"
namespace {
std::unique_ptr<arangodb::ViewImplementation> makeTestView(
arangodb::LogicalView* view,
arangodb::velocypack::Slice const& info,
bool isNew
) {
struct Impl: public arangodb::ViewImplementation {
Impl(): ViewImplementation(nullptr, arangodb::velocypack::Slice::emptyObjectSlice()) {
}
virtual void drop() override {}
virtual void getPropertiesVPack(
arangodb::velocypack::Builder&, bool
) const override {
}
virtual void open() override {}
virtual arangodb::Result updateProperties(
arangodb::velocypack::Slice const&, bool, bool
) override {
return arangodb::Result();
}
virtual bool visitCollections(
std::function<bool(TRI_voc_cid_t)> const&
) const override {
return true;
}
};
return std::unique_ptr<arangodb::ViewImplementation>(new Impl());
}
}
// -----------------------------------------------------------------------------
// --SECTION-- setup / tear-down
// -----------------------------------------------------------------------------
struct CollectionNameResolverSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
CollectionNameResolverSetup(): server(nullptr, nullptr) {
arangodb::EngineSelectorFeature::ENGINE = &engine;
// setup required application features
features.emplace_back(new arangodb::DatabaseFeature(&server), false); // required for TRI_vocbase_t::dropCollection(...)
features.emplace_back(new arangodb::QueryRegistryFeature(&server), false); // required for TRI_vocbase_t instantiation
features.emplace_back(new arangodb::ViewTypesFeature(&server), false); // required for TRI_vocbase_t::createView(...)
for (auto& f: features) {
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
}
for (auto& f: features) {
f.first->prepare();
}
for (auto& f: features) {
if (f.second) {
f.first->start();
}
}
// register view factory
arangodb::iresearch::getFeature<arangodb::ViewTypesFeature>()->emplace(
arangodb::LogicalDataSource::Type::emplace(
arangodb::velocypack::StringRef("testViewType")
),
makeTestView
);
}
~CollectionNameResolverSetup() {
arangodb::application_features::ApplicationServer::server = nullptr;
arangodb::EngineSelectorFeature::ENGINE = nullptr;
// destroy application features
for (auto& f: features) {
if (f.second) {
f.first->stop();
}
}
for (auto& f: features) {
f.first->unprepare();
}
}
};
// -----------------------------------------------------------------------------
// --SECTION-- test suite
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief setup
////////////////////////////////////////////////////////////////////////////////
TEST_CASE("CollectionNameResolverTest", "[vocbase]") {
CollectionNameResolverSetup s;
(void)(s);
SECTION("test_getDataSource") {
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"globallyUniqueId\": \"testCollectionGUID\", \"id\": 100, \"name\": \"testCollection\" }");
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"id\": 200, \"name\": \"testView\", \"type\": \"testViewType\" }"); // any arbitrary view type
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
arangodb::CollectionNameResolver resolver(&vocbase);
// not present collection (no datasource)
{
CHECK((true == !resolver.getDataSource(100)));
CHECK((true == !resolver.getDataSource("100")));
CHECK((true == !resolver.getDataSource("testCollection")));
CHECK((true == !resolver.getDataSource("testCollectionGUID")));
CHECK((true == !resolver.getCollection(100)));
CHECK((true == !resolver.getCollection("100")));
CHECK((true == !resolver.getCollection("testCollection")));
CHECK((true == !resolver.getCollection("testCollectionGUID")));
}
// not present view (no datasource)
{
CHECK((true == !resolver.getDataSource(200)));
CHECK((true == !resolver.getDataSource("200")));
CHECK((true == !resolver.getDataSource("testView")));
CHECK((true == !resolver.getDataSource("testViewGUID")));
CHECK((true == !resolver.getView(200)));
CHECK((true == !resolver.getView("200")));
CHECK((true == !resolver.getView("testView")));
CHECK((true == !resolver.getView("testViewGUID")));
}
auto* collection = vocbase.createCollection(collectionJson->slice());
auto view = vocbase.createView(viewJson->slice(), 42);
CHECK((false == collection->deleted()));
CHECK((false == view->deleted()));
// not present collection (is view)
{
CHECK((false == !resolver.getDataSource(200)));
CHECK((false == !resolver.getDataSource("200")));
CHECK((false == !resolver.getDataSource("testView")));
CHECK((true == !resolver.getDataSource("testViewGUID")));
CHECK((true == !resolver.getCollection(200)));
CHECK((true == !resolver.getCollection("200")));
CHECK((true == !resolver.getCollection("testView")));
CHECK((true == !resolver.getCollection("testViewGUID")));
}
// not preset view (is collection)
{
CHECK((false == !resolver.getDataSource(100)));
CHECK((false == !resolver.getDataSource("100")));
CHECK((false == !resolver.getDataSource("testCollection")));
CHECK((false == !resolver.getDataSource("testCollectionGUID")));
CHECK((true == !resolver.getView(100)));
CHECK((true == !resolver.getView("100")));
CHECK((true == !resolver.getView("testCollection")));
CHECK((true == !resolver.getView("testCollectionGUID")));
}
// present collection
{
CHECK((false == !resolver.getDataSource(100)));
CHECK((false == !resolver.getDataSource("100")));
CHECK((false == !resolver.getDataSource("testCollection")));
CHECK((false == !resolver.getDataSource("testCollectionGUID")));
CHECK((false == !resolver.getCollection(100)));
CHECK((false == !resolver.getCollection("100")));
CHECK((false == !resolver.getCollection("testCollection")));
CHECK((false == !resolver.getCollection("testCollectionGUID")));
}
// present view
{
CHECK((false == !resolver.getDataSource(200)));
CHECK((false == !resolver.getDataSource("200")));
CHECK((false == !resolver.getDataSource("testView")));
CHECK((true == !resolver.getDataSource("testViewGUID")));
CHECK((false == !resolver.getView(200)));
CHECK((false == !resolver.getView("200")));
CHECK((false == !resolver.getView("testView")));
CHECK((true == !resolver.getView("testViewGUID")));
}
CHECK((TRI_ERROR_NO_ERROR == vocbase.dropCollection(collection, true, 0)));
CHECK((TRI_ERROR_NO_ERROR == vocbase.dropView(view)));
CHECK((true == collection->deleted()));
CHECK((true == view->deleted()));
// present collection (deleted, cached)
{
CHECK((false == !resolver.getDataSource(100)));
CHECK((false == !resolver.getDataSource("100")));
CHECK((false == !resolver.getDataSource("testCollection")));
CHECK((false == !resolver.getDataSource("testCollectionGUID")));
CHECK((false == !resolver.getCollection(100)));
CHECK((false == !resolver.getCollection("100")));
CHECK((false == !resolver.getCollection("testCollection")));
CHECK((false == !resolver.getCollection("testCollectionGUID")));
CHECK((true == resolver.getCollection(100)->deleted()));
}
// present view (deleted, cached)
{
CHECK((false == !resolver.getDataSource(200)));
CHECK((false == !resolver.getDataSource("200")));
CHECK((false == !resolver.getDataSource("testView")));
CHECK((true == !resolver.getDataSource("testViewGUID")));
CHECK((false == !resolver.getView(200)));
CHECK((false == !resolver.getView("200")));
CHECK((false == !resolver.getView("testView")));
CHECK((true == !resolver.getView("testViewGUID")));
CHECK((true == resolver.getView(200)->deleted()));
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate tests
////////////////////////////////////////////////////////////////////////////////
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------

View File

@ -0,0 +1,368 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Andrey Abramov
/// @author Vasiliy Nabatchikov
////////////////////////////////////////////////////////////////////////////////
#include "catch.hpp"
#include "../IResearch/common.h"
#include "../IResearch/StorageEngineMock.h"
#include "IResearch/ApplicationServerHelper.h"
#include "RestServer/DatabaseFeature.h"
#include "RestServer/QueryRegistryFeature.h"
#include "RestServer/ViewTypesFeature.h"
#include "StorageEngine/EngineSelectorFeature.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "velocypack/Parser.h"
namespace {
std::unique_ptr<arangodb::ViewImplementation> makeTestView(
arangodb::LogicalView* view,
arangodb::velocypack::Slice const& info,
bool isNew
) {
struct Impl: public arangodb::ViewImplementation {
Impl(): ViewImplementation(nullptr, arangodb::velocypack::Slice::emptyObjectSlice()) {
}
virtual void drop() override {}
virtual void getPropertiesVPack(
arangodb::velocypack::Builder&, bool
) const override {
}
virtual void open() override {}
virtual arangodb::Result updateProperties(
arangodb::velocypack::Slice const&, bool, bool
) override {
return arangodb::Result();
}
virtual bool visitCollections(
std::function<bool(TRI_voc_cid_t)> const&
) const override {
return true;
}
};
return std::unique_ptr<arangodb::ViewImplementation>(new Impl());
}
}
// -----------------------------------------------------------------------------
// --SECTION-- setup / tear-down
// -----------------------------------------------------------------------------
struct VocbaseSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
VocbaseSetup(): server(nullptr, nullptr) {
arangodb::EngineSelectorFeature::ENGINE = &engine;
// setup required application features
features.emplace_back(new arangodb::DatabaseFeature(&server), false); // required for TRI_vocbase_t::dropCollection(...)
features.emplace_back(new arangodb::QueryRegistryFeature(&server), false); // required for TRI_vocbase_t instantiation
features.emplace_back(new arangodb::ViewTypesFeature(&server), false); // required for TRI_vocbase_t::createView(...)
for (auto& f: features) {
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
}
for (auto& f: features) {
f.first->prepare();
}
for (auto& f: features) {
if (f.second) {
f.first->start();
}
}
// register view factory
arangodb::iresearch::getFeature<arangodb::ViewTypesFeature>()->emplace(
arangodb::LogicalDataSource::Type::emplace(
arangodb::velocypack::StringRef("testViewType")
),
makeTestView
);
}
~VocbaseSetup() {
arangodb::application_features::ApplicationServer::server = nullptr;
arangodb::EngineSelectorFeature::ENGINE = nullptr;
// destroy application features
for (auto& f: features) {
if (f.second) {
f.first->stop();
}
}
for (auto& f: features) {
f.first->unprepare();
}
}
};
// -----------------------------------------------------------------------------
// --SECTION-- test suite
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief setup
////////////////////////////////////////////////////////////////////////////////
TEST_CASE("VocbaseTest", "[vocbase]") {
VocbaseSetup s;
(void)(s);
SECTION("test_isAllowedName") {
// direct (non-system)
{
CHECK((false == TRI_vocbase_t::IsAllowedName(false, arangodb::velocypack::StringRef(nullptr, 0))));
CHECK((false == TRI_vocbase_t::IsAllowedName(false, arangodb::velocypack::StringRef(""))));
CHECK((true == TRI_vocbase_t::IsAllowedName(false, arangodb::velocypack::StringRef("abc123"))));
CHECK((false == TRI_vocbase_t::IsAllowedName(false, arangodb::velocypack::StringRef("123abc"))));
CHECK((false == TRI_vocbase_t::IsAllowedName(false, arangodb::velocypack::StringRef("123"))));
CHECK((false == TRI_vocbase_t::IsAllowedName(false, arangodb::velocypack::StringRef("_123"))));
CHECK((false == TRI_vocbase_t::IsAllowedName(false, arangodb::velocypack::StringRef("_abc"))));
CHECK((false == TRI_vocbase_t::IsAllowedName(false, arangodb::velocypack::StringRef("abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")))); // longer than TRI_COL_NAME_LENGTH
}
// direct (system)
{
CHECK((false == TRI_vocbase_t::IsAllowedName(true, arangodb::velocypack::StringRef(nullptr, 0))));
CHECK((false == TRI_vocbase_t::IsAllowedName(true, arangodb::velocypack::StringRef(""))));
CHECK((true == TRI_vocbase_t::IsAllowedName(true, arangodb::velocypack::StringRef("abc123"))));
CHECK((false == TRI_vocbase_t::IsAllowedName(true, arangodb::velocypack::StringRef("123abc"))));
CHECK((false == TRI_vocbase_t::IsAllowedName(true, arangodb::velocypack::StringRef("123"))));
CHECK((true == TRI_vocbase_t::IsAllowedName(true, arangodb::velocypack::StringRef("_123"))));
CHECK((true == TRI_vocbase_t::IsAllowedName(true, arangodb::velocypack::StringRef("_abc"))));
CHECK((false == TRI_vocbase_t::IsAllowedName(true, arangodb::velocypack::StringRef("abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")))); // longer than TRI_COL_NAME_LENGTH
}
// slice (default)
{
auto json0 = arangodb::velocypack::Parser::fromJson("{ }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json0->slice())));
auto json1 = arangodb::velocypack::Parser::fromJson("{ \"name\": \"\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json1->slice())));
auto json2 = arangodb::velocypack::Parser::fromJson("{ \"name\": \"abc123\" }");
CHECK((true == TRI_vocbase_t::IsAllowedName(json2->slice())));
auto json3 = arangodb::velocypack::Parser::fromJson("{ \"name\": \"123abc\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json3->slice())));
auto json4 = arangodb::velocypack::Parser::fromJson("{ \"name\": \"123\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json4->slice())));
auto json5 = arangodb::velocypack::Parser::fromJson("{ \"name\": \"_123\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json5->slice())));
auto json6 = arangodb::velocypack::Parser::fromJson("{ \"name\": \"_abc\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json6->slice())));
auto json7 = arangodb::velocypack::Parser::fromJson("{ \"name\": \"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json7->slice()))); // longer than TRI_COL_NAME_LENGTH
}
// slice (non-system)
{
auto json0 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": false }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json0->slice())));
auto json1 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": false, \"name\": \"\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json1->slice())));
auto json2 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": false, \"name\": \"abc123\" }");
CHECK((true == TRI_vocbase_t::IsAllowedName(json2->slice())));
auto json3 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": false, \"name\": \"123abc\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json3->slice())));
auto json4 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": false, \"name\": \"123\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json4->slice())));
auto json5 = arangodb::velocypack::Parser::fromJson("{\"isSystem\": false, \"name\": \"_123\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json5->slice())));
auto json6 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": false, \"name\": \"_abc\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json6->slice())));
auto json7 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": false, \"name\": 123 }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json7->slice())));
auto json8 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": 123, \"name\": \"abc\" }");
CHECK((true == TRI_vocbase_t::IsAllowedName(json8->slice())));
auto json9 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": false, \"name\": \"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json9->slice()))); // longer than TRI_COL_NAME_LENGTH
}
// slice (system)
{
auto json0 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": true }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json0->slice())));
auto json1 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": true, \"name\": \"\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json1->slice())));
auto json2 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": true, \"name\": \"abc123\" }");
CHECK((true == TRI_vocbase_t::IsAllowedName(json2->slice())));
auto json3 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": true, \"name\": \"123abc\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json3->slice())));
auto json4 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": true, \"name\": \"123\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json4->slice())));
auto json5 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": true, \"name\": \"_123\" }");
CHECK((true == TRI_vocbase_t::IsAllowedName(json5->slice())));
auto json6 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": true, \"name\": \"_abc\" }");
CHECK((true == TRI_vocbase_t::IsAllowedName(json6->slice())));
auto json7 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": true, \"name\": 123 }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json7->slice())));
auto json8 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": 123, \"name\": \"_abc\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json8->slice())));
auto json9 = arangodb::velocypack::Parser::fromJson("{ \"isSystem\": true, \"name\": \"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\" }");
CHECK((false == TRI_vocbase_t::IsAllowedName(json9->slice()))); // longer than TRI_COL_NAME_LENGTH
}
}
SECTION("test_isSystemName") {
CHECK((false == TRI_vocbase_t::IsSystemName("")));
CHECK((true == TRI_vocbase_t::IsSystemName("_")));
CHECK((true == TRI_vocbase_t::IsSystemName("_abc")));
CHECK((false == TRI_vocbase_t::IsSystemName("abc")));
}
SECTION("test_lookupDataSource") {
auto collectionJson = arangodb::velocypack::Parser::fromJson("{ \"globallyUniqueId\": \"testCollectionGUID\", \"id\": 100, \"name\": \"testCollection\" }");
auto viewJson = arangodb::velocypack::Parser::fromJson("{ \"id\": 200, \"name\": \"testView\", \"type\": \"testViewType\" }"); // any arbitrary view type
Vocbase vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
// not present collection (no datasource)
{
CHECK((true == !vocbase.lookupDataSource(100)));
CHECK((true == !vocbase.lookupDataSource("100")));
CHECK((true == !vocbase.lookupDataSource("testCollection")));
CHECK((true == !vocbase.lookupDataSource("testCollectionGUID")));
CHECK((true == !vocbase.lookupCollection(100)));
CHECK((true == !vocbase.lookupCollection("100")));
CHECK((true == !vocbase.lookupCollection("testCollection")));
CHECK((true == !vocbase.lookupCollection("testCollectionGUID")));
}
// not present view (no datasource)
{
CHECK((true == !vocbase.lookupDataSource(200)));
CHECK((true == !vocbase.lookupDataSource("200")));
CHECK((true == !vocbase.lookupDataSource("testView")));
CHECK((true == !vocbase.lookupDataSource("testViewGUID")));
CHECK((true == !vocbase.lookupView(200)));
CHECK((true == !vocbase.lookupView("200")));
CHECK((true == !vocbase.lookupView("testView")));
CHECK((true == !vocbase.lookupView("testViewGUID")));
}
auto* collection = vocbase.createCollection(collectionJson->slice());
auto view = vocbase.createView(viewJson->slice(), 42);
CHECK((false == collection->deleted()));
CHECK((false == view->deleted()));
// not present collection (is view)
{
CHECK((false == !vocbase.lookupDataSource(200)));
CHECK((false == !vocbase.lookupDataSource("200")));
CHECK((false == !vocbase.lookupDataSource("testView")));
CHECK((true == !vocbase.lookupDataSource("testViewGUID")));
CHECK((true == !vocbase.lookupCollection(200)));
CHECK((true == !vocbase.lookupCollection("200")));
CHECK((true == !vocbase.lookupCollection("testView")));
CHECK((true == !vocbase.lookupCollection("testViewGUID")));
CHECK((true == !vocbase.lookupCollectionByUuid("testView")));
CHECK((true == !vocbase.lookupCollectionByUuid("testViewGUID")));
}
// not preset view (is collection)
{
CHECK((false == !vocbase.lookupDataSource(100)));
CHECK((false == !vocbase.lookupDataSource("100")));
CHECK((false == !vocbase.lookupDataSource("testCollection")));
CHECK((false == !vocbase.lookupDataSource("testCollectionGUID")));
CHECK((true == !vocbase.lookupView(100)));
CHECK((true == !vocbase.lookupView("100")));
CHECK((true == !vocbase.lookupView("testCollection")));
CHECK((true == !vocbase.lookupView("testCollectionGUID")));
}
// present collection
{
CHECK((false == !vocbase.lookupDataSource(100)));
CHECK((false == !vocbase.lookupDataSource("100")));
CHECK((false == !vocbase.lookupDataSource("testCollection")));
CHECK((false == !vocbase.lookupDataSource("testCollectionGUID")));
CHECK((false == !vocbase.lookupCollection(100)));
CHECK((false == !vocbase.lookupCollection("100")));
CHECK((false == !vocbase.lookupCollection("testCollection")));
CHECK((false == !vocbase.lookupCollection("testCollectionGUID")));
CHECK((true == !vocbase.lookupCollectionByUuid("testCollection")));
CHECK((false == !vocbase.lookupCollectionByUuid("testCollectionGUID")));
}
// present view
{
CHECK((false == !vocbase.lookupDataSource(200)));
CHECK((false == !vocbase.lookupDataSource("200")));
CHECK((false == !vocbase.lookupDataSource("testView")));
CHECK((true == !vocbase.lookupDataSource("testViewGUID")));
CHECK((false == !vocbase.lookupView(200)));
CHECK((false == !vocbase.lookupView("200")));
CHECK((false == !vocbase.lookupView("testView")));
CHECK((true == !vocbase.lookupView("testViewGUID")));
}
CHECK((TRI_ERROR_NO_ERROR == vocbase.dropCollection(collection, true, 0)));
CHECK((TRI_ERROR_NO_ERROR == vocbase.dropView(view)));
CHECK((true == collection->deleted()));
CHECK((true == view->deleted()));
// not present collection (deleted)
{
CHECK((true == !vocbase.lookupDataSource(100)));
CHECK((true == !vocbase.lookupDataSource("100")));
CHECK((true == !vocbase.lookupDataSource("testCollection")));
CHECK((true == !vocbase.lookupDataSource("testCollectionGUID")));
CHECK((true == !vocbase.lookupCollection(100)));
CHECK((true == !vocbase.lookupCollection("100")));
CHECK((true == !vocbase.lookupCollection("testCollection")));
CHECK((true == !vocbase.lookupCollection("testCollectionGUID")));
CHECK((true == !vocbase.lookupCollectionByUuid("testCollection")));
CHECK((true == !vocbase.lookupCollectionByUuid("testCollectionGUID")));
}
// not present view (deleted)
{
CHECK((true == !vocbase.lookupDataSource(200)));
CHECK((true == !vocbase.lookupDataSource("200")));
CHECK((true == !vocbase.lookupDataSource("testView")));
CHECK((true == !vocbase.lookupDataSource("testViewGUID")));
CHECK((true == !vocbase.lookupView(200)));
CHECK((true == !vocbase.lookupView("200")));
CHECK((true == !vocbase.lookupView("testView")));
CHECK((true == !vocbase.lookupView("testViewGUID")));
CHECK((true == !vocbase.lookupCollectionByUuid("testCollection")));
CHECK((true == !vocbase.lookupCollectionByUuid("testCollectionGUID")));
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate tests
////////////////////////////////////////////////////////////////////////////////
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------