1
0
Fork 0

issue 526.4.1: add analyzer removal and feature validation functionality (#8575)

This commit is contained in:
Vasiliy 2019-03-26 14:17:40 +03:00 committed by Andrey Abramov
parent 14843a4275
commit 778417cdf0
24 changed files with 1287 additions and 655 deletions

View File

@ -60,7 +60,7 @@
namespace {
static std::string const ANALYZER_COLLECTION_NAME("_iresearch_analyzers");
static std::string const ANALYZER_COLLECTION_NAME("_analyzers");
static char const ANALYZER_PREFIX_DELIM = ':'; // name prefix delimiter (2 chars)
static size_t const DEFAULT_POOL_SIZE = 8; // arbitrary value
static std::string const FEATURE_NAME("IResearchAnalyzer");
@ -467,6 +467,34 @@ std::pair<irs::string_ref, irs::string_ref> splitAnalyzerName( // split name
return std::make_pair(irs::string_ref::NIL, analyzer); // unprefixed analyzer name
}
////////////////////////////////////////////////////////////////////////////////
/// @brief validate that features are supported by arangod an ensure that their
/// dependencies are met
////////////////////////////////////////////////////////////////////////////////
arangodb::Result validateFeatures(irs::flags const& features) {
for(auto& feature: features) {
if (&irs::frequency::type() == feature) {
// no extra validation required
} else if (&irs::norm::type() == feature) {
// no extra validation required
} else if (&irs::position::type() == feature) {
if (!features.check(irs::frequency::type())) {
return arangodb::Result( // result
TRI_ERROR_BAD_PARAMETER, // code
std::string("missing feature '") + std::string(irs::frequency::type().name()) +"' required when '" + std::string(feature->name()) + "' feature is specified"
);
}
} else if (feature) {
return arangodb::Result( // result
TRI_ERROR_BAD_PARAMETER, // code
std::string("unsupported analyzer feature '") + std::string(feature->name()) + "'" // value
);
}
}
return arangodb::Result();
}
typedef irs::async_utils::read_write_mutex::read_mutex ReadMutex;
typedef irs::async_utils::read_write_mutex::write_mutex WriteMutex;
@ -660,11 +688,6 @@ IResearchAnalyzerFeature::IResearchAnalyzerFeature(arangodb::application_feature
split = splitAnalyzerName(analyzer);
}
// FIXME TODO remove temporary workaround once emplace(...) and all tests are updated
if (split.first.null()) {
return true;
}
return !split.first.null() // have a vocbase
&& ctx->canUseDatabase(split.first, level) // can use vocbase
&& ctx->canUseCollection(split.first, ANALYZER_COLLECTION_NAME, level); // can use analyzers
@ -715,11 +738,6 @@ std::pair<IResearchAnalyzerFeature::AnalyzerPool::ptr, bool> IResearchAnalyzerFe
// skip initialization and persistance
if (!initAndPersist) {
if (itr.second) {
_customAnalyzers[itr.first->first] =
itr.first->second; // mark as custom if insertion took place
}
erase = false;
return std::make_pair(pool, itr.second);
@ -845,6 +863,12 @@ arangodb::Result IResearchAnalyzerFeature::ensure( // ensure analyzer existence
const_cast<AnalyzerPool::ptr&>(value) = pool; // lazy-instantiate pool to avoid allocation if pool is already present
return pool ? irs::hashed_string_ref(key.hash(), pool->name()) : key; // reuse hash but point ref at value in pool
};
auto res = validateFeatures(features);
if (!res.ok()) {
return res;
}
WriteMutex mutex(_mutex);
SCOPED_LOCK(mutex);
@ -885,9 +909,9 @@ arangodb::Result IResearchAnalyzerFeature::ensure( // ensure analyzer existence
}
// persist only on coordinator and single-server
auto res = arangodb::ServerState::instance()->isCoordinator() // coordinator
|| arangodb::ServerState::instance()->isSingleServer() // single-server
? storeAnalyzer(*pool) : arangodb::Result();
res = arangodb::ServerState::instance()->isCoordinator() // coordinator
|| arangodb::ServerState::instance()->isSingleServer() // single-server
? storeAnalyzer(*pool) : arangodb::Result();
if (res.ok()) {
result = std::make_pair(pool, itr.second);
@ -929,114 +953,6 @@ arangodb::Result IResearchAnalyzerFeature::ensure( // ensure analyzer existence
return arangodb::Result();
}
size_t IResearchAnalyzerFeature::erase(irs::string_ref const& name) noexcept {
try {
WriteMutex mutex(_mutex);
SCOPED_LOCK(mutex);
auto itr =
_customAnalyzers.find(irs::make_hashed_ref(name, std::hash<irs::string_ref>()));
if (itr == _customAnalyzers.end()) {
return 0; // nothing to erase
}
auto pool = itr->second;
if (!pool) {
LOG_TOPIC("ea7df", WARN, arangodb::iresearch::TOPIC)
<< "removal of an unset arangosearch analizer name '" << name << "'";
_analyzers.erase(itr->first); // ok to erase since found in '_customAnalyzers'
_customAnalyzers.erase(itr);
return 0; // no actual valid analyzer was removed (this is definitly a
// bug somewhere)
}
if (_started) {
auto vocbase = getSystemDatabase();
if (!vocbase) {
LOG_TOPIC("68dc6", WARN, arangodb::iresearch::TOPIC)
<< "failure to get system database while removing arangosearch "
"analyzer name '"
<< pool->name() << "'";
return 0;
}
arangodb::SingleCollectionTransaction trx(
arangodb::transaction::StandaloneContext::Create(*vocbase),
ANALYZER_COLLECTION_NAME, arangodb::AccessMode::Type::WRITE);
auto res = trx.begin();
if (!res.ok()) {
LOG_TOPIC("13ff5", WARN, arangodb::iresearch::TOPIC)
<< "failure to start transaction while removing configuration for "
"arangosearch analyzer name '"
<< pool->name() << "'";
return 0;
}
arangodb::velocypack::Builder builder;
arangodb::OperationOptions options;
builder.openObject();
builder.add(arangodb::StaticStrings::KeyString, toValuePair(pool->_key));
builder.close();
options.waitForSync = true;
auto result = trx.remove(ANALYZER_COLLECTION_NAME, builder.slice(), options);
// stataic analyzers are not persisted
if (!result.ok() && result.isNot(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND)) {
LOG_TOPIC("4e7f4", WARN, arangodb::iresearch::TOPIC)
<< "failure to persist AnalyzerPool configuration while removing "
"arangosearch analyzer name '"
<< pool->name() << "'";
trx.abort();
return 0;
}
if (!trx.commit().ok()) {
LOG_TOPIC("68afe", WARN, arangodb::iresearch::TOPIC)
<< "failure to commit AnalyzerPool configuration while removing "
"arangosearch analyzer name '"
<< pool->name() << "'";
trx.abort();
return 0;
}
}
// OK to erase if !_started because on start() the persisted configuration
// will be loaded
_analyzers.erase(itr->first); // ok to erase since found in '_customAnalyzers'
_customAnalyzers.erase(itr);
return 1;
} catch (arangodb::basics::Exception& e) {
LOG_TOPIC("3cbe0", WARN, arangodb::iresearch::TOPIC)
<< "caught exception while removing an arangosearch analizer name '"
<< name << "': " << e.code() << " " << e.what();
IR_LOG_EXCEPTION();
} catch (std::exception& e) {
LOG_TOPIC("e4cd7", WARN, arangodb::iresearch::TOPIC)
<< "caught exception while removing an arangosearch analizer name '"
<< name << "': " << e.what();
IR_LOG_EXCEPTION();
} catch (...) {
LOG_TOPIC("1afcb", WARN, arangodb::iresearch::TOPIC)
<< "caught exception while removing an arangosearch analizer name '"
<< name << "'";
IR_LOG_EXCEPTION();
}
return 0;
}
IResearchAnalyzerFeature::AnalyzerPool::ptr IResearchAnalyzerFeature::get( // find analyzer
irs::string_ref const& name // analyzer name
) const noexcept {
@ -1119,8 +1035,6 @@ IResearchAnalyzerFeature::AnalyzerPool::ptr IResearchAnalyzerFeature::get( // fi
// register the indentity analyzer
{
static const irs::flags extraFeatures = {irs::frequency::type(), irs::norm::type()};
// static const irs::flags extraFeatures = { }; // FIXME TODO use above
// once tfidf/bm25 sort is fixed
static const irs::string_ref name("identity");
PTR_NAMED(AnalyzerPool, pool, name);
@ -1315,6 +1229,14 @@ bool IResearchAnalyzerFeature::loadConfiguration() {
properties = getStringRef(propertiesSlice);
}
auto normalizedName = // normalized name
collection->vocbase().name() + "::" + std::string(name);
auto& staticAnalyzersMap = getStaticAnalyzers();
if (staticAnalyzersMap.find(irs::make_hashed_ref(name, std::hash<irs::string_ref>())) == staticAnalyzersMap.end()) {
name = normalizedName; // use normalized name if it's not a static analyzer
}
auto entry = emplace(name, type, properties,
false); // do not persist since this config is already
// coming from the persisted store
@ -1489,11 +1411,6 @@ bool IResearchAnalyzerFeature::loadConfiguration() {
auto split = splitAnalyzerName(name);
if (expandVocbasePrefix) {
// FIXME TODO remove temporary workaround once emplace(...) and all tests are updated
if (split.first.null()) {
return split.second;
}
if (split.first.null()) {
return std::string(activeVocbase.name()).append(2, ANALYZER_PREFIX_DELIM).append(split.second);
}
@ -1525,6 +1442,170 @@ void IResearchAnalyzerFeature::prepare() {
::iresearch::analysis::analyzers::init();
}
arangodb::Result IResearchAnalyzerFeature::remove( // remove analyzer
irs::string_ref const& name, // analyzer name
bool force /*= false*/ // force removal
) {
try {
auto split = splitAnalyzerName(name);
if (split.first.null()) {
return arangodb::Result( // result
TRI_ERROR_FORBIDDEN, // code
"static analyzers cannot be removed" // message
);
}
WriteMutex mutex(_mutex);
SCOPED_LOCK(mutex);
auto itr = // find analyzer
_analyzers.find(irs::make_hashed_ref(name, std::hash<irs::string_ref>()));
if (itr == _analyzers.end()) {
return arangodb::Result( // result
TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND, // code
std::string("failure to find analyzer while removing arangosearch analyzer '") + std::string(name)+ "'"
);
}
auto& pool = itr->second;
// this should never happen since analyzers should always be valid, but this
// will make the state consistent again
if (!pool) {
_analyzers.erase(itr);
return arangodb::Result( // result
TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND, // code
std::string("failure to find a valid analyzer while removing arangosearch analyzer '") + std::string(name)+ "'"
);
}
if (!force && pool.use_count() > 1) { // +1 for ref in '_analyzers'
return arangodb::Result( // result
TRI_ERROR_FORBIDDEN, // code
std::string("analyzer in-use while removing arangosearch analyzer '") + std::string(name)+ "'"
);
}
// on db-server analyzers are not persisted
// allow removal even inRecovery()
if (arangodb::ServerState::instance()->isDBServer()) {
_analyzers.erase(itr);
return arangodb::Result();
}
// .........................................................................
// after here the analyzer must be removed from the persisted store first
// .........................................................................
// this should never happen since non-static analyzers should always have a
// valid '_key' after
if (pool->_key.null()) {
return arangodb::Result( // result
TRI_ERROR_INTERNAL, // code
std::string("failure to find '") + arangodb::StaticStrings::KeyString + "' while removing arangosearch analyzer '" + std::string(name)+ "'"
);
}
auto* engine = arangodb::EngineSelectorFeature::ENGINE;
// do not allow persistence while in recovery
if (engine && engine->inRecovery()) {
return arangodb::Result( // result
TRI_ERROR_INTERNAL, // code
std::string("failure to remove arangosearch analyzer '") + std::string(name)+ "' configuration while storage engine in recovery"
);
}
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
arangodb::DatabaseFeature // feature type
>("Database");
if (!dbFeature) {
return arangodb::Result( // result
TRI_ERROR_INTERNAL, // code
std::string("failure to find feature 'Database' while removing arangosearch analyzer '") + std::string(name)+ "'"
);
}
auto* vocbase = dbFeature->useDatabase(split.first);
if (!vocbase) {
return arangodb::Result( // result
TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND, // code
std::string("failure to find vocbase while removing arangosearch analyzer '") + std::string(name)+ "'"
);
}
std::shared_ptr<arangodb::LogicalCollection> collection;
auto collectionCallback = [&collection]( // store collection
std::shared_ptr<arangodb::LogicalCollection> const& col // args
)->void {
collection = col;
};
arangodb::methods::Collections::lookup( // find collection
*vocbase, ANALYZER_COLLECTION_NAME, collectionCallback // args
);
if (!collection) {
return arangodb::Result( // result
TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND, // code
std::string("failure to find collection while removing arangosearch analyzer '") + std::string(name)+ "'"
);
}
arangodb::SingleCollectionTransaction trx( // transaction
arangodb::transaction::StandaloneContext::Create(*vocbase), // transaction context
ANALYZER_COLLECTION_NAME, // collection name
arangodb::AccessMode::Type::WRITE // collection access type
);
auto res = trx.begin();
if (!res.ok()) {
return res;
}
arangodb::velocypack::Builder builder;
arangodb::OperationOptions options;
builder.openObject();
builder.add(arangodb::StaticStrings::KeyString, toValuePair(pool->_key));
builder.close();
auto result = // remove
trx.remove(ANALYZER_COLLECTION_NAME, builder.slice(), options);
if (!result.ok()) {
trx.abort();
return result.result;
}
_analyzers.erase(itr);
} catch (arangodb::basics::Exception const& e) {
return arangodb::Result( // result
e.code(), // code
std::string("caught exception while removing configuration for arangosearch analyzer name '") + std::string(name) + "': " + std::to_string(e.code()) + " "+ e.what()
);
} catch (std::exception const& e) {
return arangodb::Result( // result
TRI_ERROR_INTERNAL, // code
std::string("caught exception while removing configuration for arangosearch analyzer name '") + std::string(name) + "': " + e.what()
);
} catch (...) {
return arangodb::Result( // result
TRI_ERROR_INTERNAL, // code
std::string("caught exception while removing configuration for arangosearch analyzer name '") + std::string(name) + "'"
);
}
return arangodb::Result();
}
void IResearchAnalyzerFeature::start() {
ApplicationFeature::start();
@ -1542,9 +1623,9 @@ void IResearchAnalyzerFeature::start() {
"IResearch functions";
}
}
/*FIXME TODO disable until V8 handler is implemented for JavaScript tests
registerUpgradeTasks(); // register tasks after UpgradeFeature::prepare() has finished
*/
// ensure that the configuration collection is present before loading
// configuration for the case of inRecovery() if there is no collection then
// obviously no custom analyzer configurations were persisted (so missing
@ -1752,8 +1833,6 @@ arangodb::Result IResearchAnalyzerFeature::storeAnalyzer(AnalyzerPool& pool) {
builder.add("name", toValuePair(split.second));
builder.add("type", toValuePair(pool.type()));
// do not allow to pass null properties since it causes undefined behavior
// in `arangodb::velocypack::Builder`
if (pool.properties().null()) {
builder.add( // add value
"properties", // name
@ -1763,6 +1842,35 @@ arangodb::Result IResearchAnalyzerFeature::storeAnalyzer(AnalyzerPool& pool) {
builder.add("properties", toValuePair(pool.properties()));
}
// only add features if there are present
if (!pool.features().empty()) {
builder.add( // add array
"features", // name
arangodb::velocypack::Value(arangodb::velocypack::ValueType::Array) // value
);
for (auto& feature: pool.features()) {
// this should never happen since irs::flags currently provides no way
// to set nullptr
if (!feature) {
return arangodb::Result( // result
TRI_ERROR_INTERNAL, // code
std::string("failure to to add null feature persising arangosearch analyzer '") + pool.name()+ "'"
);
}
if (feature->name().null()) {
builder.add( // add value
arangodb::velocypack::Value(arangodb::velocypack::ValueType::Null) // value
);
} else {
builder.add(toValuePair(feature->name()));
}
}
builder.close();
}
builder.close();
options.waitForSync = true;

View File

@ -150,14 +150,9 @@ class IResearchAnalyzerFeature final : public arangodb::application_features::Ap
// FIXME TODO remove
AnalyzerPool::ptr ensure(irs::string_ref const& name);
//////////////////////////////////////////////////////////////////////////////
/// @return number of analyzers removed
//////////////////////////////////////////////////////////////////////////////
size_t erase(irs::string_ref const& name) noexcept;
//////////////////////////////////////////////////////////////////////////////
/// @brief find analyzer
/// @param name analyzer name (used verbatim)
/// @param name analyzer name (already normalized)
/// @return analyzer with the specified name or nullptr
//////////////////////////////////////////////////////////////////////////////
AnalyzerPool::ptr get(irs::string_ref const& name) const noexcept;
@ -193,6 +188,14 @@ class IResearchAnalyzerFeature final : public arangodb::application_features::Ap
);
void prepare() override;
//////////////////////////////////////////////////////////////////////////////
/// @brief remove the specified analyzer
/// @param name analyzer name (already normalized)
/// @param force remove even if the analyzer is actively referenced
//////////////////////////////////////////////////////////////////////////////
arangodb::Result remove(irs::string_ref const& name, bool force = false);
void start() override;
void stop() override;

View File

@ -1149,7 +1149,22 @@ bool fromFuncAnalyzer(irs::boolean_filter* filter, QueryContext const& ctx,
return false;
}
analyzer = analyzerFeature->get(analyzerIdValue);
if (ctx.trx) {
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
arangodb::SystemDatabaseFeature // featue type
>();
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
if (sysVocbase) {
analyzer = analyzerFeature->get( // get analyzer
arangodb::iresearch::IResearchAnalyzerFeature::normalize( // normalize
analyzerIdValue, ctx.trx->vocbase(), *sysVocbase // args
)
);
}
} else {
analyzer = analyzerFeature->get(analyzerIdValue); // verbatim
}
if (!analyzer) {
LOG_TOPIC("404c9", WARN, arangodb::iresearch::TOPIC)

View File

@ -653,55 +653,56 @@ namespace iresearch {
return LINK_TYPE;
}
/*static*/ arangodb::Result IResearchLinkHelper::validateLinks(
TRI_vocbase_t& vocbase, arangodb::velocypack::Slice const& links) {
/*static*/ arangodb::Result IResearchLinkHelper::validateLinks( // validate
TRI_vocbase_t& vocbase, // vocbase
arangodb::velocypack::Slice const& links // link definitions
) {
if (!links.isObject()) {
return arangodb::Result(
TRI_ERROR_BAD_PARAMETER,
std::string("while validating arangosearch link definition, error: "
"definition is not an object"));
return arangodb::Result( // result
TRI_ERROR_BAD_PARAMETER, // code
std::string("while validating arangosearch link definition, error: definition is not an object")
);
}
size_t offset = 0;
arangodb::CollectionNameResolver resolver(vocbase);
for (arangodb::velocypack::ObjectIterator itr(links); itr.valid(); ++itr, ++offset) {
for (arangodb::velocypack::ObjectIterator itr(links); // setup
itr.valid(); // condition
++itr, ++offset // step
) {
auto collectionName = itr.key();
auto linkDefinition = itr.value();
if (!collectionName.isString()) {
return arangodb::Result(
TRI_ERROR_BAD_PARAMETER,
std::string("while validating arangosearch link definition, error: "
"collection at offset ") +
std::to_string(offset) + " is not a string");
return arangodb::Result( // result
TRI_ERROR_BAD_PARAMETER, // code
std::string("while validating arangosearch link definition, error: collection at offset ") + std::to_string(offset) + " is not a string"
);
}
auto collection = resolver.getCollection(collectionName.copyString());
if (!collection) {
return arangodb::Result(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND,
std::string("while validating arangosearch link "
"definition, error: collection '") +
collectionName.copyString() + "' not found");
return arangodb::Result( // result
TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND, // code
std::string("while validating arangosearch link definition, error: collection '") + collectionName.copyString() + "' not found"
);
}
// check link auth as per https://github.com/arangodb/backlog/issues/459
if (arangodb::ExecContext::CURRENT &&
!arangodb::ExecContext::CURRENT->canUseCollection(vocbase.name(),
collection->name(),
arangodb::auth::Level::RO)) {
return arangodb::Result(TRI_ERROR_FORBIDDEN,
std::string("while validating arangosearch link "
"definition, error: collection '") +
collectionName.copyString() +
"' not authorized for read access");
if (arangodb::ExecContext::CURRENT // have context
&& !arangodb::ExecContext::CURRENT->canUseCollection(vocbase.name(), collection->name(), arangodb::auth::Level::RO)) {
return arangodb::Result( // result
TRI_ERROR_FORBIDDEN, // code
std::string("while validating arangosearch link definition, error: collection '") + collectionName.copyString() + "' not authorized for read access"
);
}
IResearchLinkMeta meta;
std::string errorField;
if (!linkDefinition.isNull() && !meta.init(linkDefinition, errorField)) { // for db-server analyzer validation should have already apssed on coordinator
if (!linkDefinition.isNull() && !meta.init(linkDefinition, errorField, &vocbase)) { // for db-server analyzer validation should have already apssed on coordinator
return arangodb::Result( // result
TRI_ERROR_BAD_PARAMETER, // code
errorField.empty()

View File

@ -53,7 +53,7 @@ std::string ensureGuid(std::string&& guid, TRI_voc_cid_t id, TRI_voc_cid_t planI
// id numbers can also not conflict, first character is always 'h'
if (arangodb::ServerState::instance()->isCoordinator() ||
arangodb::ServerState::instance()->isDBServer()) {
TRI_ASSERT(planId);
TRI_ASSERT(planId); // ensured by LogicalDataSource constructor + '_id' != 0
guid.append("c");
guid.append(std::to_string(planId));
guid.push_back('/');
@ -65,9 +65,9 @@ std::string ensureGuid(std::string&& guid, TRI_voc_cid_t id, TRI_voc_cid_t planI
} else if (isSystem) {
guid.append(name);
} else {
TRI_ASSERT(id); // ensured by ensureId(...)
char buf[sizeof(TRI_server_id_t) * 2 + 1];
auto len = TRI_StringUInt64HexInPlace(arangodb::ServerIdFeature::getId(), buf);
TRI_ASSERT(id);
guid.append("h");
guid.append(buf, len);
TRI_ASSERT(guid.size() > 3);
@ -83,14 +83,31 @@ TRI_voc_cid_t ensureId(TRI_voc_cid_t id) {
return id;
}
if (arangodb::ServerState::instance()->isCoordinator() ||
arangodb::ServerState::instance()->isDBServer()) {
auto* ci = arangodb::ClusterInfo::instance();
return ci ? ci->uniqid(1) : 0;
if (!arangodb::ServerState::instance()->isCoordinator() // not coordinator
&& !arangodb::ServerState::instance()->isDBServer() // not db-server
) {
return TRI_NewTickServer();
}
return TRI_NewTickServer();
auto* ci = arangodb::ClusterInfo::instance();
if (!ci) {
THROW_ARANGO_EXCEPTION_MESSAGE( // exception
TRI_ERROR_INTERNAL, // code
"failure to find 'ClusterInfo' instance while generating LogicalDataSource ID" // message
);
}
id = ci->uniqid(1);
if (!id) {
THROW_ARANGO_EXCEPTION_MESSAGE( // exception
TRI_ERROR_INTERNAL, // code
"invalid zero value returned for uniqueid by 'ClusterInfo' while generating LogicalDataSource ID" // message
);
}
return id;
}
bool readIsSystem(arangodb::velocypack::Slice definition) {
@ -211,4 +228,4 @@ Result LogicalDataSource::properties(velocypack::Builder& builder,
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@ -84,7 +84,7 @@ class EmptyAnalyzer: public irs::analysis::analyzer {
private:
irs::attribute_view _attrs;
TestAttribute _attr;
irs::frequency _attr;
};
DEFINE_ANALYZER_TYPE_NAMED(EmptyAnalyzer, "iresearch-document-empty");
@ -177,8 +177,8 @@ struct IResearchDocumentSetup {
// ensure that there will be no exception on 'emplace'
InvalidAnalyzer::returnNullFromMake = false;
analyzers->emplace(result, "iresearch-document-empty", "iresearch-document-empty", "en", irs::flags{ TestAttribute::type() }); // cache analyzer
analyzers->emplace(result, "iresearch-document-invalid", "iresearch-document-invalid", "en", irs::flags{ TestAttribute::type() }); // cache analyzer
analyzers->emplace(result, "iresearch-document-empty", "iresearch-document-empty", "en", irs::flags{ irs::frequency::type() }); // cache analyzer
analyzers->emplace(result, "iresearch-document-invalid", "iresearch-document-invalid", "en", irs::flags{ irs::frequency::type() }); // cache analyzer
// suppress log messages since tests check error conditions
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
@ -710,7 +710,7 @@ SECTION("FieldIterator_traverse_complex_object_ordered_check_value_types") {
auto const expected_analyzer = irs::analysis::analyzers::get("iresearch-document-empty", irs::text_format::json, "en");
auto& analyzer = dynamic_cast<EmptyAnalyzer&>(field.get_tokens());
CHECK(&expected_analyzer->type() == &analyzer.type());
CHECK(irs::flags({TestAttribute::type()}) == field.features());
CHECK(irs::flags({irs::frequency::type()}) == field.features());
}
++it;
@ -1385,15 +1385,15 @@ SECTION("FieldIterator_nullptr_analyzer") {
InvalidAnalyzer::returnNullFromMake = false;
analyzers.start();
analyzers.erase("empty");
analyzers.erase("invalid");
analyzers.remove("empty");
analyzers.remove("invalid");
// ensure that there will be no exception on 'emplace'
InvalidAnalyzer::returnNullFromMake = false;
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
analyzers.emplace(result, "empty", "iresearch-document-empty", "en", irs::flags{TestAttribute::type()});
analyzers.emplace(result, "invalid", "iresearch-document-invalid", "en", irs::flags{TestAttribute::type()});
analyzers.emplace(result, "empty", "iresearch-document-empty", "en", irs::flags{irs::frequency::type()});
analyzers.emplace(result, "invalid", "iresearch-document-invalid", "en", irs::flags{irs::frequency::type()});
}
// last analyzer invalid

View File

@ -35,6 +35,7 @@
#include "Aql/ExecutionPlan.h"
#include "Aql/ExpressionContext.h"
#include "Aql/Query.h"
#include "Cluster/ClusterFeature.h"
#include "GeneralServer/AuthenticationFeature.h"
#include "IResearch/IResearchCommon.h"
#include "IResearch/IResearchFeature.h"
@ -54,6 +55,7 @@
#include "RestServer/ViewTypesFeature.h"
#include "StorageEngine/EngineSelectorFeature.h"
#include "Transaction/StandaloneContext.h"
#include "V8Server/V8DealerFeature.h"
#include "analysis/analyzers.hpp"
#include "analysis/token_streams.hpp"
@ -71,13 +73,12 @@
// --SECTION-- setup / tear-down
// -----------------------------------------------------------------------------
struct IResearchFilterSetup {
struct IResearchFilterBooleanSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::unique_ptr<TRI_vocbase_t> system;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
IResearchFilterSetup(): engine(server), server(nullptr, nullptr) {
IResearchFilterBooleanSetup(): engine(server), server(nullptr, nullptr) {
arangodb::EngineSelectorFeature::ENGINE = &engine;
arangodb::aql::AqlFunctionFeature* functions = nullptr;
@ -86,14 +87,18 @@ struct IResearchFilterSetup {
// suppress INFO {authentication} Authentication is turned on (system only), authentication for unix sockets is turned on
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::WARN);
// suppress log messages since tests check error conditions
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
// setup required application features
features.emplace_back(new arangodb::AuthenticationFeature(server), true);
features.emplace_back(new arangodb::DatabaseFeature(server), false);
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // must be first
arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database
system = irs::memory::make_unique<TRI_vocbase_t>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE);
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // must be before AqlFeature
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
features.emplace_back(new arangodb::ViewTypesFeature(server), false); // required for IResearchFeature
features.emplace_back(new arangodb::AqlFeature(server), true);
features.emplace_back(functions = new arangodb::aql::AqlFunctionFeature(server), true); // required for IResearchAnalyzerFeature
@ -104,6 +109,11 @@ struct IResearchFilterSetup {
features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE
#endif
// required for V8DealerFeature::prepare(), ClusterFeature::prepare() not required
arangodb::application_features::ApplicationServer::server->addFeature(
new arangodb::ClusterFeature(server)
);
for (auto& f : features) {
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
}
@ -112,6 +122,12 @@ struct IResearchFilterSetup {
f.first->prepare();
}
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
for (auto& f : features) {
if (f.second) {
f.first->start();
@ -146,17 +162,20 @@ struct IResearchFilterSetup {
return params[0];
}});
// suppress log messages since tests check error conditions
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::iresearch::IResearchAnalyzerFeature
>();
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
TRI_vocbase_t* vocbase;
dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
analyzers->emplace(result, "testVocbase::test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
}
~IResearchFilterSetup() {
system.reset(); // destroy before reseting the 'ENGINE'
~IResearchFilterBooleanSetup() {
arangodb::AqlFeature(server).stop(); // unset singleton instance
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);
arangodb::application_features::ApplicationServer::server = nullptr;
arangodb::EngineSelectorFeature::ENGINE = nullptr;
// destroy application features
for (auto& f : features) {
@ -170,6 +189,7 @@ struct IResearchFilterSetup {
}
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::DEFAULT);
arangodb::EngineSelectorFeature::ENGINE = nullptr;
}
}; // IResearchFilterSetup
@ -182,7 +202,7 @@ struct IResearchFilterSetup {
////////////////////////////////////////////////////////////////////////////////
TEST_CASE("IResearchFilterBooleanTest", "[iresearch][iresearch-filter]") {
IResearchFilterSetup s;
IResearchFilterBooleanSetup s;
UNUSED(s);
SECTION("Ternary") {
@ -307,7 +327,7 @@ SECTION("UnaryNot") {
auto& root = expected.add<irs::Not>();
root.boost(2.5);
root.filter<irs::And>()
.add<irs::by_term>().field(mangleString("a.b[42].c", "test_analyzer")).term("1");
.add<irs::by_term>().field(mangleString("a.b[42].c", "testVocbase::test_analyzer")).term("1");
assertFilterSuccess("FOR d IN collection FILTER analyzer(BOOST(not (d.a.b[42].c == '1'), 2.5), 'test_analyzer') RETURN d", expected);
assertFilterSuccess("FOR d IN collection FILTER analyzer(boost(not (d['a']['b'][42]['c'] == '1'), 2.5), 'test_analyzer') RETURN d", expected);
@ -349,7 +369,7 @@ SECTION("UnaryNot") {
irs::Or expected;
expected.add<irs::Not>()
.filter<irs::And>()
.add<irs::by_term>().field(mangleString("a.b[23].c", "test_analyzer")).term("42");
.add<irs::by_term>().field(mangleString("a.b[23].c", "testVocbase::test_analyzer")).term("42");
assertFilterSuccess("LET c=41 FOR d IN collection FILTER ANALYZER(not (d.a.b[23].c == TO_STRING(c+1)), 'test_analyzer') RETURN d", expected, &ctx);
assertFilterSuccess("LET c=41 FOR d IN collection FILTER ANALYZER(not (d.a['b'][23].c == TO_STRING(c+1)), 'test_analyzer') RETURN d", expected, &ctx);
@ -1388,9 +1408,9 @@ SECTION("BinaryOr") {
irs::Or expected;
auto& root = expected.add<irs::Or>();
root.add<irs::by_range>()
.field(mangleString("a.b.c", "test_analyzer"))
.field(mangleString("a.b.c", "testVocbase::test_analyzer"))
.include<irs::Bound::MAX>(false).term<irs::Bound::MAX>("1");
root.add<irs::by_term>().field(mangleString("c.b.a", "test_analyzer")).term("2");
root.add<irs::by_term>().field(mangleString("c.b.a", "testVocbase::test_analyzer")).term("2");
assertFilterSuccess("FOR d IN collection FILTER analyzer(d.a.b.c < '1' or d.c.b.a == '2', 'test_analyzer') RETURN d", expected);
assertFilterSuccess("FOR d IN collection FILTER analyzer(d['a']['b']['c'] < '1', 'test_analyzer') or analyzER(d.c.b.a == '2', 'test_analyzer') RETURN d", expected);
@ -1405,9 +1425,9 @@ SECTION("BinaryOr") {
auto& root = expected.add<irs::Or>();
root.boost(0.5);
root.add<irs::by_range>()
.field(mangleString("a.b.c", "test_analyzer"))
.field(mangleString("a.b.c", "testVocbase::test_analyzer"))
.include<irs::Bound::MAX>(false).term<irs::Bound::MAX>("1");
root.add<irs::by_term>().field(mangleString("c.b.a", "test_analyzer")).term("2");
root.add<irs::by_term>().field(mangleString("c.b.a", "testVocbase::test_analyzer")).term("2");
assertFilterSuccess("FOR d IN collection FILTER boost(analyzer(d.a.b.c < '1' or d.c.b.a == '2', 'test_analyzer'), 0.5) RETURN d", expected);
assertFilterSuccess("FOR d IN collection FILTER analyzer(boost(d.a.b.c < '1' or d.c.b.a == '2', 0.5), 'test_analyzer') RETURN d", expected);
@ -1419,7 +1439,7 @@ SECTION("BinaryOr") {
auto& root = expected.add<irs::Or>();
root.boost(0.5);
root.add<irs::by_range>()
.field(mangleString("a.b.c", "test_analyzer"))
.field(mangleString("a.b.c", "testVocbase::test_analyzer"))
.include<irs::Bound::MAX>(false).term<irs::Bound::MAX>("1").boost(2.5);
root.add<irs::by_term>().field(mangleStringIdentity("c.b.a")).term("2");
@ -1447,9 +1467,9 @@ SECTION("BinaryOr") {
auto& root = expected.add<irs::Or>();
root.boost(2.5);
auto& subRoot = root.add<irs::Or>();
subRoot.add<irs::by_term>().field(mangleString("a", "test_analyzer")).term("1").boost(0.5);
subRoot.add<irs::by_term>().field(mangleString("a", "testVocbase::test_analyzer")).term("1").boost(0.5);
subRoot.add<irs::by_term>().field(mangleStringIdentity("a")).term("2");
root.add<irs::Not>().filter<irs::by_term>().field(mangleString("b", "test_analyzer")).term("3").boost(1.5);
root.add<irs::Not>().filter<irs::by_term>().field(mangleString("b", "testVocbase::test_analyzer")).term("3").boost(1.5);
assertFilterSuccess("FOR d IN collection FILTER boost(analyzer(analyzer(boost(d.a == '1', 0.5), 'test_analyzer') or analyzer('2' == d.a, 'identity') or boost(d.b != '3', 1.5), 'test_analyzer'), 2.5) RETURN d", expected);
assertFilterSuccess("FOR d IN collection FILTER boost(analyzer(boost(d['a'] == '1', 0.5), 'test_analyzer') or '2' == d['a'] or boost(analyzer(d.b != '3', 'test_analyzer'), 1.5), 2.5) RETURN d", expected);
@ -1935,7 +1955,7 @@ SECTION("BinaryAnd") {
auto& root = expected.add<irs::And>();
root.boost(0.5);
root.add<irs::by_range>()
.field(mangleString("a.b.c", "test_analyzer"))
.field(mangleString("a.b.c", "testVocbase::test_analyzer"))
.include<irs::Bound::MAX>(false).term<irs::Bound::MAX>("1");
root.add<irs::by_term>().field(mangleStringIdentity("c.b.a")).term("2");
@ -1947,7 +1967,7 @@ SECTION("BinaryAnd") {
irs::Or expected;
auto& root = expected.add<irs::And>();
root.add<irs::by_range>()
.field(mangleString("a.b.c", "test_analyzer"))
.field(mangleString("a.b.c", "testVocbase::test_analyzer"))
.include<irs::Bound::MAX>(false).term<irs::Bound::MAX>("1").boost(0.5);
root.add<irs::by_term>().field(mangleStringIdentity("c.b.a")).term("2").boost(0.5);
@ -1985,7 +2005,7 @@ SECTION("BinaryAnd") {
.include<irs::Bound::MAX>(false).term<irs::Bound::MAX>("1");
root.add<irs::Not>()
.filter<irs::And>()
.add<irs::by_term>().field(mangleString("c.b.a", "test_analyzer")).term("2");
.add<irs::by_term>().field(mangleString("c.b.a", "testVocbase::test_analyzer")).term("2");
assertFilterSuccess("FOR d IN collection FILTER boost(d.a.b.c < '1' and not analyzer(d.c.b.a == '2', 'test_analyzer'), 0.5) RETURN d", expected);
}
@ -1999,7 +2019,7 @@ SECTION("BinaryAnd") {
.include<irs::Bound::MAX>(false).term<irs::Bound::MAX>("1");
root.add<irs::Not>()
.filter<irs::And>()
.add<irs::by_term>().field(mangleString("c.b.a", "test_analyzer")).term("2").boost(0.5);
.add<irs::by_term>().field(mangleString("c.b.a", "testVocbase::test_analyzer")).term("2").boost(0.5);
assertFilterSuccess("FOR d IN collection FILTER d.a.b.c < '1' and not boost(analyzer(d.c.b.a == '2', 'test_analyzer'), 0.5) RETURN d", expected);
}
@ -2795,7 +2815,7 @@ SECTION("BinaryAnd") {
irs::Or expected;
auto& range = expected.add<irs::by_range>();
range.boost(0.5);
range.field(mangleString("a.b.c", "test_analyzer"))
range.field(mangleString("a.b.c", "testVocbase::test_analyzer"))
.include<irs::Bound::MIN>(true).term<irs::Bound::MIN>("15")
.include<irs::Bound::MAX>(false).term<irs::Bound::MAX>("40");
@ -2843,12 +2863,12 @@ SECTION("BinaryAnd") {
irs::Or expected;
auto& root = expected.add<irs::And>();
root.add<irs::by_range>()
.field(mangleString("a.b.c", "test_analyzer"))
.field(mangleString("a.b.c", "testVocbase::test_analyzer"))
.include<irs::Bound::MIN>(true)
.term<irs::Bound::MIN>("15")
.boost(0.5);
root.add<irs::by_range>()
.field(mangleString("a.b.c", "test_analyzer"))
.field(mangleString("a.b.c", "testVocbase::test_analyzer"))
.include<irs::Bound::MAX>(true)
.term<irs::Bound::MAX>("40")
.boost(0.5);
@ -2862,11 +2882,11 @@ SECTION("BinaryAnd") {
auto& root = expected.add<irs::And>();
root.boost(0.5);
root.add<irs::by_range>()
.field(mangleString("a.b.c", "test_analyzer"))
.field(mangleString("a.b.c", "testVocbase::test_analyzer"))
.include<irs::Bound::MIN>(true)
.term<irs::Bound::MIN>("15");
root.add<irs::by_range>()
.field(mangleString("a.b.c", "test_analyzer"))
.field(mangleString("a.b.c", "testVocbase::test_analyzer"))
.include<irs::Bound::MAX>(true)
.term<irs::Bound::MAX>("40");
@ -2923,7 +2943,7 @@ SECTION("BinaryAnd") {
irs::Or expected;
auto& range = expected.add<irs::by_range>();
range.boost(2.f);
range.field(mangleString("a.b.c.e.f", "test_analyzer"))
range.field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer"))
.include<irs::Bound::MIN>(false).term<irs::Bound::MIN>("15")
.include<irs::Bound::MAX>(true).term<irs::Bound::MAX>("40");
@ -3048,7 +3068,7 @@ SECTION("BinaryAnd") {
auto& root = expected.add<irs::And>();
root.boost(1.5);
root.add<irs::by_range>()
.field(mangleString("a.b.c", "test_analyzer"))
.field(mangleString("a.b.c", "testVocbase::test_analyzer"))
.include<irs::Bound::MIN>(true).term<irs::Bound::MIN>("15");
root.add<irs::by_granular_range>()
.field(mangleNumeric("a.b.c"))

View File

@ -35,6 +35,7 @@
#include "Aql/ExecutionPlan.h"
#include "Aql/ExpressionContext.h"
#include "Aql/Query.h"
#include "Cluster/ClusterFeature.h"
#include "GeneralServer/AuthenticationFeature.h"
#include "IResearch/IResearchCommon.h"
#include "IResearch/IResearchFeature.h"
@ -55,6 +56,7 @@
#include "StorageEngine/EngineSelectorFeature.h"
#include "Transaction/Methods.h"
#include "Transaction/StandaloneContext.h"
#include "V8Server/V8DealerFeature.h"
#include "analysis/analyzers.hpp"
#include "analysis/token_streams.hpp"
@ -72,13 +74,12 @@
// --SECTION-- setup / tear-down
// -----------------------------------------------------------------------------
struct IResearchFilterSetup {
struct IResearchFilterCompareSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::unique_ptr<TRI_vocbase_t> system;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
IResearchFilterSetup(): engine(server), server(nullptr, nullptr) {
IResearchFilterCompareSetup(): engine(server), server(nullptr, nullptr) {
arangodb::EngineSelectorFeature::ENGINE = &engine;
arangodb::aql::AqlFunctionFeature* functions = nullptr;
@ -87,14 +88,18 @@ struct IResearchFilterSetup {
// suppress INFO {authentication} Authentication is turned on (system only), authentication for unix sockets is turned on
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::WARN);
// suppress log messages since tests check error conditions
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
// setup required application features
features.emplace_back(new arangodb::AuthenticationFeature(server), true);
features.emplace_back(new arangodb::DatabaseFeature(server), false);
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // must be first
arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database
system = irs::memory::make_unique<TRI_vocbase_t>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE);
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // must be before AqlFeature
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
features.emplace_back(new arangodb::ViewTypesFeature(server), false); // required for IResearchFeature
features.emplace_back(new arangodb::AqlFeature(server), true);
features.emplace_back(functions = new arangodb::aql::AqlFunctionFeature(server), true); // required for IResearchAnalyzerFeature
@ -105,6 +110,11 @@ struct IResearchFilterSetup {
features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE
#endif
// required for V8DealerFeature::prepare(), ClusterFeature::prepare() not required
arangodb::application_features::ApplicationServer::server->addFeature(
new arangodb::ClusterFeature(server)
);
for (auto& f : features) {
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
}
@ -113,6 +123,12 @@ struct IResearchFilterSetup {
f.first->prepare();
}
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
for (auto& f : features) {
if (f.second) {
f.first->start();
@ -147,17 +163,20 @@ struct IResearchFilterSetup {
return params[0];
}});
// suppress log messages since tests check error conditions
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::iresearch::IResearchAnalyzerFeature
>();
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
TRI_vocbase_t* vocbase;
dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
analyzers->emplace(result, "testVocbase::test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
}
~IResearchFilterSetup() {
system.reset(); // destroy before reseting the 'ENGINE'
~IResearchFilterCompareSetup() {
arangodb::AqlFeature(server).stop(); // unset singleton instance
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);
arangodb::application_features::ApplicationServer::server = nullptr;
arangodb::EngineSelectorFeature::ENGINE = nullptr;
// destroy application features
for (auto& f : features) {
@ -171,6 +190,7 @@ struct IResearchFilterSetup {
}
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::DEFAULT);
arangodb::EngineSelectorFeature::ENGINE = nullptr;
}
}; // IResearchFilterSetup
@ -183,7 +203,7 @@ struct IResearchFilterSetup {
////////////////////////////////////////////////////////////////////////////////
TEST_CASE("IResearchFilterCompareTest", "[iresearch][iresearch-filter]") {
IResearchFilterSetup s;
IResearchFilterCompareSetup s;
UNUSED(s);
SECTION("BinaryEq") {
@ -249,7 +269,7 @@ SECTION("BinaryEq") {
// complex attribute with offset, string, analyzer
{
irs::Or expected;
expected.add<irs::by_term>().field(mangleString("a.b[23].c", "test_analyzer")).term("1");
expected.add<irs::by_term>().field(mangleString("a.b[23].c", "testVocbase::test_analyzer")).term("1");
assertFilterSuccess("FOR d IN collection FILTER analyzer(d.a.b[23].c == '1', 'test_analyzer') RETURN d", expected);
assertFilterSuccess("FOR d IN collection FILTER analyzer(d.a['b'][23].c == '1', 'test_analyzer') RETURN d", expected);
@ -262,7 +282,7 @@ SECTION("BinaryEq") {
// complex attribute with offset, string, analyzer, boost
{
irs::Or expected;
expected.add<irs::by_term>().field(mangleString("a.b[23].c", "test_analyzer")).term("1").boost(0.5);
expected.add<irs::by_term>().field(mangleString("a.b[23].c", "testVocbase::test_analyzer")).term("1").boost(0.5);
assertFilterSuccess("FOR d IN collection FILTER analyzer(boost(d.a.b[23].c == '1', 0.5), 'test_analyzer') RETURN d", expected);
assertFilterSuccess("FOR d IN collection FILTER boost(analyzer(d.a['b'][23].c == '1', 'test_analyzer'), 0.5) RETURN d", expected);
@ -863,7 +883,7 @@ SECTION("BinaryNotEq") {
ctx.vars.emplace(var.name, value);
irs::Or expected;
expected.add<irs::Not>().filter<irs::by_term>().field(mangleString("a.b[23].c", "test_analyzer")).term("42").boost(42);
expected.add<irs::Not>().filter<irs::by_term>().field(mangleString("a.b[23].c", "testVocbase::test_analyzer")).term("42").boost(42);
assertFilterSuccess("LET c=41 FOR d IN collection FILTER analyzer(boost(d.a.b[23].c != TO_STRING(c+1), c+1), 'test_analyzer') RETURN d", expected, &ctx);
}
@ -1427,7 +1447,7 @@ SECTION("BinaryGE") {
irs::Or expected;
expected.add<irs::by_range>()
.field(mangleString("a.b[23].c", "test_analyzer"))
.field(mangleString("a.b[23].c", "testVocbase::test_analyzer"))
.include<irs::Bound::MIN>(true).term<irs::Bound::MIN>("42")
.boost(42);
@ -2000,7 +2020,7 @@ SECTION("BinaryGT") {
irs::Or expected;
expected.add<irs::by_range>()
.field(mangleString("a.b[23].c", "test_analyzer"))
.field(mangleString("a.b[23].c", "testVocbase::test_analyzer"))
.include<irs::Bound::MIN>(false).term<irs::Bound::MIN>("42")
.boost(42);
@ -2591,7 +2611,7 @@ SECTION("BinaryLE") {
irs::Or expected;
expected.add<irs::by_range>()
.field(mangleString("a.b[23].c", "test_analyzer"))
.field(mangleString("a.b[23].c", "testVocbase::test_analyzer"))
.include<irs::Bound::MAX>(true).term<irs::Bound::MAX>("42")
.boost(42);
@ -3166,7 +3186,7 @@ SECTION("BinaryLT") {
irs::Or expected;
expected.add<irs::by_range>()
.field(mangleString("a.b[23].c", "test_analyzer"))
.field(mangleString("a.b[23].c", "testVocbase::test_analyzer"))
.include<irs::Bound::MAX>(false).term<irs::Bound::MAX>("42")
.boost(42);

View File

@ -35,6 +35,7 @@
#include "Aql/ExecutionPlan.h"
#include "Aql/ExpressionContext.h"
#include "Aql/Query.h"
#include "Cluster/ClusterFeature.h"
#include "GeneralServer/AuthenticationFeature.h"
#include "IResearch/IResearchCommon.h"
#include "IResearch/IResearchFeature.h"
@ -56,6 +57,7 @@
#include "RestServer/TraverserEngineRegistryFeature.h"
#include "RestServer/ViewTypesFeature.h"
#include "Sharding/ShardingFeature.h"
#include "V8Server/V8DealerFeature.h"
#include "analysis/analyzers.hpp"
#include "analysis/token_streams.hpp"
@ -73,13 +75,12 @@
// --SECTION-- setup / tear-down
// -----------------------------------------------------------------------------
struct IResearchFilterSetup {
struct IResearchFilterFunctionSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::unique_ptr<TRI_vocbase_t> system;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
IResearchFilterSetup(): engine(server), server(nullptr, nullptr) {
IResearchFilterFunctionSetup(): engine(server), server(nullptr, nullptr) {
arangodb::EngineSelectorFeature::ENGINE = &engine;
arangodb::aql::AqlFunctionFeature* functions = nullptr;
@ -88,15 +89,19 @@ struct IResearchFilterSetup {
// suppress INFO {authentication} Authentication is turned on (system only), authentication for unix sockets is turned on
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::WARN);
// suppress log messages since tests check error conditions
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
// setup required application features
features.emplace_back(new arangodb::AuthenticationFeature(server), true);
features.emplace_back(new arangodb::DatabaseFeature(server), false);
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // must be first
features.emplace_back(new arangodb::ShardingFeature(server), false);
arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database
system = irs::memory::make_unique<TRI_vocbase_t>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE);
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // must be before AqlFeature
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
features.emplace_back(new arangodb::ViewTypesFeature(server), false); // required for IResearchFeature
features.emplace_back(new arangodb::AqlFeature(server), true);
features.emplace_back(functions = new arangodb::aql::AqlFunctionFeature(server), true); // required for IResearchAnalyzerFeature
@ -107,6 +112,11 @@ struct IResearchFilterSetup {
features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE
#endif
// required for V8DealerFeature::prepare(), ClusterFeature::prepare() not required
arangodb::application_features::ApplicationServer::server->addFeature(
new arangodb::ClusterFeature(server)
);
for (auto& f : features) {
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
}
@ -115,6 +125,12 @@ struct IResearchFilterSetup {
f.first->prepare();
}
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
for (auto& f : features) {
if (f.second) {
f.first->start();
@ -149,17 +165,20 @@ struct IResearchFilterSetup {
return params[0];
}});
// suppress log messages since tests check error conditions
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::iresearch::IResearchAnalyzerFeature
>();
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
TRI_vocbase_t* vocbase;
dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
analyzers->emplace(result, "testVocbase::test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
}
~IResearchFilterSetup() {
system.reset(); // destroy before reseting the 'ENGINE'
~IResearchFilterFunctionSetup() {
arangodb::AqlFeature(server).stop(); // unset singleton instance
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);
arangodb::application_features::ApplicationServer::server = nullptr;
arangodb::EngineSelectorFeature::ENGINE = nullptr;
// destroy application features
for (auto& f : features) {
@ -173,6 +192,7 @@ struct IResearchFilterSetup {
}
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::DEFAULT);
arangodb::EngineSelectorFeature::ENGINE = nullptr;
}
}; // IResearchFilterSetup
@ -185,7 +205,7 @@ struct IResearchFilterSetup {
////////////////////////////////////////////////////////////////////////////////
TEST_CASE("IResearchFilterFunctionTest", "[iresearch][iresearch-filter]") {
IResearchFilterSetup s;
IResearchFilterFunctionSetup s;
UNUSED(s);
SECTION("AttributeAccess") {
@ -660,7 +680,7 @@ SECTION("Analyzer") {
// simple analyzer
{
irs::Or expected;
expected.add<irs::by_term>().field(mangleString("foo", "test_analyzer")).term("bar");
expected.add<irs::by_term>().field(mangleString("foo", "testVocbase::test_analyzer")).term("bar");
assertFilterSuccess(
"FOR d IN collection FILTER ANALYZER(d.foo == 'bar', 'test_analyzer') RETURN d",
@ -685,7 +705,7 @@ SECTION("Analyzer") {
ctx.vars.emplace("x", arangodb::aql::AqlValue(arangodb::aql::AqlValue("test_")));
irs::Or expected;
expected.add<irs::by_term>().field(mangleString("foo", "test_analyzer")).term("bar");
expected.add<irs::by_term>().field(mangleString("foo", "testVocbase::test_analyzer")).term("bar");
assertFilterSuccess(
"LET x='test_' FOR d IN collection FILTER ANALYZER(d.foo == 'bar', CONCAT(x, 'analyzer')) RETURN d",
@ -1253,7 +1273,7 @@ SECTION("Exists") {
{
irs::Or expected;
auto& exists = expected.add<irs::by_column_existence>();
exists.field(mangleString("name", "test_analyzer")).prefix_match(false);
exists.field(mangleString("name", "testVocbase::test_analyzer")).prefix_match(false);
assertFilterSuccess("FOR d IN myView FILTER analyzer(exists(d.name, 'analyzer'), 'test_analyzer') RETURN d", expected);
assertFilterSuccess("FOR d IN myView FILTER exists(d.name, 'analyzer', 'test_analyzer') RETURN d", expected);
@ -1289,7 +1309,7 @@ SECTION("Exists") {
irs::Or expected;
auto& exists = expected.add<irs::by_column_existence>();
exists.field(mangleString("name", "test_analyzer")).prefix_match(false);
exists.field(mangleString("name", "testVocbase::test_analyzer")).prefix_match(false);
assertFilterSuccess("LET type='analyz' LET anl='test_' FOR d IN myView FILTER analyzer(exists(d.name, CONCAT(type,'er')), CONCAT(anl,'analyzer')) RETURN d", expected, &ctx);
assertFilterSuccess("LET type='analyz' LET anl='test_' FOR d IN myView FILTER analyzer(eXists(d.name, CONCAT(type,'er')), CONCAT(anl,'analyzer')) RETURN d", expected, &ctx);
@ -1301,7 +1321,7 @@ SECTION("Exists") {
{
irs::Or expected;
auto& exists = expected.add<irs::by_column_existence>();
exists.field(mangleString("name", "test_analyzer")).prefix_match(false);
exists.field(mangleString("name", "testVocbase::test_analyzer")).prefix_match(false);
assertFilterSuccess("FOR d IN myView FILTER analyzer(exists(d['name'], 'analyzer'), 'test_analyzer') RETURN d", expected);
assertFilterSuccess("FOR d IN myView FILTER analyzer(eXists(d['name'], 'analyzer'), 'test_analyzer') RETURN d", expected);
@ -1392,7 +1412,7 @@ SECTION("Phrase") {
{
irs::Or expected;
auto& phrase = expected.add<irs::by_phrase>();
phrase.field(mangleString("name", "test_analyzer"));
phrase.field(mangleString("name", "testVocbase::test_analyzer"));
phrase.push_back("q").push_back("u").push_back("i").push_back("c").push_back("k");
assertFilterSuccess("FOR d IN myView FILTER Analyzer(phrase(d.name, 'quick'), 'test_analyzer') RETURN d", expected);
@ -1442,7 +1462,7 @@ SECTION("Phrase") {
irs::Or expected;
auto& phrase = expected.add<irs::by_phrase>();
phrase.field(mangleString("a.b.c.e[4].f[5].g[3].g.a", "test_analyzer"));
phrase.field(mangleString("a.b.c.e[4].f[5].g[3].g.a", "testVocbase::test_analyzer"));
phrase.push_back("q").push_back("u").push_back("i").push_back("c").push_back("k");
assertFilterSuccess("LET a='a' LET c='c' LET offsetInt=4 LET offsetDbl=5.6 FOR d IN collection FILTER analyzer(phrase(d[a].b[c].e[offsetInt].f[offsetDbl].g[_FORWARD_(3)].g[_FORWARD_('a')], 'quick'), 'test_analyzer') RETURN d", expected, &ctx);
@ -1490,7 +1510,7 @@ SECTION("Phrase") {
{
irs::Or expected;
auto& phrase = expected.add<irs::by_phrase>();
phrase.field(mangleString("[42]", "test_analyzer"));
phrase.field(mangleString("[42]", "testVocbase::test_analyzer"));
phrase.push_back("q").push_back("u").push_back("i").push_back("c").push_back("k");
assertFilterSuccess("FOR d IN myView FILTER AnalYZER(phrase(d[42], 'quick'), 'test_analyzer') RETURN d", expected);
@ -1508,7 +1528,7 @@ SECTION("Phrase") {
irs::Or expected;
auto& phrase = expected.add<irs::by_phrase>();
phrase.field(mangleString("name", "test_analyzer"));
phrase.field(mangleString("name", "testVocbase::test_analyzer"));
phrase.push_back("q").push_back("u").push_back("i").push_back("c").push_back("k");
assertFilterSuccess("LET value='qui' LET analyzer='test_' FOR d IN myView FILTER AnAlYzEr(phrase(d.name, CONCAT(value,'ck')), CONCAT(analyzer, 'analyzer')) RETURN d", expected, &ctx);
@ -1560,7 +1580,7 @@ SECTION("Phrase") {
{
irs::Or expected;
auto& phrase = expected.add<irs::by_phrase>();
phrase.field(mangleString("name", "test_analyzer"));
phrase.field(mangleString("name", "testVocbase::test_analyzer"));
phrase.push_back("q").push_back("u").push_back("i").push_back("c").push_back("k");
phrase.push_back("b").push_back("r").push_back("o").push_back("w").push_back("n");
@ -1595,7 +1615,7 @@ SECTION("Phrase") {
{
irs::Or expected;
auto& phrase = expected.add<irs::by_phrase>();
phrase.field(mangleString("obj.name", "test_analyzer"));
phrase.field(mangleString("obj.name", "testVocbase::test_analyzer"));
phrase.push_back("q").push_back("u").push_back("i").push_back("c").push_back("k");
phrase.push_back("b", 5).push_back("r").push_back("o").push_back("w").push_back("n");
@ -1630,7 +1650,7 @@ SECTION("Phrase") {
{
irs::Or expected;
auto& phrase = expected.add<irs::by_phrase>();
phrase.field(mangleString("obj.name", "test_analyzer")).boost(3.0f);
phrase.field(mangleString("obj.name", "testVocbase::test_analyzer")).boost(3.0f);
phrase.push_back("q").push_back("u").push_back("i").push_back("c").push_back("k");
phrase.push_back("b", 5).push_back("r").push_back("o").push_back("w").push_back("n");
@ -1647,7 +1667,7 @@ SECTION("Phrase") {
{
irs::Or expected;
auto& phrase = expected.add<irs::by_phrase>();
phrase.field(mangleString("obj[3].name[1]", "test_analyzer"));
phrase.field(mangleString("obj[3].name[1]", "testVocbase::test_analyzer"));
phrase.push_back("q").push_back("u").push_back("i").push_back("c").push_back("k");
phrase.push_back("b", 5).push_back("r").push_back("o").push_back("w").push_back("n");
@ -1682,7 +1702,7 @@ SECTION("Phrase") {
{
irs::Or expected;
auto& phrase = expected.add<irs::by_phrase>();
phrase.field(mangleString("[5].obj.name[100]", "test_analyzer"));
phrase.field(mangleString("[5].obj.name[100]", "testVocbase::test_analyzer"));
phrase.push_back("q").push_back("u").push_back("i").push_back("c").push_back("k");
phrase.push_back("b", 5).push_back("r").push_back("o").push_back("w").push_back("n");
@ -1717,7 +1737,7 @@ SECTION("Phrase") {
{
irs::Or expected;
auto& phrase = expected.add<irs::by_phrase>();
phrase.field(mangleString("obj.properties.id.name", "test_analyzer"));
phrase.field(mangleString("obj.properties.id.name", "testVocbase::test_analyzer"));
phrase.push_back("q").push_back("u").push_back("i").push_back("c").push_back("k");
phrase.push_back("b", 3).push_back("r").push_back("o").push_back("w").push_back("n");
phrase.push_back("f", 2).push_back("o").push_back("x");
@ -1792,7 +1812,7 @@ SECTION("Phrase") {
{
irs::Or expected;
auto& phrase = expected.add<irs::by_phrase>();
phrase.field(mangleString("obj.properties.id.name", "test_analyzer"));
phrase.field(mangleString("obj.properties.id.name", "testVocbase::test_analyzer"));
phrase.push_back("q").push_back("u").push_back("i").push_back("c").push_back("k");
phrase.push_back("b", 3).push_back("r").push_back("o").push_back("w").push_back("n");
phrase.push_back("f", 2).push_back("o").push_back("x");
@ -2091,7 +2111,7 @@ SECTION("StartsWith") {
{
irs::Or expected;
auto& prefix = expected.add<irs::by_prefix>();
prefix.field(mangleString("obj[400].properties[3].name", "test_analyzer")).term("abc");
prefix.field(mangleString("obj[400].properties[3].name", "testVocbase::test_analyzer")).term("abc");
prefix.scored_terms_limit(128);
assertFilterSuccess("FOR d IN myView FILTER Analyzer(starts_with(d['obj'][400]['properties'][3]['name'], 'abc'), 'test_analyzer') RETURN d", expected);
@ -2204,7 +2224,7 @@ SECTION("StartsWith") {
irs::Or expected;
auto& prefix = expected.add<irs::by_prefix>();
prefix.field(mangleString("obj[400].properties[3].name", "test_analyzer")).term("abc");
prefix.field(mangleString("obj[400].properties[3].name", "testVocbase::test_analyzer")).term("abc");
prefix.scored_terms_limit(6);
assertFilterSuccess("LET scoringLimit=5 LET prefix='ab' LET analyzer='analyzer' FOR d IN myView FILTER analyzer(starts_with(d['obj'][400]['properties'][3]['name'], CONCAT(prefix, 'c'), (scoringLimit + 1.5)), CONCAT('test_',analyzer)) RETURN d", expected, &ctx);

View File

@ -35,6 +35,7 @@
#include "Aql/ExecutionPlan.h"
#include "Aql/ExpressionContext.h"
#include "Aql/Query.h"
#include "Cluster/ClusterFeature.h"
#include "GeneralServer/AuthenticationFeature.h"
#include "IResearch/IResearchCommon.h"
#include "IResearch/IResearchFeature.h"
@ -54,6 +55,7 @@
#include "RestServer/ViewTypesFeature.h"
#include "StorageEngine/EngineSelectorFeature.h"
#include "Transaction/StandaloneContext.h"
#include "V8Server/V8DealerFeature.h"
#include "analysis/analyzers.hpp"
#include "analysis/token_streams.hpp"
@ -71,13 +73,12 @@
// --SECTION-- setup / tear-down
// -----------------------------------------------------------------------------
struct IResearchFilterSetup {
struct IResearchFilterInSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::unique_ptr<TRI_vocbase_t> system;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
IResearchFilterSetup(): engine(server), server(nullptr, nullptr) {
IResearchFilterInSetup(): engine(server), server(nullptr, nullptr) {
arangodb::EngineSelectorFeature::ENGINE = &engine;
arangodb::aql::AqlFunctionFeature* functions = nullptr;
@ -86,14 +87,18 @@ struct IResearchFilterSetup {
// suppress INFO {authentication} Authentication is turned on (system only), authentication for unix sockets is turned on
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::WARN);
// suppress log messages since tests check error conditions
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
// setup required application features
features.emplace_back(new arangodb::AuthenticationFeature(server), true);
features.emplace_back(new arangodb::DatabaseFeature(server), false);
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // must be first
arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database
system = irs::memory::make_unique<TRI_vocbase_t>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE);
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // must be before AqlFeature
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
features.emplace_back(new arangodb::ViewTypesFeature(server), false); // required for IResearchFeature
features.emplace_back(new arangodb::AqlFeature(server), true);
features.emplace_back(functions = new arangodb::aql::AqlFunctionFeature(server), true); // required for IResearchAnalyzerFeature
@ -104,6 +109,11 @@ struct IResearchFilterSetup {
features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE
#endif
// required for V8DealerFeature::prepare(), ClusterFeature::prepare() not required
arangodb::application_features::ApplicationServer::server->addFeature(
new arangodb::ClusterFeature(server)
);
for (auto& f : features) {
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
}
@ -112,6 +122,12 @@ struct IResearchFilterSetup {
f.first->prepare();
}
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
for (auto& f : features) {
if (f.second) {
f.first->start();
@ -146,17 +162,20 @@ struct IResearchFilterSetup {
return params[0];
}});
// suppress log messages since tests check error conditions
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::iresearch::IResearchAnalyzerFeature
>();
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
TRI_vocbase_t* vocbase;
dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
analyzers->emplace(result, "testVocbase::test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
}
~IResearchFilterSetup() {
system.reset(); // destroy before reseting the 'ENGINE'
~IResearchFilterInSetup() {
arangodb::AqlFeature(server).stop(); // unset singleton instance
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);
arangodb::application_features::ApplicationServer::server = nullptr;
arangodb::EngineSelectorFeature::ENGINE = nullptr;
// destroy application features
for (auto& f : features) {
@ -170,6 +189,7 @@ struct IResearchFilterSetup {
}
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::DEFAULT);
arangodb::EngineSelectorFeature::ENGINE = nullptr;
}
}; // IResearchFilterSetup
@ -182,7 +202,7 @@ struct IResearchFilterSetup {
////////////////////////////////////////////////////////////////////////////////
TEST_CASE("IResearchFilterTestIn", "[iresearch][iresearch-filter]") {
IResearchFilterSetup s;
IResearchFilterInSetup s;
UNUSED(s);
SECTION("BinaryIn") {
@ -250,9 +270,9 @@ SECTION("BinaryIn") {
{
irs::Or expected;
auto& root = expected.add<irs::Or>();
root.add<irs::by_term>().field(mangleString("a.b.c[412].e.f", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c[412].e.f", "test_analyzer")).term("2");
root.add<irs::by_term>().field(mangleString("a.b.c[412].e.f", "test_analyzer")).term("3");
root.add<irs::by_term>().field(mangleString("a.b.c[412].e.f", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c[412].e.f", "testVocbase::test_analyzer")).term("2");
root.add<irs::by_term>().field(mangleString("a.b.c[412].e.f", "testVocbase::test_analyzer")).term("3");
assertFilterSuccess("FOR d IN collection FILTER ANALYZER(d.a['b']['c'][412].e.f in ['1','2','3'], 'test_analyzer') RETURN d", expected);
assertFilterSuccess("FOR d IN collection FILTER ANALYZER(d.a.b.c[412].e.f in ['1','2','3'], 'test_analyzer') RETURN d", expected);
@ -276,9 +296,9 @@ SECTION("BinaryIn") {
irs::Or expected;
auto& root = expected.add<irs::Or>();
root.boost(2.5);
root.add<irs::by_term>().field(mangleString("a.b.c[412].e.f", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c[412].e.f", "test_analyzer")).term("2");
root.add<irs::by_term>().field(mangleString("a.b.c[412].e.f", "test_analyzer")).term("3");
root.add<irs::by_term>().field(mangleString("a.b.c[412].e.f", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c[412].e.f", "testVocbase::test_analyzer")).term("2");
root.add<irs::by_term>().field(mangleString("a.b.c[412].e.f", "testVocbase::test_analyzer")).term("3");
assertFilterSuccess("FOR d IN collection FILTER ANALYZER(BOOST(d.a['b']['c'][412].e.f in ['1','2','3'], 2.5), 'test_analyzer') RETURN d", expected);
assertFilterSuccess("FOR d IN collection FILTER BOOST(ANALYZER(d.a.b.c[412].e.f in ['1','2','3'], 'test_analyzer'), 2.5) RETURN d", expected);
@ -308,7 +328,7 @@ SECTION("BinaryIn") {
{
irs::Or expected;
auto& root = expected.add<irs::Or>();
root.add<irs::by_term>().field(mangleString("quick.brown.fox", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("quick.brown.fox", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleNull("quick.brown.fox")).term(irs::null_token_stream::value_null());
root.add<irs::by_term>().field(mangleBool("quick.brown.fox")).term(irs::boolean_token_stream::value_true());
root.add<irs::by_term>().field(mangleBool("quick.brown.fox")).term(irs::boolean_token_stream::value_false());
@ -350,7 +370,7 @@ SECTION("BinaryIn") {
irs::Or expected;
auto& root = expected.add<irs::Or>();
root.boost(1.5);
root.add<irs::by_term>().field(mangleString("quick.brown.fox", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("quick.brown.fox", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleNull("quick.brown.fox")).term(irs::null_token_stream::value_null());
root.add<irs::by_term>().field(mangleBool("quick.brown.fox")).term(irs::boolean_token_stream::value_true());
root.add<irs::by_term>().field(mangleBool("quick.brown.fox")).term(irs::boolean_token_stream::value_false());
@ -491,9 +511,9 @@ SECTION("BinaryIn") {
irs::Or expected;
auto& root = expected.add<irs::Or>();
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleNumeric("a.b.c.e.f")).term(term->value());
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("3");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("3");
assertFilterSuccess("LET x=['1', 2, '3'] FOR d IN collection FILTER ANALYZER(d.a.b.c.e.f in x, 'test_analyzer') RETURN d", expected, &ctx);
}
@ -539,9 +559,9 @@ SECTION("BinaryIn") {
irs::Or expected;
auto& root = expected.add<irs::Or>();
root.boost(1.5);
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleNumeric("a.b.c.e.f")).term(term->value());
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("3");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("3");
assertFilterSuccess("LET x=['1', 2, '3'] FOR d IN collection FILTER ANALYZER(BOOST(d.a.b.c.e.f in x, 1.5), 'test_analyzer') RETURN d", expected, &ctx);
assertFilterSuccess("LET x=['1', 2, '3'] FOR d IN collection FILTER BOOST(ANALYZER(d.a.b.c.e.f in x, 'test_analyzer'), 1.5) RETURN d", expected, &ctx);
@ -1265,8 +1285,8 @@ SECTION("BinaryIn") {
irs::Or expected;
auto& root = expected.add<irs::Or>();
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("str");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("str");
root.add<irs::by_term>().field(mangleBool("a.b.c.e.f")).term(irs::boolean_token_stream::value_false());
root.add<irs::by_term>().field(mangleNumeric("a.b.c.e.f")).term(term->value());
root.add<irs::by_term>().field(mangleNull("a.b.c.e.f")).term(irs::null_token_stream::value_null());
@ -1295,8 +1315,8 @@ SECTION("BinaryIn") {
irs::Or expected;
auto& root = expected.add<irs::Or>();
root.boost(2.5);
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("str");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("str");
root.add<irs::by_term>().field(mangleBool("a.b.c.e.f")).term(irs::boolean_token_stream::value_false());
root.add<irs::by_term>().field(mangleNumeric("a.b.c.e.f")).term(term->value());
root.add<irs::by_term>().field(mangleNull("a.b.c.e.f")).term(irs::null_token_stream::value_null());
@ -2115,9 +2135,9 @@ SECTION("BinaryNotIn") {
{
irs::Or expected;
auto& root = expected.add<irs::Not>().filter<irs::And>();
root.add<irs::by_term>().field(mangleString("a.b.c[323].e.f", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c[323].e.f", "test_analyzer")).term("2");
root.add<irs::by_term>().field(mangleString("a.b.c[323].e.f", "test_analyzer")).term("3");
root.add<irs::by_term>().field(mangleString("a.b.c[323].e.f", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c[323].e.f", "testVocbase::test_analyzer")).term("2");
root.add<irs::by_term>().field(mangleString("a.b.c[323].e.f", "testVocbase::test_analyzer")).term("3");
assertFilterSuccess("FOR d IN collection FILTER analyzer(d.a.b.c[323].e.f not in ['1','2','3'], 'test_analyzer') RETURN d", expected);
assertFilterSuccess("FOR d IN collection FILTER analyzer(d.a['b'].c[323].e.f not in ['1','2','3'], 'test_analyzer') RETURN d", expected);
@ -2129,9 +2149,9 @@ SECTION("BinaryNotIn") {
irs::Or expected;
auto& root = expected.add<irs::Not>().filter<irs::And>();
root.boost(2.5);
root.add<irs::by_term>().field(mangleString("a.b.c[323].e.f", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c[323].e.f", "test_analyzer")).term("2");
root.add<irs::by_term>().field(mangleString("a.b.c[323].e.f", "test_analyzer")).term("3");
root.add<irs::by_term>().field(mangleString("a.b.c[323].e.f", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c[323].e.f", "testVocbase::test_analyzer")).term("2");
root.add<irs::by_term>().field(mangleString("a.b.c[323].e.f", "testVocbase::test_analyzer")).term("3");
assertFilterSuccess("FOR d IN collection FILTER boost(analyzer(d.a.b.c[323].e.f not in ['1','2','3'], 'test_analyzer'), 2.5) RETURN d", expected);
assertFilterSuccess("FOR d IN collection FILTER analyzer(boost(d.a['b'].c[323].e.f not in ['1','2','3'], 2.5), 'test_analyzer') RETURN d", expected);
@ -2163,7 +2183,7 @@ SECTION("BinaryNotIn") {
{
irs::Or expected;
auto& root = expected.add<irs::Not>().filter<irs::And>();
root.add<irs::by_term>().field(mangleString("quick.brown.fox", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("quick.brown.fox", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleNull("quick.brown.fox")).term(irs::null_token_stream::value_null());
root.add<irs::by_term>().field(mangleBool("quick.brown.fox")).term(irs::boolean_token_stream::value_true());
root.add<irs::by_term>().field(mangleBool("quick.brown.fox")).term(irs::boolean_token_stream::value_false());
@ -2184,7 +2204,7 @@ SECTION("BinaryNotIn") {
irs::Or expected;
auto& root = expected.add<irs::Not>().filter<irs::And>();
root.boost(1.5);
root.add<irs::by_term>().field(mangleString("quick.brown.fox", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("quick.brown.fox", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleNull("quick.brown.fox")).term(irs::null_token_stream::value_null());
root.add<irs::by_term>().field(mangleBool("quick.brown.fox")).term(irs::boolean_token_stream::value_true());
root.add<irs::by_term>().field(mangleBool("quick.brown.fox")).term(irs::boolean_token_stream::value_false());
@ -2297,9 +2317,9 @@ SECTION("BinaryNotIn") {
irs::Or expected;
auto& root = expected.add<irs::Not>().filter<irs::And>();
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleNumeric("a.b.c.e.f")).term(term->value());
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("3");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("3");
assertFilterSuccess("LET x=['1', 2, '3'] FOR d IN collection FILTER analyzer(d.a.b.c.e.f not in x, 'test_analyzer') RETURN d", expected, &ctx);
}
@ -2321,9 +2341,9 @@ SECTION("BinaryNotIn") {
irs::Or expected;
auto& root = expected.add<irs::Not>().filter<irs::And>();
root.boost(3.5);
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleNumeric("a.b.c.e.f")).term(term->value());
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("3");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("3");
assertFilterSuccess("LET x=['1', 2, '3'] FOR d IN collection FILTER boost(analyzer(d.a.b.c.e.f not in x, 'test_analyzer'), 3.5) RETURN d", expected, &ctx);
assertFilterSuccess("LET x=['1', 2, '3'] FOR d IN collection FILTER analyzer(boost(d.a.b.c.e.f not in x, 3.5), 'test_analyzer') RETURN d", expected, &ctx);
@ -2373,9 +2393,9 @@ SECTION("BinaryNotIn") {
irs::Or expected;
auto& root = expected.add<irs::Not>().filter<irs::And>();
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleNumeric("a.b.c.e.f")).term(term->value());
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("3");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("3");
// not a constant in array
assertFilterSuccess(
@ -2402,9 +2422,9 @@ SECTION("BinaryNotIn") {
irs::Or expected;
auto& root = expected.add<irs::Not>().filter<irs::And>();
root.boost(1.5);
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1");
root.add<irs::by_term>().field(mangleNumeric("a.b.c.e.f")).term(term->value());
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "test_analyzer")).term("3");
root.add<irs::by_term>().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("3");
// not a constant in array
assertFilterSuccess(

View File

@ -33,6 +33,13 @@
#include "Aql/OptimizerRulesFeature.h"
#include "Basics/VelocyPackHelper.h"
#include "Basics/files.h"
#include "Cluster/ClusterFeature.h"
#if USE_ENTERPRISE
#include "Enterprise/Ldap/LdapFeature.h"
#endif
#include "GeneralServer/AuthenticationFeature.h"
#include "Sharding/ShardingFeature.h"
#include "IResearch/IResearchAnalyzerFeature.h"
#include "IResearch/IResearchCommon.h"
@ -52,6 +59,7 @@
#include "utils/utf8_path.hpp"
#include "velocypack/Iterator.h"
#include "velocypack/Parser.h"
#include "V8Server/V8DealerFeature.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
@ -133,7 +141,6 @@ REGISTER_ANALYZER_JSON(TestAnalyzer, TestAnalyzer::make);
struct IResearchIndexSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::unique_ptr<TRI_vocbase_t> system;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
IResearchIndexSetup(): engine(server), server(nullptr, nullptr) {
@ -151,20 +158,30 @@ struct IResearchIndexSetup {
// setup required application features
features.emplace_back(new arangodb::AqlFeature(server), true); // required for arangodb::aql::Query(...)
features.emplace_back(new arangodb::AuthenticationFeature(server), false); // required for ExecContext in Collections::create(...)
features.emplace_back(new arangodb::DatabaseFeature(server), false); // required for LogicalViewStorageEngine::modify(...)
features.emplace_back(new arangodb::DatabasePathFeature(server), false); // requires for IResearchView::open()
features.emplace_back(new arangodb::ShardingFeature(server), false);
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
features.emplace_back(new arangodb::ViewTypesFeature(server), true); // required by TRI_vocbase_t::createView(...)
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // required by TRI_vocbase_t(...)
arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database
system = irs::memory::make_unique<TRI_vocbase_t>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE);
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // required for AQLFeature
features.emplace_back(new arangodb::aql::AqlFunctionFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::aql::OptimizerRulesFeature(server), true); // required for arangodb::aql::Query::execute(...)
features.emplace_back(new arangodb::iresearch::IResearchAnalyzerFeature(server), true); // required for use of iresearch analyzers
features.emplace_back(new arangodb::iresearch::IResearchFeature(server), true); // required for creating views of type 'iresearch'
#if USE_ENTERPRISE
features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE
#endif
// required for V8DealerFeature::prepare(), ClusterFeature::prepare() not required
arangodb::application_features::ApplicationServer::server->addFeature(
new arangodb::ClusterFeature(server)
);
for (auto& f: features) {
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
}
@ -173,6 +190,12 @@ struct IResearchIndexSetup {
f.first->prepare();
}
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
for (auto& f: features) {
if (f.second) {
f.first->start();
@ -183,20 +206,20 @@ struct IResearchIndexSetup {
arangodb::iresearch::IResearchAnalyzerFeature
>();
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
TRI_vocbase_t* vocbase;
analyzers->emplace(result, "test_A", "TestInsertAnalyzer", "X"); // cache analyzer
analyzers->emplace(result, "test_B", "TestInsertAnalyzer", "Y"); // cache analyzer
dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
analyzers->emplace(result, "testVocbase::test_A", "TestInsertAnalyzer", "X"); // cache analyzer
analyzers->emplace(result, "testVocbase::test_B", "TestInsertAnalyzer", "Y"); // cache analyzer
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
}
~IResearchIndexSetup() {
system.reset(); // destroy before reseting the 'ENGINE'
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);
arangodb::LogTopic::setLogLevel(arangodb::Logger::AQL.name(), arangodb::LogLevel::DEFAULT);
arangodb::application_features::ApplicationServer::server = nullptr;
arangodb::EngineSelectorFeature::ENGINE = nullptr;
// destroy application features
for (auto& f: features) {
@ -210,6 +233,7 @@ struct IResearchIndexSetup {
}
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::DEFAULT);
arangodb::EngineSelectorFeature::ENGINE = nullptr;
}
};

View File

@ -76,7 +76,6 @@
struct IResearchLinkSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::unique_ptr<TRI_vocbase_t> system;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
std::string testFilesystemPath;
@ -102,8 +101,7 @@ struct IResearchLinkSetup {
features.emplace_back(new arangodb::ViewTypesFeature(server), true);
features.emplace_back(new arangodb::QueryRegistryFeature(server), false);
arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database
system = irs::memory::make_unique<TRI_vocbase_t>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE);
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // required for AqlFeature::stop()
features.emplace_back(new arangodb::DatabasePathFeature(server), false);
features.emplace_back(new arangodb::aql::AqlFunctionFeature(server), true); // required for IResearchAnalyzerFeature
@ -129,6 +127,12 @@ struct IResearchLinkSetup {
f.first->prepare();
}
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
for (auto& f : features) {
if (f.second) {
f.first->start();
@ -139,12 +143,6 @@ struct IResearchLinkSetup {
TransactionStateMock::beginTransactionCount = 0;
TransactionStateMock::commitTransactionCount = 0;
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
testFilesystemPath = dbPathFeature->directory();
@ -155,7 +153,6 @@ struct IResearchLinkSetup {
}
~IResearchLinkSetup() {
system.reset(); // destroy before reseting the 'ENGINE'
arangodb::application_features::ApplicationServer::lookupFeature<arangodb::SystemDatabaseFeature>()->unprepare(); // release system database before reseting the 'ENGINE'
TRI_RemoveDirectory(testFilesystemPath.c_str());
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);

View File

@ -76,7 +76,7 @@ struct IResearchLinkHelperSetup {
features.emplace_back(new arangodb::DatabaseFeature(server), false);
features.emplace_back(new arangodb::DatabasePathFeature(server), false); // required for IResearchLink::init(...)
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // required for constructing TRI_vocbase_t
features.emplace_back(new arangodb::SystemDatabaseFeature(server), false); // required by IResearchAnalyzerFeature::storeAnalyzer(...)
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required by IResearchAnalyzerFeature::storeAnalyzer(...)
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // required for AqlFeature::stop()
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
features.emplace_back(new arangodb::ViewTypesFeature(server), false); // required for LogicalView::instantiate(...)
@ -100,22 +100,17 @@ struct IResearchLinkHelperSetup {
f.first->prepare();
}
for (auto& f: features) {
if (f.second) {
f.first->start();
}
}
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::SystemDatabaseFeature
>();
sysDatabase->start(); // load system database after loadDatabases()
for (auto& f: features) {
if (f.second) {
f.first->start();
}
}
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
@ -266,7 +261,7 @@ SECTION("test_normalize") {
arangodb::velocypack::Builder builder;
builder.openObject();
CHECK((false == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
CHECK((true == !analyzers->get("testAnalyzer1")));
CHECK((true == !analyzers->get(arangodb::StaticStrings::SystemDatabase + "::testAnalyzer1")));
}
// analyzer single-server (inRecovery) fail persist in recovery
@ -278,7 +273,7 @@ SECTION("test_normalize") {
arangodb::velocypack::Builder builder;
builder.openObject();
CHECK((false == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
CHECK((true == !analyzers->get("testAnalyzer2")));
CHECK((true == !analyzers->get(arangodb::StaticStrings::SystemDatabase + "::testAnalyzer2")));
}
// analyzer single-server (no engine) fail persist if not storage engine, else SEGFAULT in Methods(...)
@ -290,7 +285,7 @@ SECTION("test_normalize") {
arangodb::velocypack::Builder builder;
builder.openObject();
CHECK((false == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
CHECK((true == !analyzers->get("testAnalyzer3")));
CHECK((true == !analyzers->get(arangodb::StaticStrings::SystemDatabase + "::testAnalyzer3")));
}
// analyzer coordinator
@ -302,7 +297,7 @@ SECTION("test_normalize") {
arangodb::velocypack::Builder builder;
builder.openObject();
CHECK((false == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
CHECK((true == !analyzers->get("testAnalyzer4")));
CHECK((true == !analyzers->get(arangodb::StaticStrings::SystemDatabase + "::testAnalyzer4")));
}
// analyzer coordinator (inRecovery) fail persist in recovery
@ -317,7 +312,7 @@ SECTION("test_normalize") {
arangodb::velocypack::Builder builder;
builder.openObject();
CHECK((false == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
CHECK((true == !analyzers->get("testAnalyzer5")));
CHECK((true == !analyzers->get(arangodb::StaticStrings::SystemDatabase + "::testAnalyzer5")));
}
// analyzer coordinator (no engine)
@ -332,7 +327,7 @@ SECTION("test_normalize") {
arangodb::velocypack::Builder builder;
builder.openObject();
CHECK((false == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
CHECK((true == !analyzers->get("testAnalyzer6")));
CHECK((true == !analyzers->get(arangodb::StaticStrings::SystemDatabase + "::testAnalyzer6")));
}
// analyzer db-server
@ -343,9 +338,9 @@ SECTION("test_normalize") {
auto serverRoleRestore = irs::make_finally([&before]()->void { arangodb::ServerState::instance()->setRole(before); });
arangodb::velocypack::Builder builder;
builder.openObject();
CHECK((true == !analyzers->get("testAnalyzer7")));
CHECK((true == !analyzers->get(arangodb::StaticStrings::SystemDatabase + "::testAnalyzer7")));
CHECK((true == arangodb::iresearch::IResearchLinkHelper::normalize(builder, json->slice(), false, *sysVocbase).ok()));
CHECK((false == !analyzers->get("testAnalyzer7")));
CHECK((false == !analyzers->get(arangodb::StaticStrings::SystemDatabase + "::testAnalyzer7")));
}
// meta has analyzer which is not authorised

View File

@ -156,8 +156,8 @@ struct IResearchLinkMetaSetup {
>();
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
analyzers->emplace(result, "empty", "empty", "en", irs::flags{ TestAttributeZ::type() }); // cache the 'empty' analyzer
analyzers->emplace(result, "testVocbase::empty", "empty", "de", irs::flags{ TestAttributeZ::type() }); // cache the 'empty' analyzer for 'testVocbase'
analyzers->emplace(result, "empty", "empty", "en", irs::flags{ irs::frequency::type() }); // cache the 'empty' analyzer
analyzers->emplace(result, "testVocbase::empty", "empty", "de", irs::flags{ irs::frequency::type() }); // cache the 'empty' analyzer for 'testVocbase'
// suppress log messages since tests check error conditions
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::FATAL);
@ -226,7 +226,7 @@ SECTION("test_inheritDefaults") {
defaults._trackListPositions = true;
defaults._storeValues = arangodb::iresearch::ValueStorage::FULL;
defaults._analyzers.clear();
defaults._analyzers.emplace_back(analyzers.ensure("empty"));
defaults._analyzers.emplace_back(analyzers.get(arangodb::StaticStrings::SystemDatabase + "::empty"));
defaults._fields["abc"]->_fields["xyz"] = arangodb::iresearch::IResearchLinkMeta();
auto json = arangodb::velocypack::Parser::fromJson("{}");
@ -263,7 +263,7 @@ SECTION("test_inheritDefaults") {
CHECK(1U == meta._analyzers.size());
CHECK((*(meta._analyzers.begin())));
CHECK(("empty" == (*(meta._analyzers.begin()))->name()));
CHECK((arangodb::StaticStrings::SystemDatabase + "::empty" == (*(meta._analyzers.begin()))->name()));
CHECK((irs::flags() == (*(meta._analyzers.begin()))->features()));
CHECK(false == !meta._analyzers.begin()->get());
}
@ -363,7 +363,7 @@ SECTION("test_readCustomizedValues") {
CHECK(1U == actual._analyzers.size());
CHECK((*(actual._analyzers.begin())));
CHECK(("empty" == (*(actual._analyzers.begin()))->name()));
CHECK((irs::flags({TestAttributeZ::type()}) == (*(actual._analyzers.begin()))->features()));
CHECK((irs::flags({irs::frequency::type()}) == (*(actual._analyzers.begin()))->features()));
CHECK(false == !actual._analyzers.begin()->get());
} else if ("some" == fieldOverride.key()) {
CHECK(true == actual._fields.empty()); // not inherited
@ -374,7 +374,7 @@ SECTION("test_readCustomizedValues") {
auto itr = actual._analyzers.begin();
CHECK((*itr));
CHECK(("empty" == (*itr)->name()));
CHECK((irs::flags({TestAttributeZ::type()}) == (*itr)->features()));
CHECK((irs::flags({irs::frequency::type()}) == (*itr)->features()));
CHECK(false == !itr->get());
++itr;
CHECK((*itr));
@ -389,7 +389,7 @@ SECTION("test_readCustomizedValues") {
auto itr = actual._analyzers.begin();
CHECK((*itr));
CHECK(("empty" == (*itr)->name()));
CHECK((irs::flags({TestAttributeZ::type()}) == (*itr)->features()));
CHECK((irs::flags({irs::frequency::type()}) == (*itr)->features()));
CHECK(false == !itr->get());
++itr;
CHECK((*itr));
@ -408,7 +408,7 @@ SECTION("test_readCustomizedValues") {
auto itr = meta._analyzers.begin();
CHECK((*itr));
CHECK(("empty" == (*itr)->name()));
CHECK((irs::flags({TestAttributeZ::type()}) == (*itr)->features()));
CHECK((irs::flags({irs::frequency::type()}) == (*itr)->features()));
CHECK(false == !itr->get());
++itr;
CHECK((*itr));
@ -455,10 +455,8 @@ SECTION("test_readCustomizedValues") {
CHECK((arangodb::iresearch::ValueStorage::FULL == actual._storeValues));
CHECK((1U == actual._analyzers.size()));
CHECK((*(actual._analyzers.begin())));
/* FIXME TODO uncomment once emplace(...) and all tests are updated
CHECK(("testVocbase::empty" == (*(actual._analyzers.begin()))->name()));
*/
CHECK((irs::flags({TestAttributeZ::type()}) == (*(actual._analyzers.begin()))->features()));
CHECK((irs::flags({irs::frequency::type()}) == (*(actual._analyzers.begin()))->features()));
CHECK((false == !actual._analyzers.begin()->get()));
} else if ("some" == fieldOverride.key()) {
CHECK((true == actual._fields.empty())); // not inherited
@ -468,10 +466,8 @@ SECTION("test_readCustomizedValues") {
CHECK((2U == actual._analyzers.size()));
auto itr = actual._analyzers.begin();
CHECK((*itr));
/* FIXME TODO uncomment once emplace(...) and all tests are updated
CHECK(("testVocbase::empty" == (*itr)->name()));
*/
CHECK((irs::flags({TestAttributeZ::type()}) == (*itr)->features()));
CHECK((irs::flags({irs::frequency::type()}) == (*itr)->features()));
CHECK((false == !itr->get()));
++itr;
CHECK((*itr));
@ -485,10 +481,8 @@ SECTION("test_readCustomizedValues") {
CHECK((arangodb::iresearch::ValueStorage::FULL == actual._storeValues));
auto itr = actual._analyzers.begin();
CHECK((*itr));
/* FIXME TODO uncomment once emplace(...) and all tests are updated
CHECK(("testVocbase::empty" == (*itr)->name()));
*/
CHECK((irs::flags({TestAttributeZ::type()}) == (*itr)->features()));
CHECK((irs::flags({irs::frequency::type()}) == (*itr)->features()));
CHECK((false == !itr->get()));
++itr;
CHECK((*itr));
@ -506,10 +500,8 @@ SECTION("test_readCustomizedValues") {
CHECK((arangodb::iresearch::ValueStorage::FULL == meta._storeValues));
auto itr = meta._analyzers.begin();
CHECK((*itr));
/* FIXME TODO uncomment once emplace(...) and all tests are updated
CHECK(("testVocbase::empty" == (*itr)->name()));
*/
CHECK((irs::flags({TestAttributeZ::type()}) == (*itr)->features()));
CHECK((irs::flags({irs::frequency::type()}) == (*itr)->features()));
CHECK((false == !itr->get()));
++itr;
CHECK((*itr));
@ -656,7 +648,7 @@ SECTION("test_writeCustomizedValues") {
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult emplaceResult;
arangodb::iresearch::IResearchLinkMeta meta;
analyzers.emplace(emplaceResult, "empty", "empty", "en", { irs::attribute::type_id::get("position") });
analyzers.emplace(emplaceResult, "empty", "empty", "en", { irs::frequency::type() });
meta._includeAllFields = true;
meta._trackListPositions = true;
@ -879,7 +871,7 @@ SECTION("test_writeCustomizedValues") {
&& tmpSlice.at(0).get("type").isString() && std::string("empty") == tmpSlice.at(0).get("type").copyString()
&& tmpSlice.at(0).get("properties").isString() && std::string("en") == tmpSlice.at(0).get("properties").copyString()
&& tmpSlice.at(0).get("features").isArray() && 1 == tmpSlice.at(0).get("features").length()
&& tmpSlice.at(0).get("features").at(0).isString() && std::string("position") == tmpSlice.at(0).get("features").at(0).copyString()
&& tmpSlice.at(0).get("features").at(0).isString() && std::string("frequency") == tmpSlice.at(0).get("features").at(0).copyString()
));
} else if ("some" == fieldOverride.copyString()) {
CHECK((2U == sliceOverride.length()));
@ -1108,7 +1100,7 @@ SECTION("test_writeCustomizedValues") {
&& tmpSlice.at(0).get("type").isString() && std::string("empty") == tmpSlice.at(0).get("type").copyString()
&& tmpSlice.at(0).get("properties").isString() && std::string("en") == tmpSlice.at(0).get("properties").copyString()
&& tmpSlice.at(0).get("features").isArray() && 1 == tmpSlice.at(0).get("features").length()
&& tmpSlice.at(0).get("features").at(0).isString() && std::string("position") == tmpSlice.at(0).get("features").at(0).copyString()
&& tmpSlice.at(0).get("features").at(0).isString() && std::string("frequency") == tmpSlice.at(0).get("features").at(0).copyString()
));
} else if ("some" == fieldOverride.copyString()) {
CHECK((2U == sliceOverride.length()));
@ -1389,7 +1381,7 @@ SECTION("test_readAnalyzerDefinitions") {
CHECK((std::string("empty") == meta._analyzers[0]->type()));
CHECK((std::string("en") == meta._analyzers[0]->properties()));
CHECK((1 == meta._analyzers[0]->features().size()));
CHECK((true == meta._analyzers[0]->features().check(TestAttributeZ::type())));
CHECK((true == meta._analyzers[0]->features().check(irs::frequency::type())));
}
// existing analyzer (name only) inRecovery
@ -1408,13 +1400,13 @@ SECTION("test_readAnalyzerDefinitions") {
CHECK((std::string("empty") == meta._analyzers[0]->type()));
CHECK((std::string("en") == meta._analyzers[0]->properties()));
CHECK((1 == meta._analyzers[0]->features().size()));
CHECK((true == meta._analyzers[0]->features().check(TestAttributeZ::type())));
CHECK((true == meta._analyzers[0]->features().check(irs::frequency::type())));
}
// existing analyzer (full) analyzer creation not allowed (passs)
{
auto json = arangodb::velocypack::Parser::fromJson("{ \
\"analyzers\": [ { \"name\": \"empty\", \"type\": \"empty\", \"properties\": \"en\", \"features\": [ \"TestAttributeZ\" ] } ] \
\"analyzers\": [ { \"name\": \"empty\", \"type\": \"empty\", \"properties\": \"en\", \"features\": [ \"frequency\" ] } ] \
}");
arangodb::iresearch::IResearchLinkMeta meta;
std::string errorField;
@ -1424,13 +1416,13 @@ SECTION("test_readAnalyzerDefinitions") {
CHECK((std::string("empty") == meta._analyzers[0]->type()));
CHECK((std::string("en") == meta._analyzers[0]->properties()));
CHECK((1 == meta._analyzers[0]->features().size()));
CHECK((true == meta._analyzers[0]->features().check(TestAttributeZ::type())));
CHECK((true == meta._analyzers[0]->features().check(irs::frequency::type())));
}
// existing analyzer (full)
{
auto json = arangodb::velocypack::Parser::fromJson("{ \
\"analyzers\": [ { \"name\": \"empty\", \"type\": \"empty\", \"properties\": \"en\", \"features\": [ \"TestAttributeZ\" ] } ] \
\"analyzers\": [ { \"name\": \"empty\", \"type\": \"empty\", \"properties\": \"en\", \"features\": [ \"frequency\" ] } ] \
}");
arangodb::iresearch::IResearchLinkMeta meta;
std::string errorField;
@ -1440,13 +1432,13 @@ SECTION("test_readAnalyzerDefinitions") {
CHECK((std::string("empty") == meta._analyzers[0]->type()));
CHECK((std::string("en") == meta._analyzers[0]->properties()));
CHECK((1 == meta._analyzers[0]->features().size()));
CHECK((true == meta._analyzers[0]->features().check(TestAttributeZ::type())));
CHECK((true == meta._analyzers[0]->features().check(irs::frequency::type())));
}
// existing analyzer (full) inRecovery
{
auto json = arangodb::velocypack::Parser::fromJson("{ \
\"analyzers\": [ { \"name\": \"empty\", \"type\": \"empty\", \"properties\": \"en\", \"features\": [ \"TestAttributeZ\" ] } ] \
\"analyzers\": [ { \"name\": \"empty\", \"type\": \"empty\", \"properties\": \"en\", \"features\": [ \"frequency\" ] } ] \
}");
auto before = StorageEngineMock::inRecoveryResult;
StorageEngineMock::inRecoveryResult = true;
@ -1459,13 +1451,13 @@ SECTION("test_readAnalyzerDefinitions") {
CHECK((std::string("empty") == meta._analyzers[0]->type()));
CHECK((std::string("en") == meta._analyzers[0]->properties()));
CHECK((1 == meta._analyzers[0]->features().size()));
CHECK((true == meta._analyzers[0]->features().check(TestAttributeZ::type())));
CHECK((true == meta._analyzers[0]->features().check(irs::frequency::type())));
}
// existing analyzer (definition mismatch)
{
auto json = arangodb::velocypack::Parser::fromJson("{ \
\"analyzers\": [ { \"name\": \"empty\", \"type\": \"empty\", \"properties\": \"ru\", \"features\": [ \"TestAttributeZ\" ] } ] \
\"analyzers\": [ { \"name\": \"empty\", \"type\": \"empty\", \"properties\": \"ru\", \"features\": [ \"frequency\" ] } ] \
}");
arangodb::iresearch::IResearchLinkMeta meta;
std::string errorField;
@ -1476,7 +1468,7 @@ SECTION("test_readAnalyzerDefinitions") {
// existing analyzer (definition mismatch) inRecovery
{
auto json = arangodb::velocypack::Parser::fromJson("{ \
\"analyzers\": [ { \"name\": \"empty\", \"type\": \"empty\", \"properties\": \"ru\", \"features\": [ \"TestAttributeZ\" ] } ] \
\"analyzers\": [ { \"name\": \"empty\", \"type\": \"empty\", \"properties\": \"ru\", \"features\": [ \"frequency\" ] } ] \
}");
auto before = StorageEngineMock::inRecoveryResult;
StorageEngineMock::inRecoveryResult = true;

View File

@ -35,6 +35,7 @@
#include "Aql/OptimizerRulesFeature.h"
#include "Aql/Query.h"
#include "Basics/VelocyPackHelper.h"
#include "Cluster/ClusterFeature.h"
#include "GeneralServer/AuthenticationFeature.h"
#include "IResearch/IResearchCommon.h"
#include "IResearch/IResearchFeature.h"
@ -53,6 +54,7 @@
#include "RestServer/TraverserEngineRegistryFeature.h"
#include "Sharding/ShardingFeature.h"
#include "V8/v8-globals.h"
#include "V8Server/V8DealerFeature.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
@ -78,7 +80,6 @@ namespace {
struct IResearchQueryAndSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::unique_ptr<TRI_vocbase_t> system;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
IResearchQueryAndSetup(): engine(server), server(nullptr, nullptr) {
@ -96,6 +97,7 @@ struct IResearchQueryAndSetup {
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
// setup required application features
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
features.emplace_back(new arangodb::ViewTypesFeature(server), true);
features.emplace_back(new arangodb::AuthenticationFeature(server), true);
features.emplace_back(new arangodb::DatabasePathFeature(server), false);
@ -103,8 +105,7 @@ struct IResearchQueryAndSetup {
features.emplace_back(new arangodb::ShardingFeature(server), false); //
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // must be first
arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database
system = irs::memory::make_unique<TRI_vocbase_t>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE);
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // must be before AqlFeature
features.emplace_back(new arangodb::AqlFeature(server), true);
features.emplace_back(new arangodb::aql::OptimizerRulesFeature(server), true);
@ -116,6 +117,11 @@ struct IResearchQueryAndSetup {
features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE
#endif
// required for V8DealerFeature::prepare(), ClusterFeature::prepare() not required
arangodb::application_features::ApplicationServer::server->addFeature(
new arangodb::ClusterFeature(server)
);
for (auto& f : features) {
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
}
@ -124,6 +130,12 @@ struct IResearchQueryAndSetup {
f.first->prepare();
}
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
for (auto& f : features) {
if (f.second) {
f.first->start();
@ -134,22 +146,22 @@ struct IResearchQueryAndSetup {
arangodb::iresearch::IResearchAnalyzerFeature
>();
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
TRI_vocbase_t* vocbase;
analyzers->emplace(result, "test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
analyzers->emplace(result, "test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
analyzers->emplace(result, "testVocbase::test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
analyzers->emplace(result, "testVocbase::test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
}
~IResearchQueryAndSetup() {
system.reset(); // destroy before reseting the 'ENGINE'
arangodb::AqlFeature(server).stop(); // unset singleton instance
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);
arangodb::LogTopic::setLogLevel(arangodb::Logger::FIXME.name(), arangodb::LogLevel::DEFAULT);
arangodb::LogTopic::setLogLevel(arangodb::Logger::AQL.name(), arangodb::LogLevel::DEFAULT);
arangodb::application_features::ApplicationServer::server = nullptr;
arangodb::EngineSelectorFeature::ENGINE = nullptr;
// destroy application features
for (auto& f : features) {
@ -163,6 +175,7 @@ struct IResearchQueryAndSetup {
}
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::DEFAULT);
arangodb::EngineSelectorFeature::ENGINE = nullptr;
}
}; // IResearchQuerySetup

View File

@ -30,7 +30,9 @@
#include "Enterprise/Ldap/LdapFeature.h"
#endif
#include "Cluster/ClusterFeature.h"
#include "V8/v8-globals.h"
#include "V8Server/V8DealerFeature.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "Transaction/StandaloneContext.h"
@ -78,7 +80,6 @@ namespace {
struct IResearchQueryComplexBooleanSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::unique_ptr<TRI_vocbase_t> system;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
IResearchQueryComplexBooleanSetup(): engine(server), server(nullptr, nullptr) {
@ -96,6 +97,7 @@ struct IResearchQueryComplexBooleanSetup {
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
// setup required application features
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
features.emplace_back(new arangodb::ViewTypesFeature(server), true);
features.emplace_back(new arangodb::AuthenticationFeature(server), true);
features.emplace_back(new arangodb::DatabasePathFeature(server), false);
@ -103,8 +105,7 @@ struct IResearchQueryComplexBooleanSetup {
features.emplace_back(new arangodb::ShardingFeature(server), false); //
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // must be first
arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database
system = irs::memory::make_unique<TRI_vocbase_t>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE);
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // must be before AqlFeature
features.emplace_back(new arangodb::AqlFeature(server), true);
features.emplace_back(new arangodb::aql::OptimizerRulesFeature(server), true);
@ -116,6 +117,11 @@ struct IResearchQueryComplexBooleanSetup {
features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE
#endif
// required for V8DealerFeature::prepare(), ClusterFeature::prepare() not required
arangodb::application_features::ApplicationServer::server->addFeature(
new arangodb::ClusterFeature(server)
);
for (auto& f : features) {
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
}
@ -124,6 +130,12 @@ struct IResearchQueryComplexBooleanSetup {
f.first->prepare();
}
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
for (auto& f : features) {
if (f.second) {
f.first->start();
@ -134,10 +146,12 @@ struct IResearchQueryComplexBooleanSetup {
arangodb::iresearch::IResearchAnalyzerFeature
>();
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
TRI_vocbase_t* vocbase;
dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
analyzers->emplace(
result,
"test_analyzer",
"testVocbase::test_analyzer",
"TestAnalyzer",
"abc",
irs::flags{ irs::frequency::type(), irs::position::type() } // required for PHRASE
@ -145,7 +159,7 @@ struct IResearchQueryComplexBooleanSetup {
analyzers->emplace(
result,
"test_csv_analyzer",
"testVocbase::test_csv_analyzer",
"TestDelimAnalyzer",
","
); // cache analyzer
@ -155,13 +169,11 @@ struct IResearchQueryComplexBooleanSetup {
}
~IResearchQueryComplexBooleanSetup() {
system.reset(); // destroy before reseting the 'ENGINE'
arangodb::AqlFeature(server).stop(); // unset singleton instance
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);
arangodb::LogTopic::setLogLevel(arangodb::Logger::FIXME.name(), arangodb::LogLevel::DEFAULT);
arangodb::LogTopic::setLogLevel(arangodb::Logger::AQL.name(), arangodb::LogLevel::DEFAULT);
arangodb::application_features::ApplicationServer::server = nullptr;
arangodb::EngineSelectorFeature::ENGINE = nullptr;
// destroy application features
for (auto& f : features) {
@ -175,6 +187,7 @@ struct IResearchQueryComplexBooleanSetup {
}
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::DEFAULT);
arangodb::EngineSelectorFeature::ENGINE = nullptr;
}
}; // IResearchQuerySetup

View File

@ -82,7 +82,6 @@ namespace {
struct IResearchQueryExistsSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::unique_ptr<TRI_vocbase_t> system;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
IResearchQueryExistsSetup(): engine(server), server(nullptr, nullptr) {
@ -109,8 +108,7 @@ struct IResearchQueryExistsSetup {
features.emplace_back(new arangodb::ShardingFeature(server), false);
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // must be first
arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database
system = irs::memory::make_unique<TRI_vocbase_t>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE);
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // must be before AqlFeature
features.emplace_back(new arangodb::AqlFeature(server), true);
features.emplace_back(new arangodb::aql::OptimizerRulesFeature(server), true);
@ -147,12 +145,20 @@ struct IResearchQueryExistsSetup {
}
}
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::iresearch::IResearchAnalyzerFeature
>();
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
TRI_vocbase_t* vocbase;
dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
analyzers->emplace(result, "testVocbase::text_en", "text", "{ \"locale\": \"en.UTF-8\", \"ignored_words\": [ ] }", { irs::frequency::type(), irs::norm::type(), irs::position::type() }); // cache analyzer
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
}
~IResearchQueryExistsSetup() {
system.reset(); // destroy before reseting the 'ENGINE'
arangodb::AqlFeature(server).stop(); // unset singleton instance
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);
arangodb::LogTopic::setLogLevel(arangodb::Logger::FIXME.name(), arangodb::LogLevel::DEFAULT);
@ -189,21 +195,7 @@ TEST_CASE("IResearchQueryTestExists", "[iresearch][iresearch-query]") {
IResearchQueryExistsSetup s;
UNUSED(s);
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::iresearch::IResearchAnalyzerFeature
>();
REQUIRE((nullptr != analyzers));
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
TRI_vocbase_t* vocbasePtr;
REQUIRE((TRI_ERROR_NO_ERROR == dbFeature->createDatabase(1, "testVocbase", vocbasePtr))); // required for IResearchAnalyzerFeature::emplace(...)
REQUIRE((nullptr != vocbasePtr));
auto& vocbase = *vocbasePtr;
//TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
REQUIRE((analyzers->emplace(result, "testVocbase::text_en", "text", "{ \"locale\": \"en.UTF-8\", \"ignored_words\": [ ] }", { irs::frequency::type(), irs::norm::type(), irs::position::type() }).ok()));
REQUIRE((false == !result.first));
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase");
std::vector<arangodb::velocypack::Builder> insertedDocs;
arangodb::LogicalView* view;

View File

@ -34,7 +34,9 @@
#include "Aql/ExpressionContext.h"
#include "Aql/OptimizerRulesFeature.h"
#include "Aql/Query.h"
#include "Cluster/ClusterFeature.h"
#include "V8/v8-globals.h"
#include "V8Server/V8DealerFeature.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "Transaction/Methods.h"
@ -85,7 +87,6 @@ namespace {
struct IResearchQueryJoinSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::unique_ptr<TRI_vocbase_t> system;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
IResearchQueryJoinSetup(): engine(server), server(nullptr, nullptr) {
@ -104,6 +105,7 @@ struct IResearchQueryJoinSetup {
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
// setup required application features
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
features.emplace_back(new arangodb::ViewTypesFeature(server), true);
features.emplace_back(new arangodb::AuthenticationFeature(server), true);
features.emplace_back(new arangodb::DatabasePathFeature(server), false);
@ -111,8 +113,7 @@ struct IResearchQueryJoinSetup {
features.emplace_back(new arangodb::ShardingFeature(server), false);
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // must be first
arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database
system = irs::memory::make_unique<TRI_vocbase_t>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE);
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // must be before AqlFeature
features.emplace_back(new arangodb::AqlFeature(server), true);
features.emplace_back(new arangodb::aql::OptimizerRulesFeature(server), true);
@ -124,6 +125,11 @@ struct IResearchQueryJoinSetup {
features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE
#endif
// required for V8DealerFeature::prepare(), ClusterFeature::prepare() not required
arangodb::application_features::ApplicationServer::server->addFeature(
new arangodb::ClusterFeature(server)
);
for (auto& f : features) {
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
}
@ -132,6 +138,12 @@ struct IResearchQueryJoinSetup {
f.first->prepare();
}
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
for (auto& f : features) {
if (f.second) {
f.first->start();
@ -181,22 +193,22 @@ struct IResearchQueryJoinSetup {
arangodb::iresearch::IResearchAnalyzerFeature
>();
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
TRI_vocbase_t* vocbase;
analyzers->emplace(result, "test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
analyzers->emplace(result, "test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
analyzers->emplace(result, "testVocbase::test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
analyzers->emplace(result, "testVocbase::test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
}
~IResearchQueryJoinSetup() {
system.reset(); // destroy before reseting the 'ENGINE'
arangodb::AqlFeature(server).stop(); // unset singleton instance
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);
arangodb::LogTopic::setLogLevel(arangodb::Logger::FIXME.name(), arangodb::LogLevel::DEFAULT);
arangodb::LogTopic::setLogLevel(arangodb::Logger::AQL.name(), arangodb::LogLevel::DEFAULT);
arangodb::application_features::ApplicationServer::server = nullptr;
arangodb::EngineSelectorFeature::ENGINE = nullptr;
// destroy application features
for (auto& f : features) {
@ -210,6 +222,7 @@ struct IResearchQueryJoinSetup {
}
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::DEFAULT);
arangodb::EngineSelectorFeature::ENGINE = nullptr;
}
}; // IResearchQuerySetup

View File

@ -30,7 +30,9 @@
#include "Enterprise/Ldap/LdapFeature.h"
#endif
#include "Cluster/ClusterFeature.h"
#include "V8/v8-globals.h"
#include "V8Server/V8DealerFeature.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "VocBase/ManagedDocumentResult.h"
@ -79,7 +81,6 @@ namespace {
struct IResearchQueryOrSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::unique_ptr<TRI_vocbase_t> system;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
IResearchQueryOrSetup(): engine(server), server(nullptr, nullptr) {
@ -97,6 +98,7 @@ struct IResearchQueryOrSetup {
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
// setup required application features
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
features.emplace_back(new arangodb::ViewTypesFeature(server), true);
features.emplace_back(new arangodb::AuthenticationFeature(server), true);
features.emplace_back(new arangodb::DatabasePathFeature(server), false);
@ -104,8 +106,7 @@ struct IResearchQueryOrSetup {
features.emplace_back(new arangodb::ShardingFeature(server), false);
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // must be first
arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database
system = irs::memory::make_unique<TRI_vocbase_t>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE);
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // must be before AqlFeature
features.emplace_back(new arangodb::AqlFeature(server), true);
features.emplace_back(new arangodb::aql::OptimizerRulesFeature(server), true);
@ -117,6 +118,11 @@ struct IResearchQueryOrSetup {
features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE
#endif
// required for V8DealerFeature::prepare(), ClusterFeature::prepare() not required
arangodb::application_features::ApplicationServer::server->addFeature(
new arangodb::ClusterFeature(server)
);
for (auto& f : features) {
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
}
@ -125,6 +131,12 @@ struct IResearchQueryOrSetup {
f.first->prepare();
}
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
for (auto& f : features) {
if (f.second) {
f.first->start();
@ -135,10 +147,12 @@ struct IResearchQueryOrSetup {
arangodb::iresearch::IResearchAnalyzerFeature
>();
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
TRI_vocbase_t* vocbase;
dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
analyzers->emplace(
result,
"test_analyzer",
"testVocbase::test_analyzer",
"TestAnalyzer",
"abc",
irs::flags{ irs::frequency::type(), irs::position::type() } // required for PHRASE
@ -146,7 +160,7 @@ struct IResearchQueryOrSetup {
analyzers->emplace(
result,
"test_csv_analyzer",
"testVocbase::test_csv_analyzer",
"TestDelimAnalyzer",
","
); // cache analyzer
@ -156,13 +170,11 @@ struct IResearchQueryOrSetup {
}
~IResearchQueryOrSetup() {
system.reset(); // destroy before reseting the 'ENGINE'
arangodb::AqlFeature(server).stop(); // unset singleton instance
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);
arangodb::LogTopic::setLogLevel(arangodb::Logger::FIXME.name(), arangodb::LogLevel::DEFAULT);
arangodb::LogTopic::setLogLevel(arangodb::Logger::AQL.name(), arangodb::LogLevel::DEFAULT);
arangodb::application_features::ApplicationServer::server = nullptr;
arangodb::EngineSelectorFeature::ENGINE = nullptr;
// destroy application features
for (auto& f : features) {
@ -176,6 +188,7 @@ struct IResearchQueryOrSetup {
}
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::DEFAULT);
arangodb::EngineSelectorFeature::ENGINE = nullptr;
}
}; // IResearchQuerySetup

View File

@ -30,7 +30,9 @@
#include "Enterprise/Ldap/LdapFeature.h"
#endif
#include "Cluster/ClusterFeature.h"
#include "V8/v8-globals.h"
#include "V8Server/V8DealerFeature.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "Transaction/StandaloneContext.h"
@ -78,7 +80,6 @@ namespace {
struct IResearchQueryPhraseSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::unique_ptr<TRI_vocbase_t> system;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
IResearchQueryPhraseSetup(): engine(server), server(nullptr, nullptr) {
@ -96,6 +97,7 @@ struct IResearchQueryPhraseSetup {
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
// setup required application features
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
features.emplace_back(new arangodb::ViewTypesFeature(server), true);
features.emplace_back(new arangodb::AuthenticationFeature(server), true);
features.emplace_back(new arangodb::DatabasePathFeature(server), false);
@ -103,8 +105,7 @@ struct IResearchQueryPhraseSetup {
features.emplace_back(new arangodb::ShardingFeature(server), false);
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // must be first
arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database
system = irs::memory::make_unique<TRI_vocbase_t>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE);
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // must be before AqlFeature
features.emplace_back(new arangodb::AqlFeature(server), true);
features.emplace_back(new arangodb::aql::OptimizerRulesFeature(server), true);
@ -116,6 +117,11 @@ struct IResearchQueryPhraseSetup {
features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE
#endif
// required for V8DealerFeature::prepare(), ClusterFeature::prepare() not required
arangodb::application_features::ApplicationServer::server->addFeature(
new arangodb::ClusterFeature(server)
);
for (auto& f : features) {
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
}
@ -124,6 +130,12 @@ struct IResearchQueryPhraseSetup {
f.first->prepare();
}
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
for (auto& f : features) {
if (f.second) {
f.first->start();
@ -134,10 +146,12 @@ struct IResearchQueryPhraseSetup {
arangodb::iresearch::IResearchAnalyzerFeature
>();
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
TRI_vocbase_t* vocbase;
dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
analyzers->emplace(
result,
"test_analyzer",
"testVocbase::test_analyzer",
"TestAnalyzer",
"abc",
irs::flags{ irs::frequency::type(), irs::position::type() } // required for PHRASE
@ -145,7 +159,7 @@ struct IResearchQueryPhraseSetup {
analyzers->emplace(
result,
"test_csv_analyzer",
"testVocbase::test_csv_analyzer",
"TestDelimAnalyzer",
","
); // cache analyzer
@ -155,13 +169,11 @@ struct IResearchQueryPhraseSetup {
}
~IResearchQueryPhraseSetup() {
system.reset(); // destroy before reseting the 'ENGINE'
arangodb::AqlFeature(server).stop(); // unset singleton instance
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);
arangodb::LogTopic::setLogLevel(arangodb::Logger::FIXME.name(), arangodb::LogLevel::DEFAULT);
arangodb::LogTopic::setLogLevel(arangodb::Logger::AQL.name(), arangodb::LogLevel::DEFAULT);
arangodb::application_features::ApplicationServer::server = nullptr;
arangodb::EngineSelectorFeature::ENGINE = nullptr;
// destroy application features
for (auto& f : features) {
@ -175,6 +187,7 @@ struct IResearchQueryPhraseSetup {
}
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::DEFAULT);
arangodb::EngineSelectorFeature::ENGINE = nullptr;
}
}; // IResearchQuerySetup

View File

@ -34,7 +34,9 @@
#include "Aql/ExpressionContext.h"
#include "Aql/OptimizerRulesFeature.h"
#include "Aql/Query.h"
#include "Cluster/ClusterFeature.h"
#include "V8/v8-globals.h"
#include "V8Server/V8DealerFeature.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "Transaction/Methods.h"
@ -85,7 +87,6 @@ namespace {
struct IResearchQueryScorerSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::unique_ptr<TRI_vocbase_t> system;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
IResearchQueryScorerSetup(): engine(server), server(nullptr, nullptr) {
@ -103,6 +104,7 @@ struct IResearchQueryScorerSetup {
irs::logger::output_le(iresearch::logger::IRL_FATAL, stderr);
// setup required application features
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
features.emplace_back(new arangodb::ViewTypesFeature(server), true);
features.emplace_back(new arangodb::AuthenticationFeature(server), true);
features.emplace_back(new arangodb::DatabasePathFeature(server), false);
@ -110,8 +112,7 @@ struct IResearchQueryScorerSetup {
features.emplace_back(new arangodb::ShardingFeature(server), false);
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // must be first
arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database
system = irs::memory::make_unique<TRI_vocbase_t>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE);
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // must be before AqlFeature
features.emplace_back(new arangodb::AqlFeature(server), true);
features.emplace_back(new arangodb::aql::OptimizerRulesFeature(server), true);
@ -123,6 +124,11 @@ struct IResearchQueryScorerSetup {
features.emplace_back(new arangodb::LdapFeature(server), false); // required for AuthenticationFeature with USE_ENTERPRISE
#endif
// required for V8DealerFeature::prepare(), ClusterFeature::prepare() not required
arangodb::application_features::ApplicationServer::server->addFeature(
new arangodb::ClusterFeature(server)
);
for (auto& f : features) {
arangodb::application_features::ApplicationServer::server->addFeature(f.first);
}
@ -131,6 +137,12 @@ struct IResearchQueryScorerSetup {
f.first->prepare();
}
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
for (auto& f : features) {
if (f.second) {
f.first->start();
@ -180,21 +192,21 @@ struct IResearchQueryScorerSetup {
arangodb::iresearch::IResearchAnalyzerFeature
>();
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
TRI_vocbase_t* vocbase;
analyzers->emplace(result, "test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
analyzers->emplace(result, "test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
analyzers->emplace(result, "testVocbase::test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
analyzers->emplace(result, "testVocbase::test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
}
~IResearchQueryScorerSetup() {
system.reset(); // destroy before reseting the 'ENGINE'
arangodb::AqlFeature(server).stop(); // unset singleton instance
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);
arangodb::LogTopic::setLogLevel(arangodb::Logger::FIXME.name(), arangodb::LogLevel::DEFAULT);
arangodb::application_features::ApplicationServer::server = nullptr;
arangodb::EngineSelectorFeature::ENGINE = nullptr;
// destroy application features
for (auto& f : features) {
@ -208,6 +220,7 @@ struct IResearchQueryScorerSetup {
}
arangodb::LogTopic::setLogLevel(arangodb::Logger::AUTHENTICATION.name(), arangodb::LogLevel::DEFAULT);
arangodb::EngineSelectorFeature::ENGINE = nullptr;
}
}; // IResearchQueryScorerSetup

View File

@ -88,7 +88,6 @@ extern const char* ARGV0; // defined in main.cpp
struct IResearchQueryTokensSetup {
StorageEngineMock engine;
arangodb::application_features::ApplicationServer server;
std::unique_ptr<TRI_vocbase_t> system;
std::vector<std::pair<arangodb::application_features::ApplicationFeature*, bool>> features;
IResearchQueryTokensSetup(): engine(server), server(nullptr, nullptr) {
@ -112,8 +111,7 @@ struct IResearchQueryTokensSetup {
features.emplace_back(new arangodb::ShardingFeature(server), false);
features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // must be first
arangodb::application_features::ApplicationServer::server->addFeature(features.back().first); // need QueryRegistryFeature feature to be added now in order to create the system database
system = irs::memory::make_unique<TRI_vocbase_t>(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE);
features.emplace_back(new arangodb::SystemDatabaseFeature(server, system.get()), false); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::SystemDatabaseFeature(server), true); // required for IResearchAnalyzerFeature
features.emplace_back(new arangodb::TraverserEngineRegistryFeature(server), false); // must be before AqlFeature
features.emplace_back(new arangodb::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...)
features.emplace_back(new arangodb::AqlFeature(server), true);
@ -139,32 +137,33 @@ struct IResearchQueryTokensSetup {
f.first->prepare();
}
auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]");
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
dbFeature->loadDatabases(databases->slice());
for (auto& f : features) {
if (f.second) {
f.first->start();
}
}
auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::DatabaseFeature
>("Database");
TRI_vocbase_t* vocbase;
dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature<
arangodb::iresearch::IResearchAnalyzerFeature
>();
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
TRI_vocbase_t* vocbase;
analyzers->emplace(result, "test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
analyzers->emplace(result, "test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
analyzers->emplace(result, "testVocbase::test_analyzer", "TestAnalyzer", "abc"); // cache analyzer
analyzers->emplace(result, "testVocbase::test_csv_analyzer", "TestDelimAnalyzer", ","); // cache analyzer
auto* dbPathFeature = arangodb::application_features::ApplicationServer::getFeature<arangodb::DatabasePathFeature>("DatabasePath");
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
}
~IResearchQueryTokensSetup() {
system.reset(); // destroy before reseting the 'ENGINE'
arangodb::AqlFeature(server).stop(); // unset singleton instance
arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT);
arangodb::LogTopic::setLogLevel(arangodb::Logger::FIXME.name(), arangodb::LogLevel::DEFAULT);

View File

@ -493,7 +493,14 @@ void assertExpressionFilter(
// supportsFilterCondition
{
arangodb::iresearch::QueryContext const ctx{ nullptr, nullptr, nullptr, nullptr, ref };
arangodb::transaction::Methods trx(
arangodb::transaction::StandaloneContext::Create(vocbase),
{},
{},
{},
arangodb::transaction::Options()
);
arangodb::iresearch::QueryContext const ctx{ &trx, nullptr, nullptr, nullptr, ref };
CHECK((arangodb::iresearch::FilterFactory::filter(nullptr, ctx, *filterNode)));
}
@ -619,7 +626,15 @@ void assertFilter(
// optimization time
{
arangodb::iresearch::QueryContext const ctx{ nullptr, nullptr, nullptr, nullptr, ref };
arangodb::transaction ::Methods trx(
arangodb::transaction::StandaloneContext::Create(vocbase),
{},
{},
{},
arangodb::transaction::Options()
);
arangodb::iresearch::QueryContext const ctx{ &trx, nullptr, nullptr, nullptr, ref };
CHECK((parseOk == arangodb::iresearch::FilterFactory::filter(nullptr, ctx, *filterNode)));
}