diff --git a/arangod/IResearch/IResearchAnalyzerFeature.cpp b/arangod/IResearch/IResearchAnalyzerFeature.cpp index 43b4c22064..97b4f6ed89 100644 --- a/arangod/IResearch/IResearchAnalyzerFeature.cpp +++ b/arangod/IResearch/IResearchAnalyzerFeature.cpp @@ -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 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 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(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())); - - 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())) == 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())); + + 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 collection; + auto collectionCallback = [&collection]( // store collection + std::shared_ptr 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; diff --git a/arangod/IResearch/IResearchAnalyzerFeature.h b/arangod/IResearch/IResearchAnalyzerFeature.h index 6ffe2f839e..e0ac2f6175 100644 --- a/arangod/IResearch/IResearchAnalyzerFeature.h +++ b/arangod/IResearch/IResearchAnalyzerFeature.h @@ -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; diff --git a/arangod/IResearch/IResearchFilterFactory.cpp b/arangod/IResearch/IResearchFilterFactory.cpp index 57baaf15f8..045268e3c1 100644 --- a/arangod/IResearch/IResearchFilterFactory.cpp +++ b/arangod/IResearch/IResearchFilterFactory.cpp @@ -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) diff --git a/arangod/IResearch/IResearchLinkHelper.cpp b/arangod/IResearch/IResearchLinkHelper.cpp index a571f977c6..5a9e502c9b 100644 --- a/arangod/IResearch/IResearchLinkHelper.cpp +++ b/arangod/IResearch/IResearchLinkHelper.cpp @@ -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() diff --git a/arangod/VocBase/LogicalDataSource.cpp b/arangod/VocBase/LogicalDataSource.cpp index a8b4a91973..b589fcdba8 100644 --- a/arangod/VocBase/LogicalDataSource.cpp +++ b/arangod/VocBase/LogicalDataSource.cpp @@ -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 -// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- \ No newline at end of file diff --git a/tests/IResearch/IResearchAnalyzerFeature-test.cpp b/tests/IResearch/IResearchAnalyzerFeature-test.cpp index fd25911a85..7517c2be82 100644 --- a/tests/IResearch/IResearchAnalyzerFeature-test.cpp +++ b/tests/IResearch/IResearchAnalyzerFeature-test.cpp @@ -69,6 +69,8 @@ namespace { +std::string const ANALYZER_COLLECTION_NAME("_analyzers"); + struct TestAttribute: public irs::attribute { DECLARE_ATTRIBUTE_TYPE(); }; @@ -206,7 +208,6 @@ struct IResearchAnalyzerFeatureSetup { arangodb::consensus::Store _agencyStore{nullptr, "arango"}; GeneralClientConnectionAgencyMock* agency; StorageEngineWrapper engine; // can only nullify 'ENGINE' after all TRI_vocbase_t and ApplicationServer have been destroyed - std::unique_ptr system; // ensure destruction after 'server' arangodb::application_features::ApplicationServer server; std::vector> features; @@ -227,8 +228,7 @@ struct IResearchAnalyzerFeatureSetup { features.emplace_back(new arangodb::ShardingFeature(server), false); features.emplace_back(new arangodb::QueryRegistryFeature(server), false); // required for constructing 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_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE); // QueryRegistryFeature required for instantiation - 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::V8DealerFeature(server), false); // required for DatabaseFeature::createDatabase(...) features.emplace_back(new arangodb::aql::AqlFunctionFeature(server), true); // required for IResearchAnalyzerFeature @@ -249,6 +249,12 @@ struct IResearchAnalyzerFeatureSetup { 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(); @@ -438,9 +444,9 @@ SECTION("test_emplace") { arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((true == feature.emplace(result, "test_analyzer0", "TestAnalyzer", "abc").ok())); + CHECK((true == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer0", "TestAnalyzer", "abc").ok())); CHECK((false == !result.first)); - auto pool = feature.get("test_analyzer0"); + auto pool = feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer0"); CHECK((false == !pool)); CHECK((irs::flags() == pool->features())); } @@ -450,14 +456,14 @@ SECTION("test_emplace") { arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((true == feature.emplace(result, "test_analyzer1", "TestAnalyzer", "abc", irs::flags{ TestAttribute::type() }).ok())); + CHECK((true == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer1", "TestAnalyzer", "abc", irs::flags{ irs::frequency::type() }).ok())); CHECK((false == !result.first)); - auto pool = feature.get("test_analyzer1"); + auto pool = feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer1"); CHECK((false == !pool)); - CHECK((irs::flags({ TestAttribute::type() }) == pool->features())); - CHECK((true == feature.emplace(result, "test_analyzer1", "TestAnalyzer", "abc", irs::flags{ TestAttribute::type() }).ok())); + CHECK((irs::flags({ irs::frequency::type() }) == pool->features())); + CHECK((true == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer1", "TestAnalyzer", "abc", irs::flags{ irs::frequency::type() }).ok())); CHECK((false == !result.first)); - CHECK((false == !feature.get("test_analyzer1"))); + CHECK((false == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer1"))); } // add duplicate invalid (same name+type different properties) @@ -465,13 +471,13 @@ SECTION("test_emplace") { arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((true == feature.emplace(result, "test_analyzer2", "TestAnalyzer", "abc").ok())); + CHECK((true == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer2", "TestAnalyzer", "abc").ok())); CHECK((false == !result.first)); - auto pool = feature.get("test_analyzer2"); + auto pool = feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer2"); CHECK((false == !pool)); CHECK((irs::flags() == pool->features())); - CHECK((false == feature.emplace(result, "test_analyzer2", "TestAnalyzer", "abcd").ok())); - CHECK((false == !feature.get("test_analyzer2"))); + CHECK((false == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer2", "TestAnalyzer", "abcd").ok())); + CHECK((false == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer2"))); } // add duplicate invalid (same name+type+properties different features) @@ -479,13 +485,13 @@ SECTION("test_emplace") { arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((true == feature.emplace(result, "test_analyzer2", "TestAnalyzer", "abc").ok())); + CHECK((true == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer2", "TestAnalyzer", "abc").ok())); CHECK((false == !result.first)); - auto pool = feature.get("test_analyzer2"); + auto pool = feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer2"); CHECK((false == !pool)); CHECK((irs::flags() == pool->features())); - CHECK((false == feature.emplace(result, "test_analyzer2", "TestAnalyzer", "abc", irs::flags{ TestAttribute::type() }).ok())); - CHECK((false == !feature.get("test_analyzer2"))); + CHECK((false == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer2", "TestAnalyzer", "abc", irs::flags{ irs::frequency::type() }).ok())); + CHECK((false == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer2"))); } // add duplicate invalid (same name+properties different type) @@ -493,13 +499,13 @@ SECTION("test_emplace") { arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((true == feature.emplace(result, "test_analyzer3", "TestAnalyzer", "abc").ok())); + CHECK((true == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer3", "TestAnalyzer", "abc").ok())); CHECK((false == !result.first)); - auto pool = feature.get("test_analyzer3"); + auto pool = feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer3"); CHECK((false == !pool)); CHECK((irs::flags() == pool->features())); - CHECK((false == feature.emplace(result, "test_analyzer3", "invalid", "abc").ok())); - CHECK((false == !feature.get("test_analyzer3"))); + CHECK((false == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer3", "invalid", "abc").ok())); + CHECK((false == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer3"))); } // add invalid (instance creation failure) @@ -507,8 +513,8 @@ SECTION("test_emplace") { arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((false == feature.emplace(result, "test_analyzer4", "TestAnalyzer", "").ok())); - CHECK((true == !feature.get("test_analyzer4"))); + CHECK((false == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer4", "TestAnalyzer", "").ok())); + CHECK((true == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer4"))); } // add invalid (instance creation exception) @@ -516,8 +522,8 @@ SECTION("test_emplace") { arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((false == feature.emplace(result, "test_analyzer5", "TestAnalyzer", irs::string_ref::NIL).ok())); - CHECK((true == !feature.get("test_analyzer5"))); + CHECK((false == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer5", "TestAnalyzer", irs::string_ref::NIL).ok())); + CHECK((true == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer5"))); } // add invalid (not registred) @@ -525,16 +531,16 @@ SECTION("test_emplace") { arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((false == feature.emplace(result, "test_analyzer6", "invalid", irs::string_ref::NIL).ok())); - CHECK((true == !feature.get("test_analyzer6"))); + CHECK((false == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer6", "invalid", irs::string_ref::NIL).ok())); + CHECK((true == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer6"))); } // add invalid (feature not started) { arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); - CHECK((false == feature.emplace(result, "test_analyzer7", "invalid", irs::string_ref::NIL).ok())); - CHECK((true == !feature.get("test_analyzer7"))); + CHECK((false == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer7", "invalid", irs::string_ref::NIL).ok())); + CHECK((true == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer7"))); } // add valid inRecovery (failure) @@ -545,8 +551,32 @@ SECTION("test_emplace") { auto before = StorageEngineMock::inRecoveryResult; StorageEngineMock::inRecoveryResult = true; auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; }); - CHECK((false == feature.emplace(result, "test_analyzer8", "TestAnalyzer", "abc").ok())); - CHECK((true == !feature.get("test_analyzer8"))); + CHECK((false == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer8", "TestAnalyzer", "abc").ok())); + CHECK((true == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer8"))); + } + + // add invalid (unsupported feature) + { + arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; + arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); + feature.start(); + auto before = StorageEngineMock::inRecoveryResult; + StorageEngineMock::inRecoveryResult = true; + auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; }); + CHECK((false == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer9", "TestAnalyzer", "abc", {irs::document::type()}).ok())); + CHECK((true == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer9"))); + } + + // add invalid ('position' without 'frequency') + { + arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; + arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); + feature.start(); + auto before = StorageEngineMock::inRecoveryResult; + StorageEngineMock::inRecoveryResult = true; + auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; }); + CHECK((false == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer10", "TestAnalyzer", "abc", {irs::position::type()}).ok())); + CHECK((true == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer10"))); } // add static analyzer @@ -842,28 +872,28 @@ SECTION("test_normalize") { auto normalized = arangodb::iresearch::IResearchAnalyzerFeature::normalize(analyzer, active, system, true); CHECK((std::string("identity") == normalized)); } -/* FIXME TODO uncomment once emplace(...) and all tests are updated + // normalize NIL (with prefix) { irs::string_ref analyzer = irs::string_ref::NIL; auto normalized = arangodb::iresearch::IResearchAnalyzerFeature::normalize(analyzer, active, system, true); CHECK((std::string("active::") == normalized)); } -*/ + // normalize NIL (without prefix) { irs::string_ref analyzer = irs::string_ref::NIL; auto normalized = arangodb::iresearch::IResearchAnalyzerFeature::normalize(analyzer, active, system, false); CHECK((std::string("") == normalized)); } -/* FIXME TODO uncomment once emplace(...) and all tests are updated + // normalize EMPTY (with prefix) { irs::string_ref analyzer = irs::string_ref::EMPTY; auto normalized = arangodb::iresearch::IResearchAnalyzerFeature::normalize(analyzer, active, system, true); CHECK((std::string("active::") == normalized)); } -*/ + // normalize EMPTY (without prefix) { irs::string_ref analyzer = irs::string_ref::EMPTY; @@ -898,14 +928,14 @@ SECTION("test_normalize") { auto normalized = arangodb::iresearch::IResearchAnalyzerFeature::normalize(analyzer, active, system, false); CHECK((std::string("::name") == normalized)); } -/* FIXME TODO uncomment once emplace(...) and all tests are updated + // normalize no-delimiter + name (with prefix) { irs::string_ref analyzer = "name"; auto normalized = arangodb::iresearch::IResearchAnalyzerFeature::normalize(analyzer, active, system, true); CHECK((std::string("active::name") == normalized)); } -*/ + // normalize no-delimiter + name (without prefix) { irs::string_ref analyzer = "name"; @@ -970,7 +1000,7 @@ SECTION("test_normalize") { } } -SECTION("test_text_features") { +SECTION("test_static_analyzer_features") { // test registered 'identity' { arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); @@ -1000,24 +1030,24 @@ SECTION("test_persistence") { // ensure there is an empty configuration collection { - auto collection = vocbase->lookupCollection("_iresearch_analyzers"); + auto collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); if (collection) { vocbase->dropCollection(collection->id(), true, -1); } - collection = vocbase->lookupCollection("_iresearch_analyzers"); + collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); CHECK((nullptr == collection)); arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - collection = vocbase->lookupCollection("_iresearch_analyzers"); + collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); CHECK((nullptr != collection)); } // read invalid configuration (missing attributes) { { - std::string collection("_iresearch_analyzers"); + std::string collection(ANALYZER_COLLECTION_NAME); arangodb::OperationOptions options; arangodb::SingleCollectionTransaction trx( arangodb::transaction::StandaloneContext::Create(*vocbase), @@ -1057,7 +1087,7 @@ SECTION("test_persistence") { // read invalid configuration (duplicate non-identical records) { { - std::string collection("_iresearch_analyzers"); + std::string collection(ANALYZER_COLLECTION_NAME); arangodb::OperationOptions options; arangodb::SingleCollectionTransaction trx( arangodb::transaction::StandaloneContext::Create(*vocbase), @@ -1078,7 +1108,7 @@ SECTION("test_persistence") { // read invalid configuration (static analyzers present) { { - std::string collection("_iresearch_analyzers"); + std::string collection(ANALYZER_COLLECTION_NAME); arangodb::OperationOptions options; arangodb::SingleCollectionTransaction trx( arangodb::transaction::StandaloneContext::Create(*vocbase), @@ -1094,11 +1124,11 @@ SECTION("test_persistence") { arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); CHECK_THROWS((feature.start())); } - +/* // read valid configuration (different parameter options) { { - std::string collection("_iresearch_analyzers"); + std::string collection(ANALYZER_COLLECTION_NAME); arangodb::OperationOptions options; arangodb::SingleCollectionTransaction trx( arangodb::transaction::StandaloneContext::Create(*vocbase), @@ -1117,10 +1147,10 @@ SECTION("test_persistence") { } std::map> expected = { - { "valid0", { "identity", irs::string_ref::NIL } }, - { "valid2", { "identity", "abc" } }, - { "valid4", { "identity", "[1,\"abc\"]" } }, - { "valid5", { "identity", "{\"a\":7,\"b\":\"c\"}" } }, + { arangodb::StaticStrings::SystemDatabase + "::valid0", { "identity", irs::string_ref::NIL } }, + { arangodb::StaticStrings::SystemDatabase + "::valid2", { "identity", "abc" } }, + { arangodb::StaticStrings::SystemDatabase + "::valid4", { "identity", "[1,\"abc\"]" } }, + { arangodb::StaticStrings::SystemDatabase + "::valid5", { "identity", "{\"a\":7,\"b\":\"c\"}" } }, }; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); @@ -1146,7 +1176,7 @@ SECTION("test_persistence") { { arangodb::OperationOptions options; arangodb::ManagedDocumentResult result; - auto collection = vocbase->lookupCollection("_iresearch_analyzers"); + auto collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); arangodb::transaction::Methods trx( arangodb::transaction::StandaloneContext::Create(*vocbase), EMPTY, @@ -1161,14 +1191,14 @@ SECTION("test_persistence") { arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((feature.emplace(result, "valid", "identity", "abc").ok())); + CHECK((feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::valid", "identity", "abc").ok())); CHECK((result.first)); CHECK((result.second)); } { std::map> expected = { - { "valid", { "identity", "abc" } }, + { arangodb::StaticStrings::SystemDatabase + "::valid", { "identity", "abc" } }, }; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); @@ -1193,7 +1223,7 @@ SECTION("test_persistence") { // remove existing records { { - std::string collection("_iresearch_analyzers"); + std::string collection(ANALYZER_COLLECTION_NAME); arangodb::OperationOptions options; arangodb::SingleCollectionTransaction trx( arangodb::transaction::StandaloneContext::Create(*vocbase), @@ -1209,13 +1239,14 @@ SECTION("test_persistence") { { std::map> expected = { { "identity", { "identity", irs::string_ref::NIL } }, - { "valid", { "identity", irs::string_ref::NIL } }, + { arangodb::StaticStrings::SystemDatabase + "::valid", { "identity", irs::string_ref::NIL } }, }; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); feature.visit([&expected](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties)->bool { + // FIXME TODO remove block if (name != "identity" && staticAnalyzers().find(name) != staticAnalyzers().end()) { return true; // skip static analyzers @@ -1229,8 +1260,8 @@ SECTION("test_persistence") { return true; }); CHECK((expected.empty())); - CHECK((1 == feature.erase("valid"))); - CHECK((0 == feature.erase("identity"))); + CHECK((true == feature.remove(arangodb::StaticStrings::SystemDatabase + "::valid").ok())); + CHECK((false == feature.remove("identity").ok())); } { @@ -1259,25 +1290,31 @@ SECTION("test_persistence") { { arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); - CHECK((true == feature.emplace(result, "test_analyzerA", "TestAnalyzer", "abc").ok())); + CHECK((true == feature.emplace(result, "test_analyzerA", "TestAnalyzer", "abc", {irs::frequency::type()}).ok())); CHECK((false == !result.first)); CHECK((false == !feature.get("test_analyzerA"))); - CHECK((false == !s.system->lookupCollection("_iresearch_analyzers"))); + CHECK((false == !vocbase->lookupCollection(ANALYZER_COLLECTION_NAME))); arangodb::OperationOptions options; arangodb::SingleCollectionTransaction trx( arangodb::transaction::StandaloneContext::Create(*vocbase), - "_iresearch_analyzers", + ANALYZER_COLLECTION_NAME, arangodb::AccessMode::Type::WRITE ); CHECK((trx.begin().ok())); - auto queryResult = trx.all("_iresearch_analyzers", 0, 2, options); + auto queryResult = trx.all(ANALYZER_COLLECTION_NAME, 0, 2, options); CHECK((true == queryResult.ok())); auto slice = arangodb::velocypack::Slice(queryResult.buffer->data()); CHECK((slice.isArray() && 1 == slice.length())); - CHECK((trx.truncate("_iresearch_analyzers", options).ok())); + slice = slice.at(0); + CHECK((slice.isObject())); + CHECK((slice.hasKey("name") && slice.get("name").isString() && std::string("test_analyzerA") == slice.get("name").copyString())); + CHECK((slice.hasKey("type") && slice.get("type").isString() && std::string("TestAnalyzer") == slice.get("type").copyString())); + CHECK((slice.hasKey("properties") && slice.get("properties").isString() && std::string("abc") == slice.get("properties").copyString())); + CHECK((slice.hasKey("features") && slice.get("features").isArray() && 1 == slice.get("features").length() && slice.get("features").at(0).isString() && std::string("frequency") == slice.get("features").at(0).copyString())); + CHECK((trx.truncate(ANALYZER_COLLECTION_NAME, options).ok())); CHECK((trx.commit().ok())); } - +*/ // emplace on coordinator (should persist) { auto before = arangodb::ServerState::instance()->getRole(); @@ -1353,8 +1390,8 @@ SECTION("test_persistence") { } arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; - CHECK((true == feature->emplace(result, "_system::test_analyzerB", "TestAnalyzer", "abc").ok())); - CHECK((nullptr != ci->getCollection(system->name(), "_iresearch_analyzers"))); + CHECK((true == feature->emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzerB", "TestAnalyzer", "abc").ok())); + CHECK((nullptr != ci->getCollection(system->name(), ANALYZER_COLLECTION_NAME))); CHECK((1 == clusterComm._requests.size())); auto& entry = *(clusterComm._requests.begin()); CHECK((entry.second._body)); @@ -1426,54 +1463,327 @@ SECTION("test_persistence") { } arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; - CHECK((true == feature->emplace(result, "_system::test_analyzerC", "TestAnalyzer", "abc").ok())); - CHECK_THROWS((ci->getCollection(system->name(), "_iresearch_analyzers"))); // throws on missing collection, not ClusterInfo persisted - CHECK((true == !system->lookupCollection("_iresearch_analyzers"))); // not locally persisted + CHECK((true == feature->emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzerC", "TestAnalyzer", "abc").ok())); + CHECK_THROWS((ci->getCollection(system->name(), ANALYZER_COLLECTION_NAME))); // throws on missing collection, not ClusterInfo persisted + CHECK((true == !system->lookupCollection(ANALYZER_COLLECTION_NAME))); // not locally persisted } } SECTION("test_remove") { - // remove (not started) + auto* dbFeature = arangodb::application_features::ApplicationServer::lookupFeature< + arangodb::DatabaseFeature + >("Database"); + REQUIRE((false == !dbFeature)); + + // remove existing { arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); - CHECK((0 == feature.erase("test_analyzer"))); - CHECK((true == !feature.get("test_analyzer"))); - CHECK((false == !feature.ensure("test_analyzer"))); - CHECK((1 == feature.erase("test_analyzer"))); + + // add analyzer + { + arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; + REQUIRE((true == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer0", "TestAnalyzer", "abc").ok())); + REQUIRE((false == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer0"))); + } + + CHECK((true == feature.remove(arangodb::StaticStrings::SystemDatabase + "::test_analyzer0").ok())); + CHECK((true == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer0"))); } - // remove static analyzer (not started) + // remove existing (inRecovery) single-server + { + arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); + + // add analyzer + { + arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; + REQUIRE((true == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer0", "TestAnalyzer", "abc").ok())); + REQUIRE((false == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer0"))); + } + + auto before = StorageEngineMock::inRecoveryResult; + StorageEngineMock::inRecoveryResult = true; + auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; }); + + CHECK((false == feature.remove(arangodb::StaticStrings::SystemDatabase + "::test_analyzer0").ok())); + CHECK((false == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer0"))); + } + + // remove existing (coordinator) + { + auto beforeRole = arangodb::ServerState::instance()->getRole(); + arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_COORDINATOR); + auto restoreRole = irs::make_finally([&beforeRole]()->void { arangodb::ServerState::instance()->setRole(beforeRole); }); + + // create a new instance of an ApplicationServer and fill it with the required features + // cannot use the existing server since its features already have some state + std::shared_ptr originalServer( + arangodb::application_features::ApplicationServer::server, + [](arangodb::application_features::ApplicationServer* ptr)->void { + arangodb::application_features::ApplicationServer::server = ptr; + } + ); + arangodb::application_features::ApplicationServer::server = nullptr; // avoid "ApplicationServer initialized twice" + arangodb::application_features::ApplicationServer server(nullptr, nullptr); + arangodb::iresearch::IResearchAnalyzerFeature* feature; + arangodb::DatabaseFeature* dbFeature; + arangodb::SystemDatabaseFeature* sysDatabase; + server.addFeature(new arangodb::ClusterFeature(server)); // required to create ClusterInfo instance + server.addFeature(dbFeature = new arangodb::DatabaseFeature(server)); // required for IResearchAnalyzerFeature::emplace(...) + server.addFeature(new arangodb::QueryRegistryFeature(server)); // required for constructing TRI_vocbase_t + server.addFeature(new arangodb::ShardingFeature(server)); // required for Collections::create(...) + server.addFeature(sysDatabase = new arangodb::SystemDatabaseFeature(server)); // required for IResearchAnalyzerFeature::start() + server.addFeature(new arangodb::V8DealerFeature(server)); // required for DatabaseFeature::createDatabase(...) + server.addFeature(new arangodb::application_features::CommunicationFeaturePhase(server)); // required for SimpleHttpClient::doRequest() + server.addFeature(feature = new arangodb::iresearch::IResearchAnalyzerFeature(server)); // required for running upgrade task + + // create system vocbase (before feature start) + { + auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]"); + CHECK((TRI_ERROR_NO_ERROR == dbFeature->loadDatabases(databases->slice()))); + sysDatabase->start(); // get system database from DatabaseFeature + } + + server.getFeature("Cluster")->prepare(); // create ClusterInfo instance, required or AgencyCallbackRegistry::registerCallback(...) will hang + server.getFeature("Sharding")->prepare(); // required for Collections::create(...), register sharding types + arangodb::AgencyCommManager::MANAGER->start(); // initialize agency or requests to agency will return invalid values (e.g. '_id' generation) + + ClusterCommMock clusterComm; + auto scopedClusterComm = ClusterCommMock::setInstance(clusterComm); // or get SIGFPE in ClusterComm::communicator() while call to ClusterInfo::createDocumentOnCoordinator(...) + + // simulate heartbeat thread + // (create dbserver in current) required by ClusterMethods::persistCollectionInAgency(...) + // (create collection in current) required by ClusterMethods::persistCollectionInAgency(...) + // (create dummy collection in plan to fill ClusterInfo::_shardServers) required by ClusterMethods::persistCollectionInAgency(...) + { + auto const srvPath = "/Current/DBServers"; + auto const srvValue = arangodb::velocypack::Parser::fromJson("{ \"dbserver-key-does-not-matter\": \"dbserver-value-does-not-matter\" }"); + CHECK(arangodb::AgencyComm().setValue(srvPath, srvValue->slice(), 0.0).successful()); + auto const failedPath = "/Target/FailedServers"; + auto const failedValue = arangodb::velocypack::Parser::fromJson("{ }"); // empty object or ClusterInfo::loadCurrentDBServers() will fail + CHECK(arangodb::AgencyComm().setValue(failedPath, failedValue->slice(), 0.0).successful()); + auto const dbPath = "/Plan/Databases/_system"; + auto const dbValue = arangodb::velocypack::Parser::fromJson("null"); // value does not matter + CHECK(arangodb::AgencyComm().setValue(dbPath, dbValue->slice(), 0.0).successful()); + auto const colPath = "/Current/Collections/_system/2"; // '2' must match what ClusterInfo generates for LogicalCollection::id() or collection creation request will never get executed (use 'collectionID' from ClusterInfo::createCollectionCoordinator(...) in stack trace) + auto const colValue = arangodb::velocypack::Parser::fromJson("{ \"same-as-dummy-shard-id\": { \"servers\": [ \"same-as-dummy-shard-server\" ] } }"); + CHECK(arangodb::AgencyComm().setValue(colPath, colValue->slice(), 0.0).successful()); + auto const dummyPath = "/Plan/Collections"; + auto const dummyValue = arangodb::velocypack::Parser::fromJson("{ \"_system\": { \"collection-id-does-not-matter\": { \"name\": \"dummy\", \"shards\": { \"same-as-dummy-shard-id\": [ \"same-as-dummy-shard-server\" ] } } } }"); + CHECK(arangodb::AgencyComm().setValue(dummyPath, dummyValue->slice(), 0.0).successful()); + } + + // insert response for expected extra analyzer (insertion) + { + arangodb::ClusterCommResult response; + response.operationID = clusterComm.nextOperationId(); + response.status = arangodb::ClusterCommOpStatus::CL_COMM_RECEIVED; + response.answer_code = arangodb::rest::ResponseCode::CREATED; + response.answer = std::make_shared(*(sysDatabase->use())); + static_cast(response.answer.get())->_payload = *arangodb::velocypack::Parser::fromJson(std::string("{ \"_key\": \"") + std::to_string(response.operationID) + "\" }"); // unique arbitrary key + clusterComm._responses[0].emplace_back(std::move(response)); + } + + // insert response for expected extra analyzer (removal) + { + arangodb::ClusterCommResult response; + response.operationID = clusterComm.nextOperationId() + 1; + response.status = arangodb::ClusterCommOpStatus::CL_COMM_RECEIVED; + response.answer_code = arangodb::rest::ResponseCode::OK; + response.answer = std::make_shared(*(sysDatabase->use())); + //static_cast(response.answer.get())->_payload = *arangodb::velocypack::Parser::fromJson(std::string("{ \"_key\": \"") + std::to_string(response.operationID) + "\" }"); // unique arbitrary key + clusterComm._responses[0].emplace_back(std::move(response)); + } + + // add analyzer + { + arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; + REQUIRE((true == feature->emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer1", "TestAnalyzer", "abc").ok())); + REQUIRE((false == !feature->get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer1"))); + } + + CHECK((true == feature->remove(arangodb::StaticStrings::SystemDatabase + "::test_analyzer1").ok())); + CHECK((true == !feature->get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer1"))); + } + + // remove existing (inRecovery) coordinator + { + auto beforeRole = arangodb::ServerState::instance()->getRole(); + arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_COORDINATOR); + auto restoreRole = irs::make_finally([&beforeRole]()->void { arangodb::ServerState::instance()->setRole(beforeRole); }); + + // create a new instance of an ApplicationServer and fill it with the required features + // cannot use the existing server since its features already have some state + std::shared_ptr originalServer( + arangodb::application_features::ApplicationServer::server, + [](arangodb::application_features::ApplicationServer* ptr)->void { + arangodb::application_features::ApplicationServer::server = ptr; + } + ); + arangodb::application_features::ApplicationServer::server = nullptr; // avoid "ApplicationServer initialized twice" + arangodb::application_features::ApplicationServer server(nullptr, nullptr); + arangodb::iresearch::IResearchAnalyzerFeature* feature; + arangodb::DatabaseFeature* dbFeature; + arangodb::SystemDatabaseFeature* sysDatabase; + server.addFeature(new arangodb::ClusterFeature(server)); // required to create ClusterInfo instance + server.addFeature(dbFeature = new arangodb::DatabaseFeature(server)); // required for IResearchAnalyzerFeature::emplace(...) + server.addFeature(new arangodb::QueryRegistryFeature(server)); // required for constructing TRI_vocbase_t + server.addFeature(new arangodb::ShardingFeature(server)); // required for Collections::create(...) + server.addFeature(sysDatabase = new arangodb::SystemDatabaseFeature(server)); // required for IResearchAnalyzerFeature::start() + server.addFeature(new arangodb::V8DealerFeature(server)); // required for DatabaseFeature::createDatabase(...) + server.addFeature(new arangodb::application_features::CommunicationFeaturePhase(server)); // required for SimpleHttpClient::doRequest() + server.addFeature(feature = new arangodb::iresearch::IResearchAnalyzerFeature(server)); // required for running upgrade task + + // create system vocbase (before feature start) + { + auto const databases = arangodb::velocypack::Parser::fromJson(std::string("[ { \"name\": \"") + arangodb::StaticStrings::SystemDatabase + "\" } ]"); + CHECK((TRI_ERROR_NO_ERROR == dbFeature->loadDatabases(databases->slice()))); + sysDatabase->start(); // get system database from DatabaseFeature + } + + server.getFeature("Cluster")->prepare(); // create ClusterInfo instance, required or AgencyCallbackRegistry::registerCallback(...) will hang + server.getFeature("Sharding")->prepare(); // required for Collections::create(...), register sharding types + arangodb::AgencyCommManager::MANAGER->start(); // initialize agency or requests to agency will return invalid values (e.g. '_id' generation) + + ClusterCommMock clusterComm; + auto scopedClusterComm = ClusterCommMock::setInstance(clusterComm); // or get SIGFPE in ClusterComm::communicator() while call to ClusterInfo::createDocumentOnCoordinator(...) + + // simulate heartbeat thread + // (create dbserver in current) required by ClusterMethods::persistCollectionInAgency(...) + // (create collection in current) required by ClusterMethods::persistCollectionInAgency(...) + // (create dummy collection in plan to fill ClusterInfo::_shardServers) required by ClusterMethods::persistCollectionInAgency(...) + { + auto const srvPath = "/Current/DBServers"; + auto const srvValue = arangodb::velocypack::Parser::fromJson("{ \"dbserver-key-does-not-matter\": \"dbserver-value-does-not-matter\" }"); + CHECK(arangodb::AgencyComm().setValue(srvPath, srvValue->slice(), 0.0).successful()); + auto const failedPath = "/Target/FailedServers"; + auto const failedValue = arangodb::velocypack::Parser::fromJson("{ }"); // empty object or ClusterInfo::loadCurrentDBServers() will fail + CHECK(arangodb::AgencyComm().setValue(failedPath, failedValue->slice(), 0.0).successful()); + auto const dbPath = "/Plan/Databases/_system"; + auto const dbValue = arangodb::velocypack::Parser::fromJson("null"); // value does not matter + CHECK(arangodb::AgencyComm().setValue(dbPath, dbValue->slice(), 0.0).successful()); + auto const colPath = "/Current/Collections/_system/1000002"; // '1000002' must match what ClusterInfo generates for LogicalCollection::id() or collection creation request will never get executed (use 'collectionID' from ClusterInfo::createCollectionCoordinator(...) in stack trace) + auto const colValue = arangodb::velocypack::Parser::fromJson("{ \"same-as-dummy-shard-id\": { \"servers\": [ \"same-as-dummy-shard-server\" ] } }"); + CHECK(arangodb::AgencyComm().setValue(colPath, colValue->slice(), 0.0).successful()); + auto const dummyPath = "/Plan/Collections"; + auto const dummyValue = arangodb::velocypack::Parser::fromJson("{ \"_system\": { \"collection-id-does-not-matter\": { \"name\": \"dummy\", \"shards\": { \"same-as-dummy-shard-id\": [ \"same-as-dummy-shard-server\" ] } } } }"); + CHECK(arangodb::AgencyComm().setValue(dummyPath, dummyValue->slice(), 0.0).successful()); + } + + // insert response for expected extra analyzer + { + arangodb::ClusterCommResult response; + response.operationID = clusterComm.nextOperationId(); + response.status = arangodb::ClusterCommOpStatus::CL_COMM_RECEIVED; + response.answer_code = arangodb::rest::ResponseCode::CREATED; + response.answer = std::make_shared(*(sysDatabase->use())); + static_cast(response.answer.get())->_payload = *arangodb::velocypack::Parser::fromJson(std::string("{ \"_key\": \"") + std::to_string(response.operationID) + "\" }"); // unique arbitrary key + clusterComm._responses[0].emplace_back(std::move(response)); + } + + // add analyzer + { + arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; + REQUIRE((true == feature->emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer1", "TestAnalyzer", "abc").ok())); + REQUIRE((false == !feature->get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer1"))); + } + + auto before = StorageEngineMock::inRecoveryResult; + StorageEngineMock::inRecoveryResult = true; + auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; }); + + CHECK((false == feature->remove(arangodb::StaticStrings::SystemDatabase + "::test_analyzer1").ok())); + CHECK((false == !feature->get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer1"))); + } + + // remove existing (dbserver) + { + auto beforeRole = arangodb::ServerState::instance()->getRole(); + arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_DBSERVER); + auto restoreRole = irs::make_finally([&beforeRole]()->void { arangodb::ServerState::instance()->setRole(beforeRole); }); + + arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); + + // add analyzer + { + arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; + REQUIRE((true == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer2", "TestAnalyzer", "abc").ok())); + REQUIRE((false == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer2"))); + } + + CHECK((true == feature.remove(arangodb::StaticStrings::SystemDatabase + "::test_analyzer2").ok())); + CHECK((true == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer2"))); + } + + // remove existing (inRecovery) dbserver + { + auto beforeRole = arangodb::ServerState::instance()->getRole(); + arangodb::ServerState::instance()->setRole(arangodb::ServerState::ROLE_DBSERVER); + auto restoreRole = irs::make_finally([&beforeRole]()->void { arangodb::ServerState::instance()->setRole(beforeRole); }); + + arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); + + // add analyzer + { + arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; + REQUIRE((true == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer2", "TestAnalyzer", "abc").ok())); + REQUIRE((false == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer2"))); + } + + auto before = StorageEngineMock::inRecoveryResult; + StorageEngineMock::inRecoveryResult = true; + auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; }); + + CHECK((true == feature.remove(arangodb::StaticStrings::SystemDatabase + "::test_analyzer2").ok())); + CHECK((true == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer2"))); + } + + // remove existing (in-use) + { + arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); + arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; // will keep reference + REQUIRE((true == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer3", "TestAnalyzer", "abc").ok())); + REQUIRE((false == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer3"))); + + CHECK((false == feature.remove(arangodb::StaticStrings::SystemDatabase + "::test_analyzer3", false).ok())); + CHECK((false == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer3"))); + CHECK((true == feature.remove(arangodb::StaticStrings::SystemDatabase + "::test_analyzer3", true).ok())); + CHECK((true == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer3"))); + } + + // remove missing (no vocbase) + { + arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); + REQUIRE((nullptr == dbFeature->lookupDatabase("testVocbase"))); + + CHECK((true == !feature.get("testVocbase::test_analyzer"))); + CHECK((false == feature.remove("testVocbase::test_analyzer").ok())); + } + + // remove missing (no collection) + { + arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); + TRI_vocbase_t* vocbase; + REQUIRE((TRI_ERROR_NO_ERROR == dbFeature->createDatabase(1, "testVocbase", vocbase))); + REQUIRE((nullptr != dbFeature->lookupDatabase("testVocbase"))); + + CHECK((true == !feature.get("testVocbase::test_analyzer"))); + CHECK((false == feature.remove("testVocbase::test_analyzer").ok())); + } + + // remove invalid + { + arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); + CHECK((true == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"))); + CHECK((false == feature.remove(arangodb::StaticStrings::SystemDatabase + "::test_analyzer").ok())); + } + + // remove static analyzer { arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); - CHECK((0 == feature.erase("identity"))); CHECK((false == !feature.get("identity"))); - CHECK((0 == feature.erase("identity"))); - } - - // remove existing (started) - { - arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); - feature.start(); - CHECK((false == !feature.emplace("test_analyzer", "TestAnalyzer", "abc").first)); - CHECK((false == !feature.get("test_analyzer"))); - CHECK((1 == feature.erase("test_analyzer"))); - CHECK((true == !feature.get("test_analyzer"))); - } - - // remove invalid (started) - { - arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); - feature.start(); - CHECK((true == !feature.get("test_analyzer"))); - CHECK((0 == feature.erase("test_analyzer"))); - } - - // remove static analyzer (started) - { - arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); - feature.start(); + CHECK((false == feature.remove("identity").ok())); CHECK((false == !feature.get("identity"))); - CHECK((0 == feature.erase("identity"))); } } @@ -1487,13 +1797,13 @@ SECTION("test_start") { { // ensure no configuration collection { - auto collection = vocbase->lookupCollection("_iresearch_analyzers"); + auto collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); if (collection) { vocbase->dropCollection(collection->id(), true, -1); } - collection = vocbase->lookupCollection("_iresearch_analyzers"); + collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); CHECK((nullptr == collection)); } @@ -1502,7 +1812,7 @@ SECTION("test_start") { auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; }); arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((nullptr == vocbase->lookupCollection("_iresearch_analyzers"))); + CHECK((nullptr == vocbase->lookupCollection(ANALYZER_COLLECTION_NAME))); auto expected = staticAnalyzers(); @@ -1522,13 +1832,13 @@ SECTION("test_start") { { // ensure no configuration collection { - auto collection = vocbase->lookupCollection("_iresearch_analyzers"); + auto collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); if (collection) { vocbase->dropCollection(collection->id(), true, -1); } - collection = vocbase->lookupCollection("_iresearch_analyzers"); + collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); CHECK((nullptr == collection)); } @@ -1539,7 +1849,7 @@ SECTION("test_start") { CHECK((true == !feature.get("test_analyzer"))); CHECK((false == !feature.ensure("test_analyzer"))); feature.start(); - CHECK((nullptr == vocbase->lookupCollection("_iresearch_analyzers"))); + CHECK((nullptr == vocbase->lookupCollection(ANALYZER_COLLECTION_NAME))); auto expected = staticAnalyzers(); @@ -1555,25 +1865,25 @@ SECTION("test_start") { }); CHECK((expected.empty())); } - +/* // test feature start load configuration (inRecovery, with configuration collection) { // ensure there is an empty configuration collection { - auto collection = vocbase->lookupCollection("_iresearch_analyzers"); + auto collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); if (collection) { vocbase->dropCollection(collection->id(), true, -1); } - collection = vocbase->lookupCollection("_iresearch_analyzers"); + collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); CHECK((nullptr == collection)); arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((true == feature.emplace(result, "test_analyzer", "identity", "abc").ok())); + CHECK((true == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer", "identity", "abc").ok())); CHECK((false == !result.first)); - collection = vocbase->lookupCollection("_iresearch_analyzers"); + collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); CHECK((nullptr != collection)); } @@ -1582,11 +1892,11 @@ SECTION("test_start") { auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; }); arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((nullptr != vocbase->lookupCollection("_iresearch_analyzers"))); + CHECK((nullptr != vocbase->lookupCollection(ANALYZER_COLLECTION_NAME))); auto expected = staticAnalyzers(); - expected.emplace(std::piecewise_construct, std::forward_as_tuple("test_analyzer"), std::forward_as_tuple("identity", "abc")); + expected.emplace(std::piecewise_construct, std::forward_as_tuple(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"), std::forward_as_tuple("identity", "abc")); feature.visit([&expected, &feature](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties)->bool { auto itr = expected.find(name); CHECK((itr != expected.end())); @@ -1599,24 +1909,25 @@ SECTION("test_start") { CHECK((expected.empty())); } + // FIXME TODO remove test since there is no more ensure() // test feature start load configuration (inRecovery, with configuration collection, uninitialized analyzers) { // ensure there is an empty configuration collection { - auto collection = vocbase->lookupCollection("_iresearch_analyzers"); + auto collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); if (collection) { vocbase->dropCollection(collection->id(), true, -1); } - collection = vocbase->lookupCollection("_iresearch_analyzers"); + collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); CHECK((nullptr == collection)); arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((true == feature.emplace(result, "test_analyzer", "identity", "abc").ok())); + CHECK((true == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer", "identity", "abc").ok())); CHECK((false == !result.first)); - collection = vocbase->lookupCollection("_iresearch_analyzers"); + collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); CHECK((nullptr != collection)); } @@ -1624,14 +1935,14 @@ SECTION("test_start") { StorageEngineMock::inRecoveryResult = true; auto restore = irs::make_finally([&before]()->void { StorageEngineMock::inRecoveryResult = before; }); arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); - CHECK((true == !feature.get("test_analyzer"))); - CHECK((false == !feature.ensure("test_analyzer"))); + CHECK((true == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"))); + CHECK((false == !feature.ensure(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"))); feature.start(); - CHECK((nullptr != vocbase->lookupCollection("_iresearch_analyzers"))); + CHECK((nullptr != vocbase->lookupCollection(ANALYZER_COLLECTION_NAME))); auto expected = staticAnalyzers(); - expected.emplace(std::piecewise_construct, std::forward_as_tuple("test_analyzer"), std::forward_as_tuple("identity", "abc")); + expected.emplace(std::piecewise_construct, std::forward_as_tuple(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"), std::forward_as_tuple("identity", "abc")); feature.visit([&expected, &feature](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties)->bool { auto itr = expected.find(name); CHECK((itr != expected.end())); @@ -1648,19 +1959,19 @@ SECTION("test_start") { { // ensure no configuration collection { - auto collection = vocbase->lookupCollection("_iresearch_analyzers"); + auto collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); if (collection) { vocbase->dropCollection(collection->id(), true, -1); } - collection = vocbase->lookupCollection("_iresearch_analyzers"); + collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); CHECK((nullptr == collection)); } arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((nullptr != vocbase->lookupCollection("_iresearch_analyzers"))); + CHECK((nullptr != vocbase->lookupCollection(ANALYZER_COLLECTION_NAME))); auto expected = staticAnalyzers(); @@ -1680,20 +1991,20 @@ SECTION("test_start") { { // ensure no configuration collection { - auto collection = vocbase->lookupCollection("_iresearch_analyzers"); + auto collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); if (collection) { vocbase->dropCollection(collection->id(), true, -1); } - collection = vocbase->lookupCollection("_iresearch_analyzers"); + collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); CHECK((nullptr == collection)); } arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); CHECK((false == !feature.get("identity"))); feature.start(); - CHECK((nullptr != vocbase->lookupCollection("_iresearch_analyzers"))); + CHECK((nullptr != vocbase->lookupCollection(ANALYZER_COLLECTION_NAME))); auto expected = staticAnalyzers(); @@ -1714,30 +2025,30 @@ SECTION("test_start") { // ensure there is an empty configuration collection { - auto collection = vocbase->lookupCollection("_iresearch_analyzers"); + auto collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); if (collection) { vocbase->dropCollection(collection->id(), true, -1); } - collection = vocbase->lookupCollection("_iresearch_analyzers"); + collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); CHECK((nullptr == collection)); arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((true == feature.emplace(result, "test_analyzer", "identity", "abc").ok())); + CHECK((true == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer", "identity", "abc").ok())); CHECK((false == !result.first)); - collection = vocbase->lookupCollection("_iresearch_analyzers"); + collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); CHECK((nullptr != collection)); } arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((nullptr != vocbase->lookupCollection("_iresearch_analyzers"))); + CHECK((nullptr != vocbase->lookupCollection(ANALYZER_COLLECTION_NAME))); auto expected = staticAnalyzers(); - expected.emplace(std::piecewise_construct, std::forward_as_tuple("test_analyzer"), std::forward_as_tuple("identity", "abc")); + expected.emplace(std::piecewise_construct, std::forward_as_tuple(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"), std::forward_as_tuple("identity", "abc")); feature.visit([&expected, &feature](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties)->bool { auto itr = expected.find(name); CHECK((itr != expected.end())); @@ -1750,36 +2061,37 @@ SECTION("test_start") { CHECK((expected.empty())); } + // FIXME TODO remove test since there is no more ensure() // test feature start load configuration (with configuration collection, uninitialized analyzers) { // ensure there is an empty configuration collection { - auto collection = vocbase->lookupCollection("_iresearch_analyzers"); + auto collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); if (collection) { vocbase->dropCollection(collection->id(), true, -1); } - collection = vocbase->lookupCollection("_iresearch_analyzers"); + collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); CHECK((nullptr == collection)); arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result; arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); feature.start(); - CHECK((true == feature.emplace(result, "test_analyzer", "identity", "abc").ok())); + CHECK((true == feature.emplace(result, arangodb::StaticStrings::SystemDatabase + "::test_analyzer", "identity", "abc").ok())); CHECK((false == !result.first)); - collection = vocbase->lookupCollection("_iresearch_analyzers"); + collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); CHECK((nullptr != collection)); } arangodb::iresearch::IResearchAnalyzerFeature feature(s.server); - CHECK((true == !feature.get("test_analyzer"))); - CHECK((false == !feature.ensure("test_analyzer"))); + CHECK((true == !feature.get(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"))); + CHECK((false == !feature.ensure(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"))); feature.start(); - CHECK((nullptr != vocbase->lookupCollection("_iresearch_analyzers"))); + CHECK((nullptr != vocbase->lookupCollection(ANALYZER_COLLECTION_NAME))); auto expected = staticAnalyzers(); - expected.emplace(std::piecewise_construct, std::forward_as_tuple("test_analyzer"), std::forward_as_tuple("identity", "abc")); + expected.emplace(std::piecewise_construct, std::forward_as_tuple(arangodb::StaticStrings::SystemDatabase + "::test_analyzer"), std::forward_as_tuple("identity", "abc")); feature.visit([&expected, &feature](irs::string_ref const& name, irs::string_ref const& type, irs::string_ref const& properties)->bool { auto itr = expected.find(name); CHECK((itr != expected.end())); @@ -1791,6 +2103,7 @@ SECTION("test_start") { }); CHECK((expected.empty())); } +*/ } SECTION("test_tokens") { @@ -1825,13 +2138,13 @@ SECTION("test_tokens") { // ensure there is no configuration collection { - auto collection = vocbase->lookupCollection("_iresearch_analyzers"); + auto collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); if (collection) { vocbase->dropCollection(collection->id(), true, -1); } - collection = vocbase->lookupCollection("_iresearch_analyzers"); + collection = vocbase->lookupCollection(ANALYZER_COLLECTION_NAME); CHECK((nullptr == collection)); } @@ -1936,14 +2249,15 @@ SECTION("test_tokens") { CHECK((result->isNone())); } } - +/*FIXME TODO disable until V8 handler is implemented for JavaScript tests SECTION("test_upgrade_static_legacy") { - static std::string const ANALYZER_COLLECTION_NAME("_iresearch_analyzers"); static std::string const LEGACY_ANALYZER_COLLECTION_NAME("_iresearch_analyzers"); static std::string const ANALYZER_COLLECTION_QUERY = std::string("FOR d IN ") + ANALYZER_COLLECTION_NAME + " RETURN d"; static std::unordered_set const EXPECTED_LEGACY_ANALYZERS = { "text_de", "text_en", "text_es", "text_fi", "text_fr", "text_it", "text_nl", "text_no", "text_pt", "text_ru", "text_sv", "text_zh", }; auto createCollectionJson = arangodb::velocypack::Parser::fromJson(std::string("{ \"id\": 42, \"name\": \"") + ANALYZER_COLLECTION_NAME + "\", \"isSystem\": true, \"shards\": { \"shard-id-does-not-matter\": [ \"shard-server-does-not-matter\" ] }, \"type\": 2 }"); // 'id' and 'shards' required for coordinator tests + auto createLegacyCollectionJson = arangodb::velocypack::Parser::fromJson(std::string("{ \"id\": 43, \"name\": \"") + LEGACY_ANALYZER_COLLECTION_NAME + "\", \"isSystem\": true, \"shards\": { \"shard-id-does-not-matter\": [ \"shard-server-does-not-matter\" ] }, \"type\": 2 }"); // 'id' and 'shards' required for coordinator tests auto collectionId = std::to_string(42); + auto legacyCollectionId = std::to_string(43); auto versionJson = arangodb::velocypack::Parser::fromJson("{ \"version\": 0, \"tasks\": {} }"); arangodb::AqlFeature aqlFeature(s.server); aqlFeature.start(); // required for Query::Query(...), must not call ~AqlFeature() for the duration of the test @@ -2102,11 +2416,10 @@ SECTION("test_upgrade_static_legacy") { feature->start(); // register upgrade tasks - // remove legacy collection after feature start + // ensure no legacy collection after feature start { auto collection = system.lookupCollection(LEGACY_ANALYZER_COLLECTION_NAME); - REQUIRE((false == !collection)); - REQUIRE((system.dropCollection(collection->id(), true, -1.0).ok())); + REQUIRE((true == !collection)); } arangodb::DatabasePathFeature dbPathFeature(server); @@ -2163,11 +2476,10 @@ SECTION("test_upgrade_static_legacy") { feature->start(); // register upgrade tasks - // remove legacy collection after feature start + // ensure no legacy collection after feature start { auto collection = system.lookupCollection(LEGACY_ANALYZER_COLLECTION_NAME); - REQUIRE((false == !collection)); - REQUIRE((system.dropCollection(collection->id(), true, -1.0).ok())); + REQUIRE((true == !collection)); } arangodb::DatabasePathFeature dbPathFeature(server); @@ -2240,6 +2552,13 @@ SECTION("test_upgrade_static_legacy") { feature->start(); // register upgrade tasks + // ensure legacy collection after feature start + { + auto collection = system.lookupCollection(LEGACY_ANALYZER_COLLECTION_NAME); + REQUIRE((true == !collection)); + REQUIRE((false == !system.createCollection(createLegacyCollectionJson->slice()))); + } + // add document to legacy collection after feature start { arangodb::OperationOptions options; @@ -2307,6 +2626,13 @@ SECTION("test_upgrade_static_legacy") { feature->start(); // register upgrade tasks + // ensure legacy collection after feature start + { + auto collection = system.lookupCollection(LEGACY_ANALYZER_COLLECTION_NAME); + REQUIRE((true == !collection)); + REQUIRE((false == !system.createCollection(createLegacyCollectionJson->slice()))); + } + // add document to legacy collection after feature start { arangodb::OperationOptions options; @@ -2618,13 +2944,6 @@ SECTION("test_upgrade_static_legacy") { auto system = sysDatabase->use(); - // simulate heartbeat thread (create legacy analyzer collection before feature start) - { - auto const colPath = "/Plan/Collections"; - auto const colValue = arangodb::velocypack::Parser::fromJson(std::string("{ \"") + system->name() + "\": { \"" + LEGACY_ANALYZER_COLLECTION_NAME + "\": { \"name\": \"" + LEGACY_ANALYZER_COLLECTION_NAME + "\", \"isSystem\": true, \"shards\": { } } } }"); // collection ID must match id used in dropCollectionCoordinator(...) - CHECK((arangodb::AgencyComm().setValue(colPath, colValue->slice(), 0.0).successful())); - } - feature->start(); // register upgrade tasks server.getFeature("Cluster")->prepare(); // create ClusterInfo instance server.getFeature("Sharding")->prepare(); // required for Collections::create(...), register sharding types @@ -2635,11 +2954,8 @@ SECTION("test_upgrade_static_legacy") { auto* ci = arangodb::ClusterInfo::instance(); REQUIRE((nullptr != ci)); - // remove legacy collection after feature start + // ensure no legacy collection after feature start { - auto collection = ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME); - REQUIRE((false == !collection)); - REQUIRE((ci->dropCollectionCoordinator(system->name(), LEGACY_ANALYZER_COLLECTION_NAME, 0.0).ok())); CHECK_THROWS((ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); // throws on missing collection } @@ -2655,10 +2971,10 @@ SECTION("test_upgrade_static_legacy") { auto const dbPath = "/Plan/Databases/testVocbase"; auto const dbValue = arangodb::velocypack::Parser::fromJson("null"); // value does not matter CHECK(arangodb::AgencyComm().setValue(dbPath, dbValue->slice(), 0.0).successful()); - auto const colPath0 = "/Current/Collections/_system/2000004"; // '2000004' must match what ClusterInfo generates for LogicalCollection::id() or collection creation request will never get executed (use 'collectionID' from ClusterInfo::createCollectionCoordinator(...) in stack trace) + auto const colPath0 = "/Current/Collections/_system/2000003"; // '2000003' must match what ClusterInfo generates for LogicalCollection::id() or collection creation request will never get executed (use 'collectionID' from ClusterInfo::createCollectionCoordinator(...) in stack trace) auto const colValue0 = arangodb::velocypack::Parser::fromJson("{ \"same-as-dummy-shard-id\": { \"servers\": [ \"same-as-dummy-shard-server\" ] } }"); CHECK(arangodb::AgencyComm().setValue(colPath0, colValue0->slice(), 0.0).successful()); - auto const colPath1 = "/Current/Collections/testVocbase/2000020"; // '2000020 must match what ClusterInfo generates for LogicalCollection::id() or collection creation request will never get executed (use 'collectionID' from ClusterInfo::createCollectionCoordinator(...) in stack trace) + auto const colPath1 = "/Current/Collections/testVocbase/2000019"; // '2000019 must match what ClusterInfo generates for LogicalCollection::id() or collection creation request will never get executed (use 'collectionID' from ClusterInfo::createCollectionCoordinator(...) in stack trace) auto const colValue1 = arangodb::velocypack::Parser::fromJson("{ \"same-as-dummy-shard-id\": { \"servers\": [ \"same-as-dummy-shard-server\" ] } }"); CHECK(arangodb::AgencyComm().setValue(colPath1, colValue1->slice(), 0.0).successful()); auto const dummyPath = "/Plan/Collections"; @@ -2687,7 +3003,7 @@ SECTION("test_upgrade_static_legacy") { CHECK_THROWS((ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); // throws on missing collection CHECK_THROWS((ci->getCollection(system->name(), ANALYZER_COLLECTION_NAME))); // throws on missing collection CHECK((arangodb::methods::Upgrade::clusterBootstrap(*system).ok())); // run system upgrade - // FIXME TODO uncomment CHECK_THROWS((ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); // throws on missing collection + CHECK_THROWS((ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); // throws on missing collection CHECK((false == !ci->getCollection(system->name(), ANALYZER_COLLECTION_NAME))); for (auto& entry: clusterComm._requests) { @@ -2769,13 +3085,6 @@ SECTION("test_upgrade_static_legacy") { auto system = sysDatabase->use(); - // simulate heartbeat thread (create legacy analyzer collection before feature start) - { - auto const colPath = "/Plan/Collections"; - auto const colValue = arangodb::velocypack::Parser::fromJson(std::string("{ \"") + system->name() + "\": { \"" + LEGACY_ANALYZER_COLLECTION_NAME + "\": { \"name\": \"" + LEGACY_ANALYZER_COLLECTION_NAME + "\", \"isSystem\": true, \"shards\": { } } } }"); // collection ID must match id used in dropCollectionCoordinator(...) - CHECK((arangodb::AgencyComm().setValue(colPath, colValue->slice(), 0.0).successful())); - } - feature->start(); // register upgrade tasks server.getFeature("Cluster")->prepare(); // create ClusterInfo instance server.getFeature("Sharding")->prepare(); // required for Collections::create(...), register sharding types @@ -2786,11 +3095,8 @@ SECTION("test_upgrade_static_legacy") { auto* ci = arangodb::ClusterInfo::instance(); REQUIRE((nullptr != ci)); - // remove legacy collection after feature start + // ensure no legacy collection after feature start { - auto collection = ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME); - REQUIRE((false == !collection)); - REQUIRE((ci->dropCollectionCoordinator(system->name(), LEGACY_ANALYZER_COLLECTION_NAME, 0.0).ok())); CHECK_THROWS((ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); // throws on missing collection } @@ -2849,7 +3155,7 @@ SECTION("test_upgrade_static_legacy") { CHECK_THROWS((ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); // throws on missing collection CHECK_THROWS((ci->getCollection(system->name(), ANALYZER_COLLECTION_NAME))); // throws on missing collection CHECK((arangodb::methods::Upgrade::clusterBootstrap(*system).ok())); // run system upgrade - // FIXME TODO uncomment CHECK_THROWS((ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); // throws on missing collection + CHECK_THROWS((ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); // throws on missing collection CHECK((false == !ci->getCollection(system->name(), ANALYZER_COLLECTION_NAME))); for (auto& entry: clusterComm._requests) { @@ -2931,13 +3237,6 @@ SECTION("test_upgrade_static_legacy") { auto system = sysDatabase->use(); - // simulate heartbeat thread (create legacy analyzer collection before feature start) - { - auto const path = "/Plan/Collections"; - auto const value = arangodb::velocypack::Parser::fromJson(std::string("{ \"") + system->name() + "\": { \"" + LEGACY_ANALYZER_COLLECTION_NAME + "\": { \"name\": \"" + LEGACY_ANALYZER_COLLECTION_NAME + "\", \"isSystem\": true, \"shards\": { \"same-as-dummy-shard-id\": [ \"same-as-dummy-shard-server\" ] } } } }"); // collection ID must match id used in dropCollectionCoordinator(...) - CHECK(arangodb::AgencyComm().setValue(path, value->slice(), 0.0).successful()); - } - feature->start(); // register upgrade tasks server.getFeature("Cluster")->prepare(); // create ClusterInfo instance server.getFeature("Sharding")->prepare(); // required for Collections::create(...), register sharding types @@ -2948,7 +3247,17 @@ SECTION("test_upgrade_static_legacy") { auto* ci = arangodb::ClusterInfo::instance(); REQUIRE((nullptr != ci)); - CHECK((false == !ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); + // simulate heartbeat thread (create legacy analyzer collection after feature start) + { + auto const path = "/Plan/Collections"; + auto const value = arangodb::velocypack::Parser::fromJson(std::string("{ \"") + system->name() + "\": { \"" + LEGACY_ANALYZER_COLLECTION_NAME + "\": { \"name\": \"" + LEGACY_ANALYZER_COLLECTION_NAME + "\", \"isSystem\": true, \"shards\": { \"same-as-dummy-shard-id\": [ \"same-as-dummy-shard-server\" ] } } } }"); // collection ID must match id used in dropCollectionCoordinator(...) + CHECK(arangodb::AgencyComm().setValue(path, value->slice(), 0.0).successful()); + } + + // ensure legacy collection after feature start + { + REQUIRE((false == !ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); + } // simulate heartbeat thread // (create dbserver in current) required by ClusterMethods::persistCollectionInAgency(...) @@ -2992,9 +3301,9 @@ SECTION("test_upgrade_static_legacy") { } CHECK((false == !ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); - // FIXME TODO uncomment CHECK_THROWS((ci->getCollection(system->name(), ANALYZER_COLLECTION_NAME))); // throws on missing collection + CHECK_THROWS((ci->getCollection(system->name(), ANALYZER_COLLECTION_NAME))); // throws on missing collection CHECK((arangodb::methods::Upgrade::clusterBootstrap(*system).ok())); // run system upgrade - // FIXME TODO uncomment CHECK_THROWS((ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); // throws on missing collection + CHECK_THROWS((ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); // throws on missing collection CHECK((false == !ci->getCollection(system->name(), ANALYZER_COLLECTION_NAME))); for (auto& entry: clusterComm._requests) { @@ -3076,13 +3385,6 @@ SECTION("test_upgrade_static_legacy") { auto system = sysDatabase->use(); - // simulate heartbeat thread (create legacy analyzer collection before feature start) - { - auto const path = "/Plan/Collections"; - auto const value = arangodb::velocypack::Parser::fromJson(std::string("{ \"") + system->name() + "\": { \"" + LEGACY_ANALYZER_COLLECTION_NAME + "\": { \"name\": \"" + LEGACY_ANALYZER_COLLECTION_NAME + "\", \"isSystem\": true, \"shards\": { \"same-as-dummy-shard-id\": [ \"same-as-dummy-shard-server\" ] } } } }"); // collection ID must match id used in dropCollectionCoordinator(...) - CHECK(arangodb::AgencyComm().setValue(path, value->slice(), 0.0).successful()); - } - feature->start(); // register upgrade tasks server.getFeature("Cluster")->prepare(); // create ClusterInfo instance server.getFeature("Sharding")->prepare(); // required for Collections::create(...), register sharding types @@ -3093,7 +3395,17 @@ SECTION("test_upgrade_static_legacy") { auto* ci = arangodb::ClusterInfo::instance(); REQUIRE((nullptr != ci)); - CHECK((false == !ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); + // simulate heartbeat thread (create legacy analyzer collection after feature start) + { + auto const path = "/Plan/Collections"; + auto const value = arangodb::velocypack::Parser::fromJson(std::string("{ \"") + system->name() + "\": { \"" + LEGACY_ANALYZER_COLLECTION_NAME + "\": { \"name\": \"" + LEGACY_ANALYZER_COLLECTION_NAME + "\", \"isSystem\": true, \"shards\": { \"same-as-dummy-shard-id\": [ \"same-as-dummy-shard-server\" ] } } } }"); // collection ID must match id used in dropCollectionCoordinator(...) + CHECK(arangodb::AgencyComm().setValue(path, value->slice(), 0.0).successful()); + } + + // ensure legacy collection after feature start + { + REQUIRE((false == !ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); + } // simulate heartbeat thread // (create dbserver in current) required by ClusterMethods::persistCollectionInAgency(...) @@ -3107,10 +3419,10 @@ SECTION("test_upgrade_static_legacy") { auto const dbPath = "/Plan/Databases/testVocbase"; auto const dbValue = arangodb::velocypack::Parser::fromJson("null"); // value does not matter CHECK(arangodb::AgencyComm().setValue(dbPath, dbValue->slice(), 0.0).successful()); - auto const colPath0 = "/Current/Collections/_system/5000004"; // '5000004' must match what ClusterInfo generates for LogicalCollection::id() or collection creation request will never get executed (use 'collectionID' from ClusterInfo::createCollectionCoordinator(...) in stack trace) + auto const colPath0 = "/Current/Collections/_system/5000007"; // '5000007' must match what ClusterInfo generates for LogicalCollection::id() or collection creation request will never get executed (use 'collectionID' from ClusterInfo::createCollectionCoordinator(...) in stack trace) auto const colValue0 = arangodb::velocypack::Parser::fromJson("{ \"same-as-dummy-shard-id\": { \"servers\": [ \"same-as-dummy-shard-server\" ] } }"); CHECK(arangodb::AgencyComm().setValue(colPath0, colValue0->slice(), 0.0).successful()); - auto const colPath = "/Current/Collections/testVocbase/5000006"; // '5000006' must match what ClusterInfo generates for LogicalCollection::id() or collection creation request will never get executed (use 'collectionID' from ClusterInfo::createCollectionCoordinator(...) in stack trace) + auto const colPath = "/Current/Collections/testVocbase/5000009"; // '5000009' must match what ClusterInfo generates for LogicalCollection::id() or collection creation request will never get executed (use 'collectionID' from ClusterInfo::createCollectionCoordinator(...) in stack trace) auto const colValue = arangodb::velocypack::Parser::fromJson("{ \"same-as-dummy-shard-id\": { \"servers\": [ \"same-as-dummy-shard-server\" ] } }"); CHECK(arangodb::AgencyComm().setValue(colPath, colValue->slice(), 0.0).successful()); auto const dummyPath = "/Plan/Collections"; @@ -3128,10 +3440,14 @@ SECTION("test_upgrade_static_legacy") { CHECK((false == !ci->getCollection(vocbase->name(), collectionId))); // simulate heartbeat thread (create analyzer collection) + // must also include legacy collection definition otherwise it'll be removed { auto const path = "/Plan/Collections"; - auto const value = arangodb::velocypack::Parser::fromJson(std::string("{ \"") + vocbase->name() + "\": { \"5000006\": { \"name\": \"" + ANALYZER_COLLECTION_NAME + "\", \"isSystem\": true, \"shards\": { \"same-as-dummy-shard-id\": [ \"same-as-dummy-shard-server\" ] } } } }"); // must match what ClusterInfo generates for LogicalCollection::id() or shard list retrieval will fail (use 'collectionID' from ClusterInfo::getShardList(...) in stack trace) + auto const value = arangodb::velocypack::Parser::fromJson(std::string("{ \"") + system->name() + "\": { \"5000004\": { \"name\": \"" + LEGACY_ANALYZER_COLLECTION_NAME + "\", \"isSystem\": true, \"shards\": { \"same-as-dummy-shard-id\": [ \"same-as-dummy-shard-server\" ] } } }, \"" + vocbase->name() + "\": { \"5000009\": { \"name\": \"" + ANALYZER_COLLECTION_NAME + "\", \"isSystem\": true, \"shards\": { \"same-as-dummy-shard-id\": [ \"same-as-dummy-shard-server\" ] } } } }"); // must match what ClusterInfo generates for LogicalCollection::id() or shard list retrieval will fail (use 'collectionID' from ClusterInfo::getShardList(...) in stack trace) CHECK(arangodb::AgencyComm().setValue(path, value->slice(), 0.0).successful()); + auto const versionPath = "/Plan/Version"; + auto const versionValue = arangodb::velocypack::Parser::fromJson(std::to_string(ci->getPlanVersion() + 1)); + CHECK((arangodb::AgencyComm().setValue(versionPath, versionValue->slice(), 0.0).successful())); // force loadPlan() update } CHECK((false == !ci->getCollection(vocbase->name(), ANALYZER_COLLECTION_NAME))); @@ -3147,10 +3463,10 @@ SECTION("test_upgrade_static_legacy") { clusterComm._responses[0].emplace_back(std::move(response)); } - // FIXME TODO uncomment CHECK((false == !ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); + CHECK((false == !ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); CHECK_THROWS((ci->getCollection(system->name(), ANALYZER_COLLECTION_NAME))); // throws on missing collection CHECK((arangodb::methods::Upgrade::clusterBootstrap(*system).ok())); // run system upgrade - // FIXME TODO uncomment CHECK_THROWS((ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); // throws on missing collection + CHECK_THROWS((ci->getCollection(system->name(), LEGACY_ANALYZER_COLLECTION_NAME))); // throws on missing collection CHECK((false == !ci->getCollection(system->name(), ANALYZER_COLLECTION_NAME))); for (auto& entry: clusterComm._requests) { @@ -3194,7 +3510,7 @@ SECTION("test_upgrade_static_legacy") { CHECK((true == expected.empty())); } } - +*/ SECTION("test_visit") { TRI_vocbase_t system(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 0, TRI_VOC_SYSTEM_DATABASE); // create befor reseting srver diff --git a/tests/IResearch/IResearchDocument-test.cpp b/tests/IResearch/IResearchDocument-test.cpp index 083eda96c3..da7886e429 100644 --- a/tests/IResearch/IResearchDocument-test.cpp +++ b/tests/IResearch/IResearchDocument-test.cpp @@ -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(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 diff --git a/tests/IResearch/IResearchFilterBoolean-test.cpp b/tests/IResearch/IResearchFilterBoolean-test.cpp index b1c23ad85b..de966183f1 100644 --- a/tests/IResearch/IResearchFilterBoolean-test.cpp +++ b/tests/IResearch/IResearchFilterBoolean-test.cpp @@ -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 system; std::vector> 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_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(); root.boost(2.5); root.filter() - .add().field(mangleString("a.b[42].c", "test_analyzer")).term("1"); + .add().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() .filter() - .add().field(mangleString("a.b[23].c", "test_analyzer")).term("42"); + .add().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(); root.add() - .field(mangleString("a.b.c", "test_analyzer")) + .field(mangleString("a.b.c", "testVocbase::test_analyzer")) .include(false).term("1"); - root.add().field(mangleString("c.b.a", "test_analyzer")).term("2"); + root.add().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(); root.boost(0.5); root.add() - .field(mangleString("a.b.c", "test_analyzer")) + .field(mangleString("a.b.c", "testVocbase::test_analyzer")) .include(false).term("1"); - root.add().field(mangleString("c.b.a", "test_analyzer")).term("2"); + root.add().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(); root.boost(0.5); root.add() - .field(mangleString("a.b.c", "test_analyzer")) + .field(mangleString("a.b.c", "testVocbase::test_analyzer")) .include(false).term("1").boost(2.5); root.add().field(mangleStringIdentity("c.b.a")).term("2"); @@ -1447,9 +1467,9 @@ SECTION("BinaryOr") { auto& root = expected.add(); root.boost(2.5); auto& subRoot = root.add(); - subRoot.add().field(mangleString("a", "test_analyzer")).term("1").boost(0.5); + subRoot.add().field(mangleString("a", "testVocbase::test_analyzer")).term("1").boost(0.5); subRoot.add().field(mangleStringIdentity("a")).term("2"); - root.add().filter().field(mangleString("b", "test_analyzer")).term("3").boost(1.5); + root.add().filter().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(); root.boost(0.5); root.add() - .field(mangleString("a.b.c", "test_analyzer")) + .field(mangleString("a.b.c", "testVocbase::test_analyzer")) .include(false).term("1"); root.add().field(mangleStringIdentity("c.b.a")).term("2"); @@ -1947,7 +1967,7 @@ SECTION("BinaryAnd") { irs::Or expected; auto& root = expected.add(); root.add() - .field(mangleString("a.b.c", "test_analyzer")) + .field(mangleString("a.b.c", "testVocbase::test_analyzer")) .include(false).term("1").boost(0.5); root.add().field(mangleStringIdentity("c.b.a")).term("2").boost(0.5); @@ -1985,7 +2005,7 @@ SECTION("BinaryAnd") { .include(false).term("1"); root.add() .filter() - .add().field(mangleString("c.b.a", "test_analyzer")).term("2"); + .add().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(false).term("1"); root.add() .filter() - .add().field(mangleString("c.b.a", "test_analyzer")).term("2").boost(0.5); + .add().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(); range.boost(0.5); - range.field(mangleString("a.b.c", "test_analyzer")) + range.field(mangleString("a.b.c", "testVocbase::test_analyzer")) .include(true).term("15") .include(false).term("40"); @@ -2843,12 +2863,12 @@ SECTION("BinaryAnd") { irs::Or expected; auto& root = expected.add(); root.add() - .field(mangleString("a.b.c", "test_analyzer")) + .field(mangleString("a.b.c", "testVocbase::test_analyzer")) .include(true) .term("15") .boost(0.5); root.add() - .field(mangleString("a.b.c", "test_analyzer")) + .field(mangleString("a.b.c", "testVocbase::test_analyzer")) .include(true) .term("40") .boost(0.5); @@ -2862,11 +2882,11 @@ SECTION("BinaryAnd") { auto& root = expected.add(); root.boost(0.5); root.add() - .field(mangleString("a.b.c", "test_analyzer")) + .field(mangleString("a.b.c", "testVocbase::test_analyzer")) .include(true) .term("15"); root.add() - .field(mangleString("a.b.c", "test_analyzer")) + .field(mangleString("a.b.c", "testVocbase::test_analyzer")) .include(true) .term("40"); @@ -2923,7 +2943,7 @@ SECTION("BinaryAnd") { irs::Or expected; auto& range = expected.add(); 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(false).term("15") .include(true).term("40"); @@ -3048,7 +3068,7 @@ SECTION("BinaryAnd") { auto& root = expected.add(); root.boost(1.5); root.add() - .field(mangleString("a.b.c", "test_analyzer")) + .field(mangleString("a.b.c", "testVocbase::test_analyzer")) .include(true).term("15"); root.add() .field(mangleNumeric("a.b.c")) diff --git a/tests/IResearch/IResearchFilterCompare-test.cpp b/tests/IResearch/IResearchFilterCompare-test.cpp index 450529978c..70a6453b9b 100644 --- a/tests/IResearch/IResearchFilterCompare-test.cpp +++ b/tests/IResearch/IResearchFilterCompare-test.cpp @@ -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 system; std::vector> 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_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().field(mangleString("a.b[23].c", "test_analyzer")).term("1"); + expected.add().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().field(mangleString("a.b[23].c", "test_analyzer")).term("1").boost(0.5); + expected.add().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().filter().field(mangleString("a.b[23].c", "test_analyzer")).term("42").boost(42); + expected.add().filter().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() - .field(mangleString("a.b[23].c", "test_analyzer")) + .field(mangleString("a.b[23].c", "testVocbase::test_analyzer")) .include(true).term("42") .boost(42); @@ -2000,7 +2020,7 @@ SECTION("BinaryGT") { irs::Or expected; expected.add() - .field(mangleString("a.b[23].c", "test_analyzer")) + .field(mangleString("a.b[23].c", "testVocbase::test_analyzer")) .include(false).term("42") .boost(42); @@ -2591,7 +2611,7 @@ SECTION("BinaryLE") { irs::Or expected; expected.add() - .field(mangleString("a.b[23].c", "test_analyzer")) + .field(mangleString("a.b[23].c", "testVocbase::test_analyzer")) .include(true).term("42") .boost(42); @@ -3166,7 +3186,7 @@ SECTION("BinaryLT") { irs::Or expected; expected.add() - .field(mangleString("a.b[23].c", "test_analyzer")) + .field(mangleString("a.b[23].c", "testVocbase::test_analyzer")) .include(false).term("42") .boost(42); diff --git a/tests/IResearch/IResearchFilterFunction-test.cpp b/tests/IResearch/IResearchFilterFunction-test.cpp index d7888f2c04..40e357852d 100644 --- a/tests/IResearch/IResearchFilterFunction-test.cpp +++ b/tests/IResearch/IResearchFilterFunction-test.cpp @@ -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 system; std::vector> 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_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().field(mangleString("foo", "test_analyzer")).term("bar"); + expected.add().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().field(mangleString("foo", "test_analyzer")).term("bar"); + expected.add().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(); - 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(); - 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(); - 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(); - 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(); - 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(); - 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(); - 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(); - 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(); - 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(); - 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(); - 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(); - 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(); - 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(); - 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(); - 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(); - 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); diff --git a/tests/IResearch/IResearchFilterIn-test.cpp b/tests/IResearch/IResearchFilterIn-test.cpp index ca5bf5c4c0..6bafeebc29 100644 --- a/tests/IResearch/IResearchFilterIn-test.cpp +++ b/tests/IResearch/IResearchFilterIn-test.cpp @@ -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 system; std::vector> 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_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(); - root.add().field(mangleString("a.b.c[412].e.f", "test_analyzer")).term("1"); - root.add().field(mangleString("a.b.c[412].e.f", "test_analyzer")).term("2"); - root.add().field(mangleString("a.b.c[412].e.f", "test_analyzer")).term("3"); + root.add().field(mangleString("a.b.c[412].e.f", "testVocbase::test_analyzer")).term("1"); + root.add().field(mangleString("a.b.c[412].e.f", "testVocbase::test_analyzer")).term("2"); + root.add().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(); root.boost(2.5); - root.add().field(mangleString("a.b.c[412].e.f", "test_analyzer")).term("1"); - root.add().field(mangleString("a.b.c[412].e.f", "test_analyzer")).term("2"); - root.add().field(mangleString("a.b.c[412].e.f", "test_analyzer")).term("3"); + root.add().field(mangleString("a.b.c[412].e.f", "testVocbase::test_analyzer")).term("1"); + root.add().field(mangleString("a.b.c[412].e.f", "testVocbase::test_analyzer")).term("2"); + root.add().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(); - root.add().field(mangleString("quick.brown.fox", "test_analyzer")).term("1"); + root.add().field(mangleString("quick.brown.fox", "testVocbase::test_analyzer")).term("1"); root.add().field(mangleNull("quick.brown.fox")).term(irs::null_token_stream::value_null()); root.add().field(mangleBool("quick.brown.fox")).term(irs::boolean_token_stream::value_true()); root.add().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(); root.boost(1.5); - root.add().field(mangleString("quick.brown.fox", "test_analyzer")).term("1"); + root.add().field(mangleString("quick.brown.fox", "testVocbase::test_analyzer")).term("1"); root.add().field(mangleNull("quick.brown.fox")).term(irs::null_token_stream::value_null()); root.add().field(mangleBool("quick.brown.fox")).term(irs::boolean_token_stream::value_true()); root.add().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(); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1"); + root.add().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1"); root.add().field(mangleNumeric("a.b.c.e.f")).term(term->value()); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("3"); + root.add().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(); root.boost(1.5); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1"); + root.add().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1"); root.add().field(mangleNumeric("a.b.c.e.f")).term(term->value()); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("3"); + root.add().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(); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1"); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("str"); + root.add().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1"); + root.add().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("str"); root.add().field(mangleBool("a.b.c.e.f")).term(irs::boolean_token_stream::value_false()); root.add().field(mangleNumeric("a.b.c.e.f")).term(term->value()); root.add().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(); root.boost(2.5); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1"); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("str"); + root.add().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1"); + root.add().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("str"); root.add().field(mangleBool("a.b.c.e.f")).term(irs::boolean_token_stream::value_false()); root.add().field(mangleNumeric("a.b.c.e.f")).term(term->value()); root.add().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().filter(); - root.add().field(mangleString("a.b.c[323].e.f", "test_analyzer")).term("1"); - root.add().field(mangleString("a.b.c[323].e.f", "test_analyzer")).term("2"); - root.add().field(mangleString("a.b.c[323].e.f", "test_analyzer")).term("3"); + root.add().field(mangleString("a.b.c[323].e.f", "testVocbase::test_analyzer")).term("1"); + root.add().field(mangleString("a.b.c[323].e.f", "testVocbase::test_analyzer")).term("2"); + root.add().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().filter(); root.boost(2.5); - root.add().field(mangleString("a.b.c[323].e.f", "test_analyzer")).term("1"); - root.add().field(mangleString("a.b.c[323].e.f", "test_analyzer")).term("2"); - root.add().field(mangleString("a.b.c[323].e.f", "test_analyzer")).term("3"); + root.add().field(mangleString("a.b.c[323].e.f", "testVocbase::test_analyzer")).term("1"); + root.add().field(mangleString("a.b.c[323].e.f", "testVocbase::test_analyzer")).term("2"); + root.add().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().filter(); - root.add().field(mangleString("quick.brown.fox", "test_analyzer")).term("1"); + root.add().field(mangleString("quick.brown.fox", "testVocbase::test_analyzer")).term("1"); root.add().field(mangleNull("quick.brown.fox")).term(irs::null_token_stream::value_null()); root.add().field(mangleBool("quick.brown.fox")).term(irs::boolean_token_stream::value_true()); root.add().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().filter(); root.boost(1.5); - root.add().field(mangleString("quick.brown.fox", "test_analyzer")).term("1"); + root.add().field(mangleString("quick.brown.fox", "testVocbase::test_analyzer")).term("1"); root.add().field(mangleNull("quick.brown.fox")).term(irs::null_token_stream::value_null()); root.add().field(mangleBool("quick.brown.fox")).term(irs::boolean_token_stream::value_true()); root.add().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().filter(); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1"); + root.add().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1"); root.add().field(mangleNumeric("a.b.c.e.f")).term(term->value()); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("3"); + root.add().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().filter(); root.boost(3.5); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1"); + root.add().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1"); root.add().field(mangleNumeric("a.b.c.e.f")).term(term->value()); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("3"); + root.add().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().filter(); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1"); + root.add().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1"); root.add().field(mangleNumeric("a.b.c.e.f")).term(term->value()); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("3"); + root.add().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().filter(); root.boost(1.5); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("1"); + root.add().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("1"); root.add().field(mangleNumeric("a.b.c.e.f")).term(term->value()); - root.add().field(mangleString("a.b.c.e.f", "test_analyzer")).term("3"); + root.add().field(mangleString("a.b.c.e.f", "testVocbase::test_analyzer")).term("3"); // not a constant in array assertFilterSuccess( diff --git a/tests/IResearch/IResearchIndex-test.cpp b/tests/IResearch/IResearchIndex-test.cpp index f2010eabae..73fdc89ab8 100644 --- a/tests/IResearch/IResearchIndex-test.cpp +++ b/tests/IResearch/IResearchIndex-test.cpp @@ -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 system; std::vector> 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_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("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; } }; diff --git a/tests/IResearch/IResearchLink-test.cpp b/tests/IResearch/IResearchLink-test.cpp index 1b6e0cae22..f514a0ff36 100644 --- a/tests/IResearch/IResearchLink-test.cpp +++ b/tests/IResearch/IResearchLink-test.cpp @@ -76,7 +76,6 @@ struct IResearchLinkSetup { StorageEngineMock engine; arangodb::application_features::ApplicationServer server; - std::unique_ptr system; std::vector> 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_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("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()->unprepare(); // release system database before reseting the 'ENGINE' TRI_RemoveDirectory(testFilesystemPath.c_str()); arangodb::LogTopic::setLogLevel(arangodb::iresearch::TOPIC.name(), arangodb::LogLevel::DEFAULT); diff --git a/tests/IResearch/IResearchLinkHelper-test.cpp b/tests/IResearch/IResearchLinkHelper-test.cpp index 37e929e42a..aa0ff8931c 100644 --- a/tests/IResearch/IResearchLinkHelper-test.cpp +++ b/tests/IResearch/IResearchLinkHelper-test.cpp @@ -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("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 diff --git a/tests/IResearch/IResearchLinkMeta-test.cpp b/tests/IResearch/IResearchLinkMeta-test.cpp index fd39270e9a..9d43c5f14d 100644 --- a/tests/IResearch/IResearchLinkMeta-test.cpp +++ b/tests/IResearch/IResearchLinkMeta-test.cpp @@ -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; diff --git a/tests/IResearch/IResearchQueryAnd-test.cpp b/tests/IResearch/IResearchQueryAnd-test.cpp index f8157a3804..08a8bae4be 100644 --- a/tests/IResearch/IResearchQueryAnd-test.cpp +++ b/tests/IResearch/IResearchQueryAnd-test.cpp @@ -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 system; std::vector> 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_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("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 diff --git a/tests/IResearch/IResearchQueryComplexBoolean-test.cpp b/tests/IResearch/IResearchQueryComplexBoolean-test.cpp index 9bfe8bbbd1..e2e662fb01 100644 --- a/tests/IResearch/IResearchQueryComplexBoolean-test.cpp +++ b/tests/IResearch/IResearchQueryComplexBoolean-test.cpp @@ -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 system; std::vector> 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_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 diff --git a/tests/IResearch/IResearchQueryExists-test.cpp b/tests/IResearch/IResearchQueryExists-test.cpp index e1af8be063..8437047fbc 100644 --- a/tests/IResearch/IResearchQueryExists-test.cpp +++ b/tests/IResearch/IResearchQueryExists-test.cpp @@ -82,7 +82,6 @@ namespace { struct IResearchQueryExistsSetup { StorageEngineMock engine; arangodb::application_features::ApplicationServer server; - std::unique_ptr system; std::vector> 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_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("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 insertedDocs; arangodb::LogicalView* view; diff --git a/tests/IResearch/IResearchQueryJoin-test.cpp b/tests/IResearch/IResearchQueryJoin-test.cpp index 6eba20ac54..582b64e87c 100644 --- a/tests/IResearch/IResearchQueryJoin-test.cpp +++ b/tests/IResearch/IResearchQueryJoin-test.cpp @@ -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 system; std::vector> 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_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("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 diff --git a/tests/IResearch/IResearchQueryOr-test.cpp b/tests/IResearch/IResearchQueryOr-test.cpp index 1a6f3ff11a..d8c34428b1 100644 --- a/tests/IResearch/IResearchQueryOr-test.cpp +++ b/tests/IResearch/IResearchQueryOr-test.cpp @@ -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 system; std::vector> 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_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 diff --git a/tests/IResearch/IResearchQueryPhrase-test.cpp b/tests/IResearch/IResearchQueryPhrase-test.cpp index 271be70fb8..7c13cea41e 100644 --- a/tests/IResearch/IResearchQueryPhrase-test.cpp +++ b/tests/IResearch/IResearchQueryPhrase-test.cpp @@ -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 system; std::vector> 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_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 diff --git a/tests/IResearch/IResearchQueryScorer-test.cpp b/tests/IResearch/IResearchQueryScorer-test.cpp index 78effae2e6..1314139a7c 100644 --- a/tests/IResearch/IResearchQueryScorer-test.cpp +++ b/tests/IResearch/IResearchQueryScorer-test.cpp @@ -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 system; std::vector> 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_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("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 diff --git a/tests/IResearch/IResearchQueryTokens-test.cpp b/tests/IResearch/IResearchQueryTokens-test.cpp index 41fe82ba34..cae290f093 100644 --- a/tests/IResearch/IResearchQueryTokens-test.cpp +++ b/tests/IResearch/IResearchQueryTokens-test.cpp @@ -88,7 +88,6 @@ extern const char* ARGV0; // defined in main.cpp struct IResearchQueryTokensSetup { StorageEngineMock engine; arangodb::application_features::ApplicationServer server; - std::unique_ptr system; std::vector> 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_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("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); diff --git a/tests/IResearch/common.cpp b/tests/IResearch/common.cpp index 9ea362a3d4..d586ee83c5 100644 --- a/tests/IResearch/common.cpp +++ b/tests/IResearch/common.cpp @@ -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))); }