mirror of https://gitee.com/bigwinds/arangodb
* Porting fix for issue #9652 * Update CHANGELOG
This commit is contained in:
parent
b753c895e4
commit
5effbfd35a
|
@ -658,10 +658,19 @@ bool make_json_config(
|
|||
if(!options.explicit_stopwords.empty() || options.explicit_stopwords_set) {
|
||||
// explicit_stopwords_set marks that even empty stopwords list is valid
|
||||
rapidjson::Value stopwordsArray(rapidjson::kArrayType);
|
||||
for (const auto& stopword : options.explicit_stopwords) {
|
||||
stopwordsArray.PushBack(
|
||||
rapidjson::StringRef(stopword.c_str(), stopword.size()),
|
||||
allocator);
|
||||
if (!options.explicit_stopwords.empty()) {
|
||||
// for simplifying comparsion between properties we need deterministic order of stopwords
|
||||
std::vector<irs::string_ref> sortedWords;
|
||||
sortedWords.reserve(options.explicit_stopwords.size());
|
||||
for (const auto& stopword : options.explicit_stopwords) {
|
||||
sortedWords.emplace_back(stopword);
|
||||
}
|
||||
std::sort(sortedWords.begin(), sortedWords.end());
|
||||
for (const auto& stopword : sortedWords) {
|
||||
stopwordsArray.PushBack(
|
||||
rapidjson::StringRef(stopword.c_str(), stopword.size()),
|
||||
allocator);
|
||||
}
|
||||
}
|
||||
|
||||
json.AddMember(
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
v3.5.1 (XXXX-XX-XX)
|
||||
-------------------
|
||||
|
||||
* Fixed issue #9652: fix ArangoSearch wrong name collision and raising
|
||||
"Name collision detected" error during creation of a custom analyzer with
|
||||
stopwords.
|
||||
|
||||
* Fixed an agency bug found in Windows tests.
|
||||
|
||||
* Added initial support for wgs84 reference ellipsoid in GEO_DISTANCE through
|
||||
|
|
|
@ -522,11 +522,34 @@ bool equalAnalyzer(
|
|||
return false;
|
||||
}
|
||||
|
||||
return type == pool.type() // same type
|
||||
&& 0 == arangodb::basics::VelocyPackHelper::compare(
|
||||
arangodb::iresearch::slice(normalizedProperties),
|
||||
pool.properties(), false) // same properties
|
||||
&& features == pool.features(); // same features
|
||||
// first check non-normalizeable portion of analyzer definition
|
||||
// to rule out need to check normalization of properties
|
||||
if (type != pool.type() || features != pool.features()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// this check is not final as old-normalized definition may be present in database!
|
||||
if (arangodb::basics::VelocyPackHelper::equal(arangodb::iresearch::slice(normalizedProperties),
|
||||
pool.properties(), false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Here could be analyzer definition with old-normalized properties (see Issue #9652)
|
||||
// To make sure properties really differ, let`s re-normalize and re-check
|
||||
std::string reNormalizedProperties;
|
||||
if (ADB_UNLIKELY(!::normalize(reNormalizedProperties, pool.type(), pool.properties()))) {
|
||||
// failed to re-normalize definition - strange. It was already normalized once.
|
||||
// Some bug in load/store?
|
||||
TRI_ASSERT(FALSE);
|
||||
LOG_TOPIC("a4073", WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failed to re-normalize properties for analyzer type '"
|
||||
<< pool.type()
|
||||
<< "' properties '" << pool.properties().toString() << "'";
|
||||
return false;
|
||||
}
|
||||
return arangodb::basics::VelocyPackHelper::equal(
|
||||
arangodb::iresearch::slice(normalizedProperties),
|
||||
arangodb::iresearch::slice(reNormalizedProperties), false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -670,34 +693,6 @@ void registerUpgradeTasks() {
|
|||
});
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief split the analyzer name into the vocbase part and analyzer part
|
||||
/// @param name analyzer name
|
||||
/// @return pair of first == vocbase name, second == analyzer name
|
||||
/// EMPTY == system vocbase
|
||||
/// NIL == unprefixed analyzer name, i.e. active vocbase
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::pair<irs::string_ref, irs::string_ref> splitAnalyzerName( // split name
|
||||
irs::string_ref const& analyzer // analyzer name
|
||||
) noexcept {
|
||||
// search for vocbase prefix ending with '::'
|
||||
for (size_t i = 1, count = analyzer.size(); i < count; ++i) {
|
||||
if (analyzer[i] == ANALYZER_PREFIX_DELIM // current is delim
|
||||
&& analyzer[i - 1] == ANALYZER_PREFIX_DELIM) { // previous is also delim
|
||||
auto vocbase = i > 1 // non-empty prefix, +1 for first delimiter char
|
||||
? irs::string_ref(analyzer.c_str(), i - 1) // -1 for the first ':' delimiter
|
||||
: irs::string_ref::EMPTY;
|
||||
auto name = i < count - 1 // have suffix
|
||||
? irs::string_ref(analyzer.c_str() + i + 1, count - i - 1) // +-1 for the suffix after '::'
|
||||
: irs::string_ref::EMPTY; // do not point after end of buffer
|
||||
|
||||
return std::make_pair(vocbase, name); // prefixed analyzer name
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(irs::string_ref::NIL, analyzer); // unprefixed analyzer name
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief read analyzers from vocbase
|
||||
/// @return visitation completed fully
|
||||
|
@ -1971,6 +1966,49 @@ arangodb::Result IResearchAnalyzerFeature::loadAnalyzers(
|
|||
return FEATURE_NAME;
|
||||
}
|
||||
|
||||
/*static*/ irs::string_ref IResearchAnalyzerFeature::extractVocbaseName(
|
||||
irs::string_ref const& name) noexcept {// analyzer name (normalized)
|
||||
auto split = splitAnalyzerName(name);
|
||||
return split.first;
|
||||
}
|
||||
|
||||
/*static*/ bool IResearchAnalyzerFeature::analyzerReachableFromDb(
|
||||
irs::string_ref const& dbNameFromAnalyzer,
|
||||
irs::string_ref const& currentDbName, bool forGetters) noexcept {
|
||||
TRI_ASSERT(!currentDbName.empty());
|
||||
if (dbNameFromAnalyzer.null()) { // NULL means local db name = always reachable
|
||||
return true;
|
||||
}
|
||||
if (dbNameFromAnalyzer.empty()) { // empty name with :: means always system
|
||||
if (forGetters) {
|
||||
return true; // system database is always accessible for reading analyzer from any other db
|
||||
}
|
||||
return currentDbName == arangodb::StaticStrings::SystemDatabase;
|
||||
}
|
||||
return currentDbName == dbNameFromAnalyzer ||
|
||||
(forGetters && dbNameFromAnalyzer == arangodb::StaticStrings::SystemDatabase);
|
||||
}
|
||||
|
||||
/*static*/ std::pair<irs::string_ref, irs::string_ref> IResearchAnalyzerFeature::splitAnalyzerName(
|
||||
irs::string_ref const& analyzer) noexcept {
|
||||
// search for vocbase prefix ending with '::'
|
||||
for (size_t i = 1, count = analyzer.size(); i < count; ++i) {
|
||||
if (analyzer[i] == ANALYZER_PREFIX_DELIM // current is delim
|
||||
&& analyzer[i - 1] == ANALYZER_PREFIX_DELIM) { // previous is also delim
|
||||
auto vocbase = i > 1 // non-empty prefix, +1 for first delimiter char
|
||||
? irs::string_ref(analyzer.c_str(), i - 1) // -1 for the first ':' delimiter
|
||||
: irs::string_ref::EMPTY;
|
||||
auto name = i < count - 1 // have suffix
|
||||
? irs::string_ref(analyzer.c_str() + i + 1, count - i - 1) // +-1 for the suffix after '::'
|
||||
: irs::string_ref::EMPTY; // do not point after end of buffer
|
||||
|
||||
return std::make_pair(vocbase, name); // prefixed analyzer name
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(irs::string_ref::NIL, analyzer); // unprefixed analyzer name
|
||||
}
|
||||
|
||||
/*static*/ std::string IResearchAnalyzerFeature::normalize( // normalize name
|
||||
irs::string_ref const& name, // analyzer name
|
||||
TRI_vocbase_t const& activeVocbase, // fallback vocbase if not part of name
|
||||
|
@ -2055,7 +2093,6 @@ arangodb::Result IResearchAnalyzerFeature::remove( // remove analyzer
|
|||
// 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)+ "'"
|
||||
|
@ -2195,7 +2232,18 @@ void IResearchAnalyzerFeature::start() {
|
|||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE
|
||||
// sanity check: we rely on this condition is true internally
|
||||
{
|
||||
auto sysDbFeature =
|
||||
arangodb::application_features::ApplicationServer::lookupFeature<arangodb::SystemDatabaseFeature>(
|
||||
"SystemDatabase");
|
||||
if (sysDbFeature && sysDbFeature->use()) { // feature/db may be absent in some unit-test enviroment
|
||||
TRI_ASSERT(sysDbFeature->use()->name() == arangodb::StaticStrings::SystemDatabase);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// register analyzer functions
|
||||
{
|
||||
auto* functions =
|
||||
|
|
|
@ -200,6 +200,36 @@ class IResearchAnalyzerFeature final : public arangodb::application_features::Ap
|
|||
bool expandVocbasePrefix = true // use full vocbase name as prefix for active/system v.s. EMPTY/'::'
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @param name analyzer name (normalized)
|
||||
/// @return vocbase prefix extracted from normalized analyzer name
|
||||
/// EMPTY == system vocbase
|
||||
/// NIL == analyzer name have had no db name prefix
|
||||
/// @see analyzerReachableFromDb
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static irs::string_ref extractVocbaseName(irs::string_ref const& name) noexcept;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// Checks if analyzer db (identified by db name prefix extracted from analyzer
|
||||
/// name) could be reached from specified db.
|
||||
/// Properly handles special cases (e.g. NIL and EMPTY)
|
||||
/// @param dbNameFromAnalyzer database name extracted from analyzer name
|
||||
/// @param currentDbName database name to check against (should not be empty!)
|
||||
/// @param forGetters check special case for getting analyzer (not creating/removing)
|
||||
/// @return true if analyzer is reachable
|
||||
static bool analyzerReachableFromDb(irs::string_ref const& dbNameFromAnalyzer,
|
||||
irs::string_ref const& currentDbName,
|
||||
bool forGetters = false) noexcept;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief split the analyzer name into the vocbase part and analyzer part
|
||||
/// @param name analyzer name
|
||||
/// @return pair of first == vocbase name, second == analyzer name
|
||||
/// EMPTY == system vocbase
|
||||
/// NIL == unprefixed analyzer name, i.e. active vocbase
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static std::pair<irs::string_ref, irs::string_ref> splitAnalyzerName(irs::string_ref const& analyzer) noexcept;
|
||||
|
||||
void prepare() override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -776,14 +776,33 @@ namespace iresearch {
|
|||
IResearchLinkMeta meta;
|
||||
std::string errorField;
|
||||
|
||||
if (!linkDefinition.isNull() // have link definition
|
||||
&& !meta.init(linkDefinition, false, errorField, &vocbase)) { // for db-server analyzer validation should have already applied on coordinator
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
errorField.empty()
|
||||
? (std::string("while validating arangosearch link definition, error: invalid link definition for collection '") + collectionName.copyString() + "': " + linkDefinition.toString())
|
||||
: (std::string("while validating arangosearch link definition, error: invalid link definition for collection '") + collectionName.copyString() + "' error in attribute: " + errorField)
|
||||
);
|
||||
if (!linkDefinition.isNull()) { // have link definition
|
||||
if (!meta.init(linkDefinition, false, errorField, &vocbase)) { // for db-server analyzer validation should have already applied on coordinator
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
errorField.empty()
|
||||
? (std::string("while validating arangosearch link definition, error: invalid link definition for collection '") + collectionName.copyString() + "': " + linkDefinition.toString())
|
||||
: (std::string("while validating arangosearch link definition, error: invalid link definition for collection '") + collectionName.copyString() + "' error in attribute: " + errorField)
|
||||
);
|
||||
}
|
||||
// validate analyzers origin
|
||||
// analyzer should be either from same database as view (and collection) or from system database
|
||||
{
|
||||
const auto& currentVocbase = vocbase.name();
|
||||
for (const auto& analyzer : meta._analyzers) {
|
||||
TRI_ASSERT(analyzer._pool); // should be checked in meta init
|
||||
if (ADB_UNLIKELY(!analyzer._pool)) {
|
||||
continue;
|
||||
}
|
||||
auto analyzerVocbase = IResearchAnalyzerFeature::extractVocbaseName(analyzer._pool->name());
|
||||
if (!IResearchAnalyzerFeature::analyzerReachableFromDb(analyzerVocbase, currentVocbase, true)) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("Analyzer '").append(analyzer._pool->name())
|
||||
.append("' is not accessible from database '").append(currentVocbase).append("'"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,14 +28,12 @@
|
|||
#include "analysis/token_attributes.hpp"
|
||||
#include "utils/hash_utils.hpp"
|
||||
#include "utils/locale_utils.hpp"
|
||||
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "Cluster/ServerState.h"
|
||||
#include "RestServer/SystemDatabaseFeature.h"
|
||||
#include "VelocyPackHelper.h"
|
||||
#include "velocypack/Builder.h"
|
||||
#include "velocypack/Iterator.h"
|
||||
|
||||
#include "IResearchLinkMeta.h"
|
||||
#include "Misc.h"
|
||||
|
||||
|
@ -318,7 +316,6 @@ bool IResearchLinkMeta::init( // initialize meta
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get analyzer potentially creating it (e.g. on cluster)
|
||||
// @note do not use emplace(...) since it'll trigger loadAnalyzers(...)
|
||||
if (!analyzers->get(name, type, properties, features)) {
|
||||
|
|
|
@ -35,23 +35,21 @@
|
|||
namespace arangodb {
|
||||
namespace iresearch {
|
||||
|
||||
RestAnalyzerHandler::RestAnalyzerHandler( // constructor
|
||||
arangodb::GeneralRequest* request, // request
|
||||
arangodb::GeneralResponse* response // response
|
||||
RestAnalyzerHandler::RestAnalyzerHandler(
|
||||
arangodb::GeneralRequest* request,
|
||||
arangodb::GeneralResponse* response
|
||||
): RestVocbaseBaseHandler(request, response) {
|
||||
}
|
||||
|
||||
void RestAnalyzerHandler::createAnalyzer( // create
|
||||
IResearchAnalyzerFeature& analyzers, // analyzer feature
|
||||
TRI_vocbase_t const* sysVocbase // system vocbase
|
||||
IResearchAnalyzerFeature& analyzers
|
||||
) {
|
||||
TRI_ASSERT(_request); // ensured by execute()
|
||||
|
||||
if (_request->payload().isEmptyObject()) {
|
||||
generateError( // generate error
|
||||
arangodb::rest::ResponseCode::BAD, TRI_ERROR_HTTP_CORRUPTED_JSON // args
|
||||
generateError(
|
||||
arangodb::rest::ResponseCode::BAD, TRI_ERROR_HTTP_CORRUPTED_JSON
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -63,8 +61,8 @@ void RestAnalyzerHandler::createAnalyzer( // create
|
|||
}
|
||||
|
||||
if (!body.isObject()) {
|
||||
generateError(arangodb::Result( // generate error
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
"expecting body to be of the form { name: <string>, type: <string>[, properties: <object|string>[, features: <string-array>]] }"
|
||||
));
|
||||
|
||||
|
@ -75,26 +73,35 @@ void RestAnalyzerHandler::createAnalyzer( // create
|
|||
auto nameSlice = body.get(StaticStrings::AnalyzerNameField);
|
||||
|
||||
if (!nameSlice.isString()) {
|
||||
generateError(arangodb::Result( // generate error
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
"invalid 'name', expecting body to be of the form { name: <string>, type: <string>[, properties: <object|string>[, features: <string-array>]] }"
|
||||
));
|
||||
|
||||
return;
|
||||
}
|
||||
auto splittedAnalyzerName = IResearchAnalyzerFeature::splitAnalyzerName(getStringRef(nameSlice));
|
||||
if (!IResearchAnalyzerFeature::analyzerReachableFromDb(splittedAnalyzerName.first,
|
||||
_vocbase.name())) {
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_FORBIDDEN,
|
||||
"Database in analyzer name does not match current database"));
|
||||
return;
|
||||
}
|
||||
|
||||
name = getStringRef(nameSlice);
|
||||
|
||||
name = splittedAnalyzerName.second;
|
||||
if (!TRI_vocbase_t::IsAllowedName(false, velocypack::StringRef(name.c_str(), name.size()))) {
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
"invalid characters in analyzer name '" + static_cast<std::string>(name) + "'"
|
||||
));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::string nameBuf;
|
||||
auto* sysDatabase =
|
||||
arangodb::application_features::ApplicationServer::lookupFeature<arangodb::SystemDatabaseFeature>();
|
||||
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
|
||||
if (sysVocbase) {
|
||||
nameBuf = IResearchAnalyzerFeature::normalize(name, _vocbase, *sysVocbase); // normalize
|
||||
name = nameBuf;
|
||||
|
@ -104,8 +111,8 @@ void RestAnalyzerHandler::createAnalyzer( // create
|
|||
auto typeSlice = body.get(StaticStrings::AnalyzerTypeField);
|
||||
|
||||
if (!typeSlice.isString()) {
|
||||
generateError(arangodb::Result( // generate error
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
"invalid 'type', expecting body to be of the form { name: <string>, type: <string>[, properties: <object|string>[, features: <string-array>]] }"
|
||||
));
|
||||
|
||||
|
@ -123,8 +130,8 @@ void RestAnalyzerHandler::createAnalyzer( // create
|
|||
}
|
||||
|
||||
if (!properties.isNone() && !properties.isObject()) { // optional parameter
|
||||
generateError(arangodb::Result( // generate error
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
"invalid 'properties', expecting body to be of the form { name: <string>, type: <string>[, properties: <object>[, features: <string-array>]] }"
|
||||
));
|
||||
return;
|
||||
|
@ -143,8 +150,8 @@ void RestAnalyzerHandler::createAnalyzer( // create
|
|||
auto value = *itr;
|
||||
|
||||
if (!value.isString()) {
|
||||
generateError(arangodb::Result( // generate error
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
"invalid value in 'features', expecting body to be of the form { name: <string>, type: <string>[, properties: <object>[, features: <string-array>]] }"
|
||||
));
|
||||
|
||||
|
@ -154,8 +161,8 @@ void RestAnalyzerHandler::createAnalyzer( // create
|
|||
auto* feature = irs::attribute::type_id::get(getStringRef(value));
|
||||
|
||||
if (!feature) {
|
||||
generateError(arangodb::Result( // generate error
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
"unknown value in 'features', expecting body to be of the form { name: <string>, type: <string>[, properties: <object>[, features: <string-array>]] }"
|
||||
));
|
||||
|
||||
|
@ -165,8 +172,8 @@ void RestAnalyzerHandler::createAnalyzer( // create
|
|||
features.add(*feature);
|
||||
}
|
||||
} else {
|
||||
generateError(arangodb::Result( // generate error
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
"invalid 'features', expecting body to be of the form { name: <string>, type: <string>[, properties: <object>[, features: <string-array>]] }"
|
||||
));
|
||||
|
||||
|
@ -179,12 +186,11 @@ void RestAnalyzerHandler::createAnalyzer( // create
|
|||
// ...........................................................................
|
||||
|
||||
if (!IResearchAnalyzerFeature::canUse(name, auth::Level::RW)) {
|
||||
generateError( // generate error
|
||||
arangodb::rest::ResponseCode::FORBIDDEN, // HTTP code
|
||||
TRI_ERROR_FORBIDDEN, // code
|
||||
std::string("insufficient rights while creating analyzer: ") + body.toString() // message
|
||||
generateError(
|
||||
arangodb::rest::ResponseCode::FORBIDDEN,
|
||||
TRI_ERROR_FORBIDDEN,
|
||||
std::string("insufficient rights while creating analyzer: ") + body.toString()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -198,12 +204,11 @@ void RestAnalyzerHandler::createAnalyzer( // create
|
|||
}
|
||||
|
||||
if (!result.first) {
|
||||
generateError( // generate error
|
||||
arangodb::rest::ResponseCode::BAD, // HTTP code
|
||||
TRI_errno(), // code
|
||||
std::string("failure while creating analyzer: ") + body.toString() // message
|
||||
generateError(
|
||||
arangodb::rest::ResponseCode::BAD,
|
||||
TRI_errno(),
|
||||
std::string("failure while creating analyzer: ") + body.toString()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -212,7 +217,7 @@ void RestAnalyzerHandler::createAnalyzer( // create
|
|||
|
||||
pool->toVelocyPack(builder);
|
||||
|
||||
generateResult( // generate result
|
||||
generateResult(
|
||||
result.second // new analyzer v.s. existing analyzer
|
||||
? arangodb::rest::ResponseCode::CREATED : arangodb::rest::ResponseCode::OK,
|
||||
builder.slice() // analyzer definition
|
||||
|
@ -220,146 +225,116 @@ void RestAnalyzerHandler::createAnalyzer( // create
|
|||
}
|
||||
|
||||
arangodb::RestStatus RestAnalyzerHandler::execute() {
|
||||
auto* analyzers = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
|
||||
IResearchAnalyzerFeature // feature type
|
||||
>();
|
||||
|
||||
if (!analyzers) {
|
||||
generateError( // generate error
|
||||
arangodb::rest::ResponseCode::BAD, // HTTP code
|
||||
TRI_ERROR_INTERNAL, // code
|
||||
std::string("failure to find feature '") + IResearchAnalyzerFeature::name() + "' while executing REST request for: " + ANALYZER_PATH
|
||||
);
|
||||
|
||||
return arangodb::RestStatus::DONE;
|
||||
}
|
||||
|
||||
auto* sysDatabase = arangodb::application_features::ApplicationServer::lookupFeature< // find feature
|
||||
arangodb::SystemDatabaseFeature // featue type
|
||||
>();
|
||||
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
|
||||
|
||||
if (!_request) {
|
||||
generateError( // generate error
|
||||
arangodb::rest::ResponseCode::METHOD_NOT_ALLOWED, // HTTP code
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER // error code
|
||||
generateError(
|
||||
arangodb::rest::ResponseCode::METHOD_NOT_ALLOWED,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER
|
||||
);
|
||||
|
||||
return arangodb::RestStatus::DONE;
|
||||
}
|
||||
|
||||
auto* analyzers =
|
||||
arangodb::application_features::ApplicationServer::getFeature<IResearchAnalyzerFeature>();
|
||||
|
||||
auto& suffixes = _request->suffixes();
|
||||
|
||||
switch (_request->requestType()) {
|
||||
case arangodb::rest::RequestType::DELETE_REQ:
|
||||
if (suffixes.size() == 1) {
|
||||
auto name = arangodb::basics::StringUtils::urlDecode(suffixes[0]);
|
||||
|
||||
if (!sysVocbase) {
|
||||
removeAnalyzer(*analyzers, name); // verbatim (assume already normalized)
|
||||
|
||||
return arangodb::RestStatus::DONE;
|
||||
}
|
||||
|
||||
removeAnalyzer( // remove
|
||||
*analyzers, // feature
|
||||
IResearchAnalyzerFeature::normalize(name, _vocbase, *sysVocbase) // normalize
|
||||
);
|
||||
|
||||
auto force = _request->parsedValue("force", false);
|
||||
removeAnalyzer(*analyzers, name, force);
|
||||
return arangodb::RestStatus::DONE;
|
||||
}
|
||||
|
||||
generateError( // generate error
|
||||
arangodb::rest::ResponseCode::BAD, // HTTP code
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
std::string("expecting DELETE ") + ANALYZER_PATH + "/<analyzer-name>[?force=true]" // mesage
|
||||
generateError(
|
||||
arangodb::rest::ResponseCode::BAD,
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("expecting DELETE ").append(ANALYZER_PATH).append("/<analyzer-name>[?force=true]")
|
||||
);
|
||||
|
||||
return arangodb::RestStatus::DONE;
|
||||
|
||||
case arangodb::rest::RequestType::GET:
|
||||
if (suffixes.empty()) {
|
||||
getAnalyzers(*analyzers);
|
||||
|
||||
return arangodb::RestStatus::DONE;
|
||||
}
|
||||
|
||||
if (suffixes.size() == 1) {
|
||||
auto name = arangodb::basics::StringUtils::urlDecode(suffixes[0]);
|
||||
|
||||
if (!sysVocbase) {
|
||||
getAnalyzer(*analyzers, name);
|
||||
|
||||
return arangodb::RestStatus::DONE;
|
||||
}
|
||||
|
||||
getAnalyzer( // get
|
||||
*analyzers, // feature
|
||||
IResearchAnalyzerFeature::normalize(name, _vocbase, *sysVocbase) // normalize
|
||||
);
|
||||
|
||||
getAnalyzer(*analyzers, name);
|
||||
return arangodb::RestStatus::DONE;
|
||||
}
|
||||
|
||||
generateError(arangodb::Result( // generate error
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
std::string("expecting GET ") + ANALYZER_PATH + "[/<analyzer-name>]" // mesage
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("expecting GET ").append(ANALYZER_PATH).append("[/<analyzer-name>]")
|
||||
));
|
||||
|
||||
return arangodb::RestStatus::DONE;
|
||||
|
||||
case arangodb::rest::RequestType::POST:
|
||||
if (suffixes.empty()) {
|
||||
createAnalyzer(*analyzers, sysVocbase.get());
|
||||
|
||||
createAnalyzer(*analyzers);
|
||||
return arangodb::RestStatus::DONE;
|
||||
}
|
||||
|
||||
generateError(arangodb::Result( // generate error
|
||||
TRI_ERROR_BAD_PARAMETER, // code
|
||||
std::string("expecting POST ") + ANALYZER_PATH // mesage
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("expecting POST ").append(ANALYZER_PATH)
|
||||
));
|
||||
|
||||
return arangodb::RestStatus::DONE;
|
||||
|
||||
default:
|
||||
generateError(arangodb::Result( // generate error
|
||||
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED // error code
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED
|
||||
));
|
||||
}
|
||||
|
||||
return arangodb::RestStatus::DONE;
|
||||
}
|
||||
|
||||
void RestAnalyzerHandler::getAnalyzer( // get analyzer
|
||||
IResearchAnalyzerFeature& analyzers, // analyzer feature
|
||||
std::string const& name // analyzer name (normalized)
|
||||
void RestAnalyzerHandler::getAnalyzer(
|
||||
IResearchAnalyzerFeature& analyzers,
|
||||
std::string const& requestedName
|
||||
) {
|
||||
TRI_ASSERT(_request); // ensured by execute()
|
||||
auto* sysDatabase =
|
||||
arangodb::application_features::ApplicationServer::lookupFeature<arangodb::SystemDatabaseFeature>();
|
||||
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
|
||||
auto normalizedName = sysVocbase ?
|
||||
IResearchAnalyzerFeature::normalize(requestedName, _vocbase, *sysVocbase) : requestedName;
|
||||
|
||||
// ...........................................................................
|
||||
// end of parameter parsing
|
||||
// ...........................................................................
|
||||
|
||||
if (!IResearchAnalyzerFeature::canUse(name, auth::Level::RO)) {
|
||||
generateError(arangodb::Result( // generate error
|
||||
TRI_ERROR_FORBIDDEN, // code
|
||||
std::string("insufficient rights while getting analyzer: ") + name // message
|
||||
// need to check if analyzer is from current database or from system database
|
||||
const auto analyzerVocbase = IResearchAnalyzerFeature::extractVocbaseName(normalizedName);
|
||||
if (!IResearchAnalyzerFeature::analyzerReachableFromDb(analyzerVocbase, _vocbase.name(), true)) {
|
||||
std::string errorMessage("Analyzer '");
|
||||
errorMessage.append(normalizedName)
|
||||
.append("' is not accessible. Only analyzers from current database ('")
|
||||
.append(_vocbase.name())
|
||||
.append("')");
|
||||
if (_vocbase.name() != arangodb::StaticStrings::SystemDatabase) {
|
||||
errorMessage.append(" or system database");
|
||||
}
|
||||
errorMessage.append(" are available");
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_FORBIDDEN,
|
||||
errorMessage
|
||||
));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto pool = analyzers.get(name);
|
||||
|
||||
if (!pool) {
|
||||
generateError(arangodb::Result( // generate error
|
||||
TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND, // code
|
||||
std::string("unable to find analyzer: ") + name // mesage
|
||||
if (!IResearchAnalyzerFeature::canUse(normalizedName, auth::Level::RO)) {
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_FORBIDDEN,
|
||||
std::string("insufficient rights while getting analyzer: ").append(normalizedName)
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
auto pool = analyzers.get(normalizedName);
|
||||
if (!pool) {
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND,
|
||||
std::string("unable to find analyzer: ").append(normalizedName)
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
pool->toVelocyPack(builder);
|
||||
|
||||
// generate result + 'error' field + 'code' field
|
||||
|
@ -415,39 +390,51 @@ void RestAnalyzerHandler::getAnalyzers( // get all analyzers
|
|||
generateOk(arangodb::rest::ResponseCode::OK, builder.slice());
|
||||
}
|
||||
|
||||
void RestAnalyzerHandler::removeAnalyzer( // remove
|
||||
IResearchAnalyzerFeature& analyzers, // analyzer feature
|
||||
std::string const& name // analyzer name (normalized)
|
||||
void RestAnalyzerHandler::removeAnalyzer(
|
||||
IResearchAnalyzerFeature& analyzers,
|
||||
std::string const& requestedName,
|
||||
bool force
|
||||
) {
|
||||
TRI_ASSERT(_request); // ensured by execute()
|
||||
auto splittedAnalyzerName = IResearchAnalyzerFeature::splitAnalyzerName(requestedName);
|
||||
auto name = splittedAnalyzerName.second;
|
||||
|
||||
auto force = _request->parsedValue("force", false);
|
||||
|
||||
// ...........................................................................
|
||||
// end of parameter parsing
|
||||
// ...........................................................................
|
||||
|
||||
if (!IResearchAnalyzerFeature::canUse(name, auth::Level::RW)) {
|
||||
generateError(arangodb::Result( // generate error
|
||||
TRI_ERROR_FORBIDDEN, // code
|
||||
std::string("insufficient rights while removing analyzer: ") + name // message
|
||||
if (!TRI_vocbase_t::IsAllowedName(false, velocypack::StringRef(name.c_str(), name.size()))) {
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string("Invalid characters in analyzer name '").append(name)
|
||||
.append("'.")
|
||||
));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto res = analyzers.remove(name, force);
|
||||
if (!IResearchAnalyzerFeature::analyzerReachableFromDb(splittedAnalyzerName.first,
|
||||
_vocbase.name())) {
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_FORBIDDEN,
|
||||
"Database in analyzer name does not match current database"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto* sysDatabase =
|
||||
arangodb::application_features::ApplicationServer::lookupFeature<arangodb::SystemDatabaseFeature>();
|
||||
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
|
||||
auto normalizedName = sysVocbase ?
|
||||
IResearchAnalyzerFeature::normalize(name, _vocbase, *sysVocbase) : std::string(name);
|
||||
if (!IResearchAnalyzerFeature::canUse(normalizedName, auth::Level::RW)) {
|
||||
generateError(arangodb::Result(
|
||||
TRI_ERROR_FORBIDDEN,
|
||||
std::string("insufficient rights while removing analyzer: ").append(normalizedName)
|
||||
));
|
||||
return;
|
||||
}
|
||||
auto res = analyzers.remove(normalizedName, force);
|
||||
if (!res.ok()) {
|
||||
generateError(res);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.openObject();
|
||||
builder.add(StaticStrings::AnalyzerNameField, arangodb::velocypack::Value(name));
|
||||
builder.add(StaticStrings::AnalyzerNameField, arangodb::velocypack::Value(normalizedName));
|
||||
builder.close();
|
||||
|
||||
// generate result + 'error' field + 'code' field
|
||||
|
|
|
@ -49,22 +49,20 @@ class RestAnalyzerHandler: public RestVocbaseBaseHandler {
|
|||
virtual char const* name() const override { return "RestAnalyzerHandler"; }
|
||||
|
||||
private:
|
||||
void createAnalyzer(
|
||||
IResearchAnalyzerFeature& analyzers, // analyzer feature
|
||||
TRI_vocbase_t const* sysVocbase // system vocbase
|
||||
);
|
||||
void createAnalyzer(IResearchAnalyzerFeature& analyzers);
|
||||
void getAnalyzer(
|
||||
IResearchAnalyzerFeature& analyzers, // analyzer feature
|
||||
std::string const& name // analyzer name (normalized)
|
||||
IResearchAnalyzerFeature& analyzers,
|
||||
std::string const& requestedName
|
||||
);
|
||||
void getAnalyzers(IResearchAnalyzerFeature& analyzers);
|
||||
void removeAnalyzer(
|
||||
IResearchAnalyzerFeature& analyzers, // analyzer feature
|
||||
std::string const& name // analyzer name (normalized)
|
||||
IResearchAnalyzerFeature& analyzers,
|
||||
std::string const& requestedName,
|
||||
bool force
|
||||
);
|
||||
};
|
||||
|
||||
} // iresearch
|
||||
} // arangodb
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "v8-analyzers.h"
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "Basics/StaticStrings.h"
|
||||
#include "IResearch/IResearchAnalyzerFeature.h"
|
||||
#include "IResearch/VelocyPackHelper.h"
|
||||
#include "RestServer/SystemDatabaseFeature.h"
|
||||
|
@ -279,12 +280,22 @@ void JS_Create(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
|||
>();
|
||||
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
|
||||
|
||||
auto name = TRI_ObjectToString(isolate, args[0]);
|
||||
auto nameFromArgs = TRI_ObjectToString(isolate, args[0]);
|
||||
auto splittedAnalyzerName =
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::splitAnalyzerName(nameFromArgs);
|
||||
if (!arangodb::iresearch::IResearchAnalyzerFeature::analyzerReachableFromDb(
|
||||
splittedAnalyzerName.first, vocbase.name())) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_FORBIDDEN,
|
||||
"Database in analyzer name does not match current database");
|
||||
return;
|
||||
}
|
||||
auto name = splittedAnalyzerName.second;
|
||||
|
||||
if (!TRI_vocbase_t::IsAllowedName(false, arangodb::velocypack::StringRef(name))) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
"invalid characters in analyzer name '" + name + "'"
|
||||
std::string("invalid characters in analyzer name '").append(name).append("'")
|
||||
);
|
||||
|
||||
return;
|
||||
|
@ -443,6 +454,24 @@ void JS_Get(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
|||
// end of parameter parsing
|
||||
// ...........................................................................
|
||||
|
||||
const auto analyzerVocbase = arangodb::iresearch::IResearchAnalyzerFeature::extractVocbaseName(name);
|
||||
if (!arangodb::iresearch::IResearchAnalyzerFeature::analyzerReachableFromDb(
|
||||
analyzerVocbase, vocbase.name(), true)) {
|
||||
std::string errorMessage("Analyzer '");
|
||||
errorMessage.append(name)
|
||||
.append("' is not accessible. Only analyzers from current database ('")
|
||||
.append(vocbase.name())
|
||||
.append("')");
|
||||
if (vocbase.name() != arangodb::StaticStrings::SystemDatabase) {
|
||||
errorMessage.append(" or system database");
|
||||
}
|
||||
errorMessage.append(" are available");
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_FORBIDDEN, // code
|
||||
errorMessage
|
||||
);
|
||||
}
|
||||
|
||||
if (!arangodb::iresearch::IResearchAnalyzerFeature::canUse(name, arangodb::auth::Level::RO)) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE( // exception
|
||||
TRI_ERROR_FORBIDDEN, // code
|
||||
|
@ -500,12 +529,6 @@ void JS_List(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
|||
// ...........................................................................
|
||||
|
||||
typedef arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool::ptr AnalyzerPoolPtr;
|
||||
static const auto nameLess = []( // analyzer name less
|
||||
AnalyzerPoolPtr const& lhs, // left hand side
|
||||
AnalyzerPoolPtr const& rhs // right hand side
|
||||
)->bool {
|
||||
return arangodb::basics::StringUtils::tolower(lhs->name()) < arangodb::basics::StringUtils::tolower(rhs->name());
|
||||
};
|
||||
std::vector<AnalyzerPoolPtr> result;
|
||||
auto visitor = [&result](AnalyzerPoolPtr const& analyzer)->bool {
|
||||
if (analyzer) {
|
||||
|
@ -529,8 +552,6 @@ void JS_List(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
|||
analyzers->visit(visitor, sysVocbase.get());
|
||||
}
|
||||
|
||||
std::sort(result.begin(), result.end(), nameLess);
|
||||
|
||||
auto v8Result = v8::Array::New(isolate);
|
||||
|
||||
for (size_t i = 0, count = result.size(); i < count; ++i) {
|
||||
|
@ -586,9 +607,27 @@ void JS_Remove(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
|||
>();
|
||||
auto sysVocbase = sysDatabase ? sysDatabase->use() : nullptr;
|
||||
|
||||
auto name = TRI_ObjectToString(isolate, args[0]);
|
||||
std::string nameBuf;
|
||||
auto nameFromArgs = TRI_ObjectToString(isolate, args[0]);
|
||||
auto splittedAnalyzerName =
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::splitAnalyzerName(nameFromArgs);
|
||||
if (!arangodb::iresearch::IResearchAnalyzerFeature::analyzerReachableFromDb(
|
||||
splittedAnalyzerName.first, vocbase.name())) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_FORBIDDEN,
|
||||
"Database in analyzer name does not match current database");
|
||||
return;
|
||||
}
|
||||
auto name = splittedAnalyzerName.second;
|
||||
|
||||
if (!TRI_vocbase_t::IsAllowedName(false, arangodb::velocypack::StringRef(name))) {
|
||||
TRI_V8_THROW_EXCEPTION_MESSAGE(
|
||||
TRI_ERROR_BAD_PARAMETER,
|
||||
std::string( "Invalid characters in analyzer name '").append(name)
|
||||
.append("'.")
|
||||
);
|
||||
}
|
||||
|
||||
std::string nameBuf;
|
||||
if (sysVocbase) {
|
||||
nameBuf = arangodb::iresearch::IResearchAnalyzerFeature::normalize( // normalize
|
||||
name, vocbase, *sysVocbase // args
|
||||
|
|
|
@ -438,12 +438,6 @@ static void JS_ViewsVocbase(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
|||
|
||||
return true;
|
||||
});
|
||||
std::sort(views.begin(), views.end(),
|
||||
[](std::shared_ptr<LogicalView> const& lhs,
|
||||
std::shared_ptr<LogicalView> const& rhs) -> bool {
|
||||
return StringUtils::tolower(lhs->name()) <
|
||||
StringUtils::tolower(rhs->name());
|
||||
});
|
||||
|
||||
bool error = false;
|
||||
// already create an array of the correct size
|
||||
|
|
|
@ -122,6 +122,65 @@ struct TestTermAttribute : public irs::term_attribute {
|
|||
void value(irs::bytes_ref const& value) { value_ = value; }
|
||||
};
|
||||
|
||||
class ReNormalizingAnalyzer : public irs::analysis::analyzer {
|
||||
public:
|
||||
DECLARE_ANALYZER_TYPE();
|
||||
ReNormalizingAnalyzer() : irs::analysis::analyzer(ReNormalizingAnalyzer::type()) {
|
||||
_attrs.emplace(_attr);
|
||||
}
|
||||
|
||||
virtual irs::attribute_view const& attributes() const NOEXCEPT override {
|
||||
return _attrs;
|
||||
}
|
||||
|
||||
static ptr make(irs::string_ref const& args) {
|
||||
auto slice = arangodb::iresearch::slice(args);
|
||||
if (slice.isNull()) throw std::exception();
|
||||
if (slice.isNone()) return nullptr;
|
||||
PTR_NAMED(ReNormalizingAnalyzer, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// test implementation
|
||||
// string will be normalized as is. But object will be converted!
|
||||
// need this to test comparsion "old-normalized" against "new-normalized"
|
||||
static bool normalize(irs::string_ref const& args, std::string& definition) {
|
||||
auto slice = arangodb::iresearch::slice(args);
|
||||
arangodb::velocypack::Builder builder;
|
||||
if (slice.isString()) {
|
||||
VPackObjectBuilder scope(&builder);
|
||||
arangodb::iresearch::addStringRef(builder, "args",
|
||||
arangodb::iresearch::getStringRef(slice));
|
||||
} else if (slice.isObject() && slice.hasKey("args") && slice.get("args").isString()) {
|
||||
VPackObjectBuilder scope(&builder);
|
||||
auto inputDef = arangodb::iresearch::getStringRef(slice.get("args"));
|
||||
arangodb::iresearch::addStringRef(builder, "args",
|
||||
inputDef == "123" ? "321" : inputDef);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
definition = builder.buffer()->toString();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool next() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool reset(irs::string_ref const& data) override {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
irs::attribute_view _attrs;
|
||||
TestAttribute _attr;
|
||||
};
|
||||
|
||||
DEFINE_ANALYZER_TYPE_NAMED(ReNormalizingAnalyzer, "ReNormalizingAnalyzer");
|
||||
REGISTER_ANALYZER_VPACK(ReNormalizingAnalyzer, ReNormalizingAnalyzer::make, ReNormalizingAnalyzer::normalize);
|
||||
|
||||
class TestAnalyzer : public irs::analysis::analyzer {
|
||||
public:
|
||||
DECLARE_ANALYZER_TYPE();
|
||||
|
@ -862,6 +921,31 @@ TEST_F(IResearchAnalyzerFeatureTest, test_get_feature_mismatch) {
|
|||
ASSERT_EQ(read, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(IResearchAnalyzerFeatureTest, test_renormalize_for_equal) {
|
||||
arangodb::iresearch::IResearchAnalyzerFeature feature(server);
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
EXPECT_TRUE(feature.emplace(result, analyzerName(), "ReNormalizingAnalyzer",
|
||||
VPackParser::fromJson("\"123\"")->slice()) //123 will be stored as is (old-normalized)
|
||||
.ok());
|
||||
EXPECT_NE(result.first, nullptr);
|
||||
}
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
EXPECT_TRUE(feature.emplace(result, analyzerName(), "ReNormalizingAnalyzer",
|
||||
VPackParser::fromJson("{ \"args\":\"123\"}")->slice()) //123 will be normalized to 321
|
||||
.ok());
|
||||
EXPECT_NE(result.first, nullptr);
|
||||
}
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
EXPECT_FALSE(feature.emplace(result, analyzerName(), "ReNormalizingAnalyzer",
|
||||
VPackParser::fromJson("{ \"args\":\"1231\"}")->slice()) //Re-normalization should not help
|
||||
.ok());
|
||||
EXPECT_EQ(result.first, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- get test suite
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -84,7 +84,8 @@ class IResearchLinkHelperTest : public ::testing::Test {
|
|||
features.emplace_back(new arangodb::AqlFeature(server),
|
||||
true); // required for UserManager::loadFromDB()
|
||||
features.emplace_back(new arangodb::AuthenticationFeature(server), false); // required for authentication tests
|
||||
features.emplace_back(new arangodb::DatabaseFeature(server), false);
|
||||
auto dbFeature = new arangodb::DatabaseFeature(server);
|
||||
features.emplace_back(dbFeature, 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), true); // required by IResearchAnalyzerFeature::storeAnalyzer(...)
|
||||
|
@ -117,10 +118,7 @@ class IResearchLinkHelperTest : public ::testing::Test {
|
|||
|
||||
auto const databases = arangodb::velocypack::Parser::fromJson(
|
||||
std::string("[ { \"name\": \"") +
|
||||
arangodb::StaticStrings::SystemDatabase + "\" } ]");
|
||||
auto* dbFeature =
|
||||
arangodb::application_features::ApplicationServer::lookupFeature<arangodb::DatabaseFeature>(
|
||||
"Database");
|
||||
arangodb::StaticStrings::SystemDatabase + "\" }]");
|
||||
dbFeature->loadDatabases(databases->slice());
|
||||
|
||||
for (auto& f : features) {
|
||||
|
@ -134,6 +132,29 @@ class IResearchLinkHelperTest : public ::testing::Test {
|
|||
"DatabasePath");
|
||||
arangodb::tests::setDatabasePath(*dbPathFeature); // ensure test data is stored in a unique directory
|
||||
testFilesystemPath = dbPathFeature->directory();
|
||||
{
|
||||
auto vocbase = dbFeature->useDatabase(arangodb::StaticStrings::SystemDatabase);
|
||||
arangodb::methods::Collections::createSystem(
|
||||
*vocbase,
|
||||
arangodb::tests::AnalyzerCollectionName);
|
||||
}
|
||||
{
|
||||
TRI_vocbase_t* vocbase;
|
||||
dbFeature->createDatabase(1, "testVocbaseWithAnalyzer", vocbase);
|
||||
arangodb::methods::Collections::createSystem(
|
||||
*vocbase,
|
||||
arangodb::tests::AnalyzerCollectionName);
|
||||
}
|
||||
{
|
||||
TRI_vocbase_t* vocbase;
|
||||
dbFeature->createDatabase(2, "testVocbaseWithView", vocbase);
|
||||
arangodb::methods::Collections::createSystem(
|
||||
*vocbase,
|
||||
arangodb::tests::AnalyzerCollectionName);
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson(
|
||||
"{ \"id\":102, \"name\": \"foo\" }");
|
||||
EXPECT_NE(nullptr, vocbase->createCollection(collectionJson->slice()));
|
||||
}
|
||||
|
||||
long systemError;
|
||||
std::string systemErrorStr;
|
||||
|
@ -274,6 +295,37 @@ TEST_F(IResearchLinkHelperTest, test_equals) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST_F(IResearchLinkHelperTest, test_validate_cross_db_analyzer) {
|
||||
auto* analyzers =
|
||||
arangodb::application_features::ApplicationServer::lookupFeature<arangodb::iresearch::IResearchAnalyzerFeature>();
|
||||
ASSERT_NE(nullptr, analyzers);
|
||||
auto* dbFeature =
|
||||
arangodb::application_features::ApplicationServer::lookupFeature<arangodb::DatabaseFeature>("Database");
|
||||
ASSERT_NE(nullptr, dbFeature);
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult emplaceResult;
|
||||
ASSERT_TRUE(analyzers->emplace(emplaceResult, "testVocbaseWithAnalyzer::myIdentity", "identity",
|
||||
VPackParser::fromJson("{ }")->slice()).ok());
|
||||
}
|
||||
|
||||
// existing analyzer but wrong database
|
||||
{
|
||||
auto vocbaseLocal = dbFeature->useDatabase("testVocbaseWithView");
|
||||
ASSERT_NE(nullptr, vocbaseLocal);
|
||||
auto json = VPackParser::fromJson(
|
||||
"{ \"foo\": "
|
||||
" { "
|
||||
" \"analyzers\": [ \"testVocbaseWithAnalyzer::myIdentity\" ] "
|
||||
" } "
|
||||
" }");
|
||||
auto validateResult = arangodb::iresearch::IResearchLinkHelper::validateLinks(
|
||||
*vocbaseLocal, json->slice());
|
||||
EXPECT_FALSE(validateResult.ok());
|
||||
EXPECT_EQ(TRI_ERROR_BAD_PARAMETER, validateResult.errorNumber());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_F(IResearchLinkHelperTest, test_normalize) {
|
||||
auto* analyzers =
|
||||
arangodb::application_features::ApplicationServer::lookupFeature<arangodb::iresearch::IResearchAnalyzerFeature>();
|
||||
|
@ -282,17 +334,6 @@ TEST_F(IResearchLinkHelperTest, test_normalize) {
|
|||
arangodb::application_features::ApplicationServer::lookupFeature<arangodb::SystemDatabaseFeature>();
|
||||
auto sysVocbase = sysDatabase->use();
|
||||
|
||||
// create analyzer collection
|
||||
{
|
||||
if (!sysVocbase->lookupCollection(arangodb::tests::AnalyzerCollectionName)) {
|
||||
auto collectionJson = arangodb::velocypack::Parser::fromJson(
|
||||
std::string("{ \"name\": \"") + arangodb::tests::AnalyzerCollectionName +
|
||||
"\", \"isSystem\": true }");
|
||||
auto logicalCollection = sysVocbase->createCollection(collectionJson->slice());
|
||||
ASSERT_TRUE((false == !logicalCollection));
|
||||
}
|
||||
}
|
||||
|
||||
// analyzer single-server
|
||||
{
|
||||
auto json = arangodb::velocypack::Parser::fromJson(
|
||||
|
|
|
@ -183,11 +183,13 @@ class IResearchLinkMetaTest : public ::testing::Test {
|
|||
*sysvocbase,
|
||||
arangodb::tests::AnalyzerCollectionName);
|
||||
|
||||
|
||||
TRI_vocbase_t* vocbase;
|
||||
dbFeature->createDatabase(1, "testVocbase", vocbase); // required for IResearchAnalyzerFeature::emplace(...)
|
||||
arangodb::methods::Collections::createSystem(
|
||||
*vocbase,
|
||||
arangodb::tests::AnalyzerCollectionName);
|
||||
*vocbase,
|
||||
arangodb::tests::AnalyzerCollectionName);
|
||||
|
||||
auto* analyzers =
|
||||
arangodb::application_features::ApplicationServer::lookupFeature<arangodb::iresearch::IResearchAnalyzerFeature>();
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
|
|
|
@ -106,7 +106,9 @@ class RestAnalyzerHandlerTest : public ::testing::Test {
|
|||
|
||||
// setup required application features
|
||||
features.emplace_back(new arangodb::AuthenticationFeature(server), false); // required for VocbaseContext
|
||||
|
||||
features.emplace_back(new arangodb::DatabaseFeature(server), false);
|
||||
features.emplace_back(new arangodb::SystemDatabaseFeature(server),
|
||||
true); // required for IResearchAnalyzerFeature
|
||||
#if USE_ENTERPRISE
|
||||
features.emplace_back(new arangodb::LdapFeature(server),
|
||||
false); // required for AuthenticationFeature with USE_ENTERPRISE
|
||||
|
@ -329,19 +331,19 @@ TEST_F(RestAnalyzerHandlerTest, test_create) {
|
|||
|
||||
auto status = handler.execute();
|
||||
EXPECT_TRUE((arangodb::RestStatus::DONE == status));
|
||||
EXPECT_TRUE((arangodb::rest::ResponseCode::BAD == responce.responseCode()));
|
||||
EXPECT_TRUE((arangodb::rest::ResponseCode::FORBIDDEN == responce.responseCode()));
|
||||
auto slice = responce._payload.slice();
|
||||
EXPECT_TRUE((slice.isObject()));
|
||||
EXPECT_TRUE((slice.hasKey(arangodb::StaticStrings::Code) &&
|
||||
slice.get(arangodb::StaticStrings::Code).isNumber<size_t>() &&
|
||||
size_t(arangodb::rest::ResponseCode::BAD) ==
|
||||
size_t(arangodb::rest::ResponseCode::FORBIDDEN) ==
|
||||
slice.get(arangodb::StaticStrings::Code).getNumber<size_t>()));
|
||||
EXPECT_TRUE((slice.hasKey(arangodb::StaticStrings::Error) &&
|
||||
slice.get(arangodb::StaticStrings::Error).isBoolean() &&
|
||||
true == slice.get(arangodb::StaticStrings::Error).getBoolean()));
|
||||
EXPECT_TRUE((slice.hasKey(arangodb::StaticStrings::ErrorNum) &&
|
||||
slice.get(arangodb::StaticStrings::ErrorNum).isNumber<int>() &&
|
||||
TRI_ERROR_BAD_PARAMETER ==
|
||||
TRI_ERROR_FORBIDDEN ==
|
||||
slice.get(arangodb::StaticStrings::ErrorNum).getNumber<int>()));
|
||||
}
|
||||
|
||||
|
@ -357,9 +359,9 @@ TEST_F(RestAnalyzerHandlerTest, test_create) {
|
|||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::POST);
|
||||
request._payload.openObject();
|
||||
request._payload.add("name", VPackValue(arangodb::StaticStrings::SystemDatabase + "::testAnalyzer"));
|
||||
request._payload.add("name", VPackValue(arangodb::StaticStrings::SystemDatabase + "::testAn:alyzer"));
|
||||
request._payload.add("type", VPackValue("identity"));
|
||||
request._payload.add("properties", VPackValue(arangodb::velocypack::ValueType::Null));
|
||||
request._payload.add("properties", arangodb::velocypack::Value("{\"args\":\"abc\"}"));
|
||||
request._payload.close();
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
|
@ -388,7 +390,7 @@ TEST_F(RestAnalyzerHandlerTest, test_create) {
|
|||
slice.get(arangodb::StaticStrings::ErrorNum).getNumber<int>()));
|
||||
}
|
||||
|
||||
// invalid params (name contains invalid symbols)
|
||||
// name contains :: as link to system database (this is now ok)
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
arangodb::StaticStrings::SystemDatabase);
|
||||
|
@ -400,9 +402,9 @@ TEST_F(RestAnalyzerHandlerTest, test_create) {
|
|||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::POST);
|
||||
request._payload.openObject();
|
||||
request._payload.add("name", VPackValue("::testAnalyzer"));
|
||||
request._payload.add("name", VPackValue("::testAnalyzerImplicitDbName"));
|
||||
request._payload.add("type", VPackValue("identity"));
|
||||
request._payload.add("properties", VPackValue(arangodb::velocypack::ValueType::Null));
|
||||
request._payload.add("properties", arangodb::velocypack::Value("{\"args\":\"abc\"}"));
|
||||
request._payload.close();
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
|
@ -415,22 +417,44 @@ TEST_F(RestAnalyzerHandlerTest, test_create) {
|
|||
|
||||
auto status = handler.execute();
|
||||
EXPECT_TRUE((arangodb::RestStatus::DONE == status));
|
||||
EXPECT_TRUE((arangodb::rest::ResponseCode::BAD == responce.responseCode()));
|
||||
auto slice = responce._payload.slice();
|
||||
EXPECT_TRUE((slice.isObject()));
|
||||
EXPECT_TRUE((slice.hasKey(arangodb::StaticStrings::Code) &&
|
||||
slice.get(arangodb::StaticStrings::Code).isNumber<size_t>() &&
|
||||
size_t(arangodb::rest::ResponseCode::BAD) ==
|
||||
slice.get(arangodb::StaticStrings::Code).getNumber<size_t>()));
|
||||
EXPECT_TRUE((slice.hasKey(arangodb::StaticStrings::Error) &&
|
||||
slice.get(arangodb::StaticStrings::Error).isBoolean() &&
|
||||
true == slice.get(arangodb::StaticStrings::Error).getBoolean()));
|
||||
EXPECT_TRUE((slice.hasKey(arangodb::StaticStrings::ErrorNum) &&
|
||||
slice.get(arangodb::StaticStrings::ErrorNum).isNumber<int>() &&
|
||||
TRI_ERROR_BAD_PARAMETER ==
|
||||
slice.get(arangodb::StaticStrings::ErrorNum).getNumber<int>()));
|
||||
EXPECT_TRUE((arangodb::rest::ResponseCode::CREATED == responce.responseCode()));
|
||||
auto analyzer = analyzers->get(arangodb::StaticStrings::SystemDatabase +
|
||||
"::testAnalyzerImplicitDbName");
|
||||
EXPECT_NE(nullptr, analyzer);
|
||||
}
|
||||
// name contains full database name
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
arangodb::StaticStrings::SystemDatabase);
|
||||
auto requestPtr = std::make_unique<GeneralRequestMock>(vocbase);
|
||||
auto& request = *requestPtr;
|
||||
auto responcePtr = std::make_unique<GeneralResponseMock>();
|
||||
auto& responce = *responcePtr;
|
||||
arangodb::iresearch::RestAnalyzerHandler handler(requestPtr.release(),
|
||||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::POST);
|
||||
request._payload.openObject();
|
||||
request._payload.add("name", VPackValue(arangodb::StaticStrings::SystemDatabase +
|
||||
"::testAnalyzerWithDbName"));
|
||||
request._payload.add("type", VPackValue("identity"));
|
||||
request._payload.add("properties", arangodb::velocypack::Value("{\"args\":\"abc\"}"));
|
||||
request._payload.close();
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
userMap
|
||||
.emplace("", arangodb::auth::User::newUser("", "", arangodb::auth::Source::LDAP))
|
||||
.first->second;
|
||||
user.grantDatabase(vocbase.name(), arangodb::auth::Level::RW); // for system collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
auto status = handler.execute();
|
||||
EXPECT_TRUE((arangodb::RestStatus::DONE == status));
|
||||
EXPECT_TRUE((arangodb::rest::ResponseCode::CREATED == responce.responseCode()));
|
||||
auto analyzer = analyzers->get(arangodb::StaticStrings::SystemDatabase +
|
||||
"::testAnalyzerWithDbName");
|
||||
EXPECT_NE(nullptr, analyzer);
|
||||
}
|
||||
// name collision
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
|
@ -616,21 +640,33 @@ TEST_F(RestAnalyzerHandlerTest, test_get) {
|
|||
server.addFeature(new arangodb::QueryRegistryFeature(server)); // required for constructing TRI_vocbase_t
|
||||
server.addFeature(new arangodb::V8DealerFeature(server)); // required for DatabaseFeature::createDatabase(...)
|
||||
server.addFeature(dbFeature = new arangodb::DatabaseFeature(server)); // required for IResearchAnalyzerFeature::emplace(...)
|
||||
auto sysDbFeature = new arangodb::SystemDatabaseFeature(server);
|
||||
server.addFeature(sysDbFeature);
|
||||
server.addFeature(analyzers = new arangodb::iresearch::IResearchAnalyzerFeature(server)); // required for running upgrade task
|
||||
analyzers->prepare(); // add static analyzers
|
||||
|
||||
auto cleanup = arangodb::scopeGuard([dbFeature](){ dbFeature->unprepare(); });
|
||||
|
||||
// create system vocbase
|
||||
// create vocbases
|
||||
{
|
||||
auto const databases = arangodb::velocypack::Parser::fromJson(
|
||||
std::string("[ { \"name\": \"") +
|
||||
arangodb::StaticStrings::SystemDatabase + "\" } ]");
|
||||
arangodb::StaticStrings::SystemDatabase + "\" }, { \"name\": \"FooDb\" }, { \"name\": \"FooDb2\" } ]");
|
||||
ASSERT_TRUE((TRI_ERROR_NO_ERROR == dbFeature->loadDatabases(databases->slice())));
|
||||
arangodb::methods::Collections::createSystem(
|
||||
*dbFeature->useDatabase(arangodb::StaticStrings::SystemDatabase),
|
||||
arangodb::tests::AnalyzerCollectionName);
|
||||
arangodb::methods::Collections::createSystem(
|
||||
*dbFeature->useDatabase("FooDb"),
|
||||
arangodb::tests::AnalyzerCollectionName);
|
||||
arangodb::methods::Collections::createSystem(
|
||||
*dbFeature->useDatabase("FooDb2"),
|
||||
arangodb::tests::AnalyzerCollectionName);
|
||||
|
||||
sysDbFeature->prepare();
|
||||
sysDbFeature->start();
|
||||
}
|
||||
|
||||
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
ASSERT_TRUE((analyzers
|
||||
|
@ -712,12 +748,12 @@ TEST_F(RestAnalyzerHandlerTest, test_get) {
|
|||
userMap
|
||||
.emplace("", arangodb::auth::User::newUser("", "", arangodb::auth::Source::LDAP))
|
||||
.first->second;
|
||||
user.grantDatabase(vocbase.name(), arangodb::auth::Level::NONE); // for system collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
user.grantDatabase(vocbase.name(), arangodb::auth::Level::RO); // for system collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
auto status = handler.execute();
|
||||
EXPECT_TRUE((arangodb::RestStatus::DONE == status));
|
||||
EXPECT_TRUE((arangodb::rest::ResponseCode::NOT_FOUND == responce.responseCode()));
|
||||
EXPECT_EQ(arangodb::rest::ResponseCode::NOT_FOUND, responce.responseCode());
|
||||
auto slice = responce._payload.slice();
|
||||
EXPECT_TRUE((slice.isObject()));
|
||||
EXPECT_TRUE((slice.hasKey(arangodb::StaticStrings::Code) &&
|
||||
|
@ -774,7 +810,73 @@ TEST_F(RestAnalyzerHandlerTest, test_get) {
|
|||
EXPECT_TRUE(slice.hasKey("properties") && slice.get("properties").isObject());
|
||||
EXPECT_TRUE((slice.hasKey("features") && slice.get("features").isArray()));
|
||||
}
|
||||
// get custom (known analyzer) authorized but from different db
|
||||
{
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
userMap
|
||||
.emplace("", arangodb::auth::User::newUser("", "", arangodb::auth::Source::LDAP))
|
||||
.first->second;
|
||||
user.grantDatabase("FooDb", arangodb::auth::Level::RW);
|
||||
user.grantDatabase("FooDb2", arangodb::auth::Level::RO);
|
||||
user.grantDatabase(arangodb::StaticStrings::SystemDatabase, arangodb::auth::Level::RO);
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
ASSERT_TRUE((analyzers
|
||||
->emplace(result, "FooDb::testAnalyzer1",
|
||||
"identity",
|
||||
VPackSlice::noneSlice()) // Empty VPack for nullptr
|
||||
.ok()));
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
"FooDb2");
|
||||
auto requestPtr = std::make_unique<GeneralRequestMock>(vocbase);
|
||||
auto& request = *requestPtr;
|
||||
auto responcePtr = std::make_unique<GeneralResponseMock>();
|
||||
auto& responce = *responcePtr;
|
||||
arangodb::iresearch::RestAnalyzerHandler handler(requestPtr.release(),
|
||||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::GET);
|
||||
request.addSuffix("FooDb::testAnalyzer1");
|
||||
|
||||
auto status = handler.execute();
|
||||
EXPECT_TRUE((arangodb::RestStatus::DONE == status));
|
||||
// user has access but analyzer should not be visible
|
||||
EXPECT_EQ(arangodb::rest::ResponseCode::FORBIDDEN, responce.responseCode());
|
||||
}
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
"FooDb2");
|
||||
auto requestPtr = std::make_unique<GeneralRequestMock>(vocbase);
|
||||
auto& request = *requestPtr;
|
||||
auto responcePtr = std::make_unique<GeneralResponseMock>();
|
||||
auto& responce = *responcePtr;
|
||||
arangodb::iresearch::RestAnalyzerHandler handler(requestPtr.release(),
|
||||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::GET);
|
||||
request.addSuffix(arangodb::StaticStrings::SystemDatabase + "::testAnalyzer1");
|
||||
auto status = handler.execute();
|
||||
EXPECT_TRUE((arangodb::RestStatus::DONE == status));
|
||||
//system should be visible
|
||||
EXPECT_EQ(arangodb::rest::ResponseCode::OK, responce.responseCode());
|
||||
}
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
"FooDb2");
|
||||
auto requestPtr = std::make_unique<GeneralRequestMock>(vocbase);
|
||||
auto& request = *requestPtr;
|
||||
auto responcePtr = std::make_unique<GeneralResponseMock>();
|
||||
auto& responce = *responcePtr;
|
||||
arangodb::iresearch::RestAnalyzerHandler handler(requestPtr.release(),
|
||||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::GET);
|
||||
request.addSuffix("::testAnalyzer1");
|
||||
auto status = handler.execute();
|
||||
EXPECT_TRUE((arangodb::RestStatus::DONE == status));
|
||||
//system should be visible
|
||||
EXPECT_EQ(arangodb::rest::ResponseCode::OK, responce.responseCode());
|
||||
}
|
||||
}
|
||||
// get custom (known analyzer) not authorized
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
|
@ -786,8 +888,7 @@ TEST_F(RestAnalyzerHandlerTest, test_get) {
|
|||
arangodb::iresearch::RestAnalyzerHandler handler(requestPtr.release(),
|
||||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::GET);
|
||||
request.addSuffix(arangodb::StaticStrings::SystemDatabase +
|
||||
"::testAnalyzer1");
|
||||
request.addSuffix("testAnalyzer1");
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
|
@ -799,7 +900,7 @@ TEST_F(RestAnalyzerHandlerTest, test_get) {
|
|||
|
||||
auto status = handler.execute();
|
||||
EXPECT_TRUE((arangodb::RestStatus::DONE == status));
|
||||
EXPECT_TRUE((arangodb::rest::ResponseCode::FORBIDDEN == responce.responseCode()));
|
||||
EXPECT_EQ(arangodb::rest::ResponseCode::FORBIDDEN , responce.responseCode());
|
||||
auto slice = responce._payload.slice();
|
||||
EXPECT_TRUE((slice.isObject()));
|
||||
EXPECT_TRUE((slice.hasKey(arangodb::StaticStrings::Code) &&
|
||||
|
@ -826,7 +927,7 @@ TEST_F(RestAnalyzerHandlerTest, test_get) {
|
|||
arangodb::iresearch::RestAnalyzerHandler handler(requestPtr.release(),
|
||||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::GET);
|
||||
request.addSuffix(arangodb::StaticStrings::SystemDatabase + "::unknown");
|
||||
request.addSuffix("unknown");
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
|
@ -865,7 +966,7 @@ TEST_F(RestAnalyzerHandlerTest, test_get) {
|
|||
arangodb::iresearch::RestAnalyzerHandler handler(requestPtr.release(),
|
||||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::GET);
|
||||
request.addSuffix(arangodb::StaticStrings::SystemDatabase + "::unknown");
|
||||
request.addSuffix("unknown");
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
|
@ -904,7 +1005,7 @@ TEST_F(RestAnalyzerHandlerTest, test_get) {
|
|||
arangodb::iresearch::RestAnalyzerHandler handler(requestPtr.release(),
|
||||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::GET);
|
||||
request.addSuffix("unknownVocbase::unknown");
|
||||
request.addSuffix("unknown");
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
|
@ -943,7 +1044,7 @@ TEST_F(RestAnalyzerHandlerTest, test_get) {
|
|||
arangodb::iresearch::RestAnalyzerHandler handler(requestPtr.release(),
|
||||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::GET);
|
||||
request.addSuffix("unknownVocbase::unknown");
|
||||
request.addSuffix("unknown");
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
|
@ -1393,6 +1494,8 @@ TEST_F(RestAnalyzerHandlerTest, test_remove) {
|
|||
server.addFeature(new arangodb::QueryRegistryFeature(server)); // required for constructing TRI_vocbase_t
|
||||
server.addFeature(new arangodb::V8DealerFeature(server)); // required for DatabaseFeature::createDatabase(...)
|
||||
server.addFeature(dbFeature = new arangodb::DatabaseFeature(server)); // required for IResearchAnalyzerFeature::emplace(...)
|
||||
auto sysDbFeature = new arangodb::SystemDatabaseFeature(server);
|
||||
server.addFeature(sysDbFeature);
|
||||
server.addFeature(analyzers = new arangodb::iresearch::IResearchAnalyzerFeature(server)); // required for running upgrade task
|
||||
|
||||
auto cleanup = arangodb::scopeGuard([dbFeature](){ dbFeature->unprepare(); });
|
||||
|
@ -1406,6 +1509,8 @@ TEST_F(RestAnalyzerHandlerTest, test_remove) {
|
|||
arangodb::methods::Collections::createSystem(
|
||||
*dbFeature->useDatabase(arangodb::StaticStrings::SystemDatabase),
|
||||
arangodb::tests::AnalyzerCollectionName);
|
||||
sysDbFeature->prepare();
|
||||
sysDbFeature->start();
|
||||
}
|
||||
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
|
@ -1417,6 +1522,15 @@ TEST_F(RestAnalyzerHandlerTest, test_remove) {
|
|||
->emplace(result, arangodb::StaticStrings::SystemDatabase + "::testAnalyzer2",
|
||||
"identity", VPackSlice::noneSlice())
|
||||
.ok()));
|
||||
ASSERT_TRUE((analyzers
|
||||
->emplace(result, arangodb::StaticStrings::SystemDatabase + "::testAnalyzer3",
|
||||
"identity", VPackSlice::noneSlice())
|
||||
.ok()));
|
||||
ASSERT_TRUE((analyzers
|
||||
->emplace(result, arangodb::StaticStrings::SystemDatabase + "::testAnalyzer4",
|
||||
"identity", VPackSlice::noneSlice())
|
||||
.ok()));
|
||||
result.first.reset(); // to release reference!
|
||||
|
||||
struct ExecContext : public arangodb::ExecContext {
|
||||
ExecContext()
|
||||
|
@ -1482,7 +1596,7 @@ TEST_F(RestAnalyzerHandlerTest, test_remove) {
|
|||
arangodb::iresearch::RestAnalyzerHandler handler(requestPtr.release(),
|
||||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::DELETE_REQ);
|
||||
request.addSuffix(arangodb::StaticStrings::SystemDatabase + "::unknown");
|
||||
request.addSuffix("unknown");
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
|
@ -1521,8 +1635,7 @@ TEST_F(RestAnalyzerHandlerTest, test_remove) {
|
|||
arangodb::iresearch::RestAnalyzerHandler handler(requestPtr.release(),
|
||||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::DELETE_REQ);
|
||||
request.addSuffix(arangodb::StaticStrings::SystemDatabase +
|
||||
"::testAnalyzer1");
|
||||
request.addSuffix("testAnalyzer1");
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
|
@ -1564,8 +1677,7 @@ TEST_F(RestAnalyzerHandlerTest, test_remove) {
|
|||
arangodb::iresearch::RestAnalyzerHandler handler(requestPtr.release(),
|
||||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::DELETE_REQ);
|
||||
request.addSuffix(arangodb::StaticStrings::SystemDatabase +
|
||||
"::testAnalyzer2");
|
||||
request.addSuffix("testAnalyzer2");
|
||||
request.values().emplace("force", "false");
|
||||
auto inUseAnalyzer = analyzers->get(arangodb::StaticStrings::SystemDatabase +
|
||||
"::testAnalyzer2"); // hold ref to mark in-use
|
||||
|
@ -1611,8 +1723,7 @@ TEST_F(RestAnalyzerHandlerTest, test_remove) {
|
|||
arangodb::iresearch::RestAnalyzerHandler handler(requestPtr.release(),
|
||||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::DELETE_REQ);
|
||||
request.addSuffix(arangodb::StaticStrings::SystemDatabase +
|
||||
"::testAnalyzer2");
|
||||
request.addSuffix("testAnalyzer2");
|
||||
request.values().emplace("force", "true");
|
||||
auto inUseAnalyzer = analyzers->get(arangodb::StaticStrings::SystemDatabase +
|
||||
"::testAnalyzer2"); // hold ref to mark in-use
|
||||
|
@ -1646,7 +1757,7 @@ TEST_F(RestAnalyzerHandlerTest, test_remove) {
|
|||
EXPECT_TRUE((true == !analyzer));
|
||||
}
|
||||
|
||||
// success removal
|
||||
// removal with db name in analyzer name
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
arangodb::StaticStrings::SystemDatabase);
|
||||
|
@ -1658,7 +1769,7 @@ TEST_F(RestAnalyzerHandlerTest, test_remove) {
|
|||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::DELETE_REQ);
|
||||
request.addSuffix(arangodb::StaticStrings::SystemDatabase +
|
||||
"::testAnalyzer1");
|
||||
"::testAnalyzer3");
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
|
@ -1670,7 +1781,65 @@ TEST_F(RestAnalyzerHandlerTest, test_remove) {
|
|||
|
||||
auto status = handler.execute();
|
||||
EXPECT_TRUE((arangodb::RestStatus::DONE == status));
|
||||
EXPECT_TRUE((arangodb::rest::ResponseCode::OK == responce.responseCode()));
|
||||
EXPECT_EQ(arangodb::rest::ResponseCode::OK, responce.responseCode());
|
||||
auto analyzer = analyzers->get(arangodb::StaticStrings::SystemDatabase +
|
||||
"::testAnalyzer3");
|
||||
EXPECT_EQ(nullptr, analyzer);
|
||||
}
|
||||
|
||||
// removal with db name prefix as ::
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
arangodb::StaticStrings::SystemDatabase);
|
||||
auto requestPtr = std::make_unique<GeneralRequestMock>(vocbase);
|
||||
auto& request = *requestPtr;
|
||||
auto responcePtr = std::make_unique<GeneralResponseMock>();
|
||||
auto& responce = *responcePtr;
|
||||
arangodb::iresearch::RestAnalyzerHandler handler(requestPtr.release(),
|
||||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::DELETE_REQ);
|
||||
request.addSuffix("::testAnalyzer4");
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
userMap
|
||||
.emplace("", arangodb::auth::User::newUser("", "", arangodb::auth::Source::LDAP))
|
||||
.first->second;
|
||||
user.grantDatabase(vocbase.name(), arangodb::auth::Level::RW); // for system collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
auto status = handler.execute();
|
||||
EXPECT_TRUE((arangodb::RestStatus::DONE == status));
|
||||
EXPECT_EQ(arangodb::rest::ResponseCode::OK, responce.responseCode());
|
||||
auto analyzer = analyzers->get(arangodb::StaticStrings::SystemDatabase +
|
||||
"::testAnalyzer4");
|
||||
EXPECT_EQ(nullptr, analyzer);
|
||||
}
|
||||
|
||||
// success removal
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
arangodb::StaticStrings::SystemDatabase);
|
||||
auto requestPtr = std::make_unique<GeneralRequestMock>(vocbase);
|
||||
auto& request = *requestPtr;
|
||||
auto responcePtr = std::make_unique<GeneralResponseMock>();
|
||||
auto& responce = *responcePtr;
|
||||
arangodb::iresearch::RestAnalyzerHandler handler(requestPtr.release(),
|
||||
responcePtr.release());
|
||||
request.setRequestType(arangodb::rest::RequestType::DELETE_REQ);
|
||||
request.addSuffix("testAnalyzer1");
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
userMap
|
||||
.emplace("", arangodb::auth::User::newUser("", "", arangodb::auth::Source::LDAP))
|
||||
.first->second;
|
||||
user.grantDatabase(vocbase.name(), arangodb::auth::Level::RW); // for system collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
auto status = handler.execute();
|
||||
EXPECT_TRUE((arangodb::RestStatus::DONE == status));
|
||||
EXPECT_EQ(arangodb::rest::ResponseCode::OK, responce.responseCode());
|
||||
auto slice = responce._payload.slice();
|
||||
EXPECT_TRUE((slice.isObject()));
|
||||
EXPECT_TRUE((slice.hasKey(arangodb::StaticStrings::Code) &&
|
||||
|
|
|
@ -891,7 +891,7 @@ TEST_F(V8AnalyzersTest, test_create) {
|
|||
EXPECT_TRUE((fn_create->IsFunction()));
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {
|
||||
TRI_V8_STD_STRING(isolate.get(), arangodb::StaticStrings::SystemDatabase + "::testAnalyzer2"),
|
||||
TRI_V8_STD_STRING(isolate.get(), arangodb::StaticStrings::SystemDatabase + "::test:Analyzer2"),
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "identity"),
|
||||
v8::True(isolate.get()),
|
||||
};
|
||||
|
@ -949,7 +949,7 @@ TEST_F(V8AnalyzersTest, test_create) {
|
|||
EXPECT_TRUE((fn_create->IsFunction()));
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {
|
||||
TRI_V8_STD_STRING(isolate.get(), "::testAnalyzer2"s),
|
||||
TRI_V8_STD_STRING(isolate.get(), "::test:Analyzer2"s),
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "identity"),
|
||||
v8::True(isolate.get()),
|
||||
};
|
||||
|
@ -1033,7 +1033,7 @@ TEST_F(V8AnalyzersTest, test_create) {
|
|||
EXPECT_TRUE((slice.isObject()));
|
||||
EXPECT_TRUE((slice.hasKey(arangodb::StaticStrings::ErrorNum) &&
|
||||
slice.get(arangodb::StaticStrings::ErrorNum).isNumber<int>() &&
|
||||
TRI_ERROR_BAD_PARAMETER == slice.get(arangodb::StaticStrings::ErrorNum).getNumber<int>()));
|
||||
TRI_ERROR_FORBIDDEN == slice.get(arangodb::StaticStrings::ErrorNum).getNumber<int>()));
|
||||
}
|
||||
|
||||
// name collision
|
||||
|
@ -1271,6 +1271,124 @@ TEST_F(V8AnalyzersTest, test_create) {
|
|||
auto analyzer = analyzers->get(arangodb::StaticStrings::SystemDatabase + "::testAnalyzer2");
|
||||
EXPECT_TRUE((false == !analyzer));
|
||||
}
|
||||
// successful creation with DB name prefix
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
arangodb::StaticStrings::SystemDatabase);
|
||||
v8::Isolate::CreateParams isolateParams;
|
||||
ArrayBufferAllocator arrayBufferAllocator;
|
||||
isolateParams.array_buffer_allocator = &arrayBufferAllocator;
|
||||
auto isolate =
|
||||
std::shared_ptr<v8::Isolate>(v8::Isolate::New(isolateParams),
|
||||
[](v8::Isolate* p) -> void { p->Dispose(); });
|
||||
ASSERT_TRUE((nullptr != isolate));
|
||||
v8::Isolate::Scope isolateScope(isolate.get()); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::internal::Isolate::Current()->InitializeLoggingAndCounters(); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::HandleScope handleScope(isolate.get()); // required for v8::Context::New(...), v8::ObjectTemplate::New(...) and TRI_AddMethodVocbase(...)
|
||||
auto context = v8::Context::New(isolate.get());
|
||||
v8::Context::Scope contextScope(context); // required for TRI_AddMethodVocbase(...)
|
||||
std::unique_ptr<TRI_v8_global_t> v8g(TRI_CreateV8Globals(isolate.get(), 0)); // create and set inside 'isolate' for use with 'TRI_GET_GLOBALS()'
|
||||
v8g->ArangoErrorTempl.Reset(isolate.get(), v8::ObjectTemplate::New(isolate.get())); // otherwise v8:-utils::CreateErrorObject(...) will fail
|
||||
v8g->_vocbase = &vocbase;
|
||||
arangodb::iresearch::TRI_InitV8Analyzers(*v8g, isolate.get());
|
||||
|
||||
auto v8Analyzers = v8::Local<v8::ObjectTemplate>::New(isolate.get(), v8g->IResearchAnalyzersTempl)
|
||||
->NewInstance();
|
||||
auto fn_create =
|
||||
v8Analyzers->Get(TRI_V8_ASCII_STRING(isolate.get(), "save"));
|
||||
EXPECT_TRUE((fn_create->IsFunction()));
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {
|
||||
TRI_V8_STD_STRING(isolate.get(), vocbase.name() + "::testAnalyzer3"s),
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "identity"),
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "{\"abc\":1}")
|
||||
};
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
userMap
|
||||
.emplace("", arangodb::auth::User::newUser("", "", arangodb::auth::Source::LDAP))
|
||||
.first->second;
|
||||
user.grantDatabase(vocbase.name(), arangodb::auth::Level::RW); // for system collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
auto result = v8::Function::Cast(*fn_create)
|
||||
->CallAsFunction(context, fn_create,
|
||||
static_cast<int>(args.size()), args.data());
|
||||
EXPECT_TRUE((!result.IsEmpty()));
|
||||
EXPECT_TRUE((result.ToLocalChecked()->IsObject()));
|
||||
auto* v8Analyzer = TRI_UnwrapClass<arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool>(
|
||||
result.ToLocalChecked()->ToObject(TRI_IGETC).FromMaybe(v8::Local<v8::Object>()),
|
||||
WRP_IRESEARCH_ANALYZER_TYPE, TRI_IGETC);
|
||||
EXPECT_TRUE((false == !v8Analyzer));
|
||||
EXPECT_EQ(vocbase.name() + "::testAnalyzer3", v8Analyzer->name());
|
||||
EXPECT_EQ("identity", v8Analyzer->type());
|
||||
EXPECT_EQUAL_SLICES(
|
||||
VPackSlice::emptyObjectSlice(),
|
||||
v8Analyzer->properties());
|
||||
EXPECT_TRUE(v8Analyzer->features().empty());
|
||||
auto analyzer = analyzers->get(vocbase.name() + "::testAnalyzer3");
|
||||
EXPECT_TRUE((false == !analyzer));
|
||||
}
|
||||
// successful creation in system db by :: prefix
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
arangodb::StaticStrings::SystemDatabase);
|
||||
v8::Isolate::CreateParams isolateParams;
|
||||
ArrayBufferAllocator arrayBufferAllocator;
|
||||
isolateParams.array_buffer_allocator = &arrayBufferAllocator;
|
||||
auto isolate =
|
||||
std::shared_ptr<v8::Isolate>(v8::Isolate::New(isolateParams),
|
||||
[](v8::Isolate* p) -> void { p->Dispose(); });
|
||||
ASSERT_TRUE((nullptr != isolate));
|
||||
v8::Isolate::Scope isolateScope(isolate.get()); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::internal::Isolate::Current()->InitializeLoggingAndCounters(); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::HandleScope handleScope(isolate.get()); // required for v8::Context::New(...), v8::ObjectTemplate::New(...) and TRI_AddMethodVocbase(...)
|
||||
auto context = v8::Context::New(isolate.get());
|
||||
v8::Context::Scope contextScope(context); // required for TRI_AddMethodVocbase(...)
|
||||
std::unique_ptr<TRI_v8_global_t> v8g(TRI_CreateV8Globals(isolate.get(), 0)); // create and set inside 'isolate' for use with 'TRI_GET_GLOBALS()'
|
||||
v8g->ArangoErrorTempl.Reset(isolate.get(), v8::ObjectTemplate::New(isolate.get())); // otherwise v8:-utils::CreateErrorObject(...) will fail
|
||||
v8g->_vocbase = &vocbase;
|
||||
arangodb::iresearch::TRI_InitV8Analyzers(*v8g, isolate.get());
|
||||
|
||||
auto v8Analyzers = v8::Local<v8::ObjectTemplate>::New(isolate.get(), v8g->IResearchAnalyzersTempl)
|
||||
->NewInstance();
|
||||
auto fn_create =
|
||||
v8Analyzers->Get(TRI_V8_ASCII_STRING(isolate.get(), "save"));
|
||||
EXPECT_TRUE((fn_create->IsFunction()));
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {
|
||||
TRI_V8_STD_STRING(isolate.get(), "::testAnalyzer4"s),
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "identity"),
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "{\"abc\":1}")
|
||||
};
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
userMap
|
||||
.emplace("", arangodb::auth::User::newUser("", "", arangodb::auth::Source::LDAP))
|
||||
.first->second;
|
||||
user.grantDatabase(vocbase.name(), arangodb::auth::Level::RW); // for system collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
auto result = v8::Function::Cast(*fn_create)
|
||||
->CallAsFunction(context, fn_create,
|
||||
static_cast<int>(args.size()), args.data());
|
||||
EXPECT_TRUE((!result.IsEmpty()));
|
||||
EXPECT_TRUE((result.ToLocalChecked()->IsObject()));
|
||||
auto* v8Analyzer = TRI_UnwrapClass<arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool>(
|
||||
result.ToLocalChecked()->ToObject(TRI_IGETC).FromMaybe(v8::Local<v8::Object>()),
|
||||
WRP_IRESEARCH_ANALYZER_TYPE, TRI_IGETC);
|
||||
EXPECT_TRUE((false == !v8Analyzer));
|
||||
EXPECT_EQ(vocbase.name() + "::testAnalyzer4", v8Analyzer->name());
|
||||
EXPECT_EQ("identity", v8Analyzer->type());
|
||||
EXPECT_EQUAL_SLICES(
|
||||
VPackSlice::emptyObjectSlice(),
|
||||
v8Analyzer->properties());
|
||||
EXPECT_TRUE(v8Analyzer->features().empty());
|
||||
auto analyzer = analyzers->get(vocbase.name() + "::testAnalyzer4");
|
||||
EXPECT_NE(nullptr, analyzer);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(V8AnalyzersTest, test_get) {
|
||||
|
@ -1298,7 +1416,7 @@ TEST_F(V8AnalyzersTest, test_get) {
|
|||
{
|
||||
auto const databases = arangodb::velocypack::Parser::fromJson(
|
||||
std::string("[ { \"name\": \"") +
|
||||
arangodb::StaticStrings::SystemDatabase + "\" } ]");
|
||||
arangodb::StaticStrings::SystemDatabase + "\" }, {\"name\" : \"testVocbase\"} ]");
|
||||
ASSERT_TRUE((TRI_ERROR_NO_ERROR == dbFeature->loadDatabases(databases->slice())));
|
||||
}
|
||||
{
|
||||
|
@ -1307,12 +1425,21 @@ TEST_F(V8AnalyzersTest, test_get) {
|
|||
*vocbase,
|
||||
arangodb::tests::AnalyzerCollectionName);
|
||||
}
|
||||
{
|
||||
auto vocbase = dbFeature->useDatabase("testVocbase");
|
||||
arangodb::methods::Collections::createSystem(
|
||||
*vocbase,
|
||||
arangodb::tests::AnalyzerCollectionName);
|
||||
}
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
ASSERT_TRUE((analyzers
|
||||
->emplace(result, arangodb::StaticStrings::SystemDatabase + "::testAnalyzer1",
|
||||
"identity", VPackSlice::noneSlice())
|
||||
.ok()));
|
||||
|
||||
ASSERT_TRUE((analyzers
|
||||
->emplace(result, "testVocbase::testAnalyzer1",
|
||||
"identity", VPackSlice::noneSlice())
|
||||
.ok()));
|
||||
struct ExecContext : public arangodb::ExecContext {
|
||||
ExecContext()
|
||||
: arangodb::ExecContext(arangodb::ExecContext::Type::Default, "", "",
|
||||
|
@ -1545,6 +1672,122 @@ TEST_F(V8AnalyzersTest, test_get) {
|
|||
EXPECT_TRUE((true == v8Analyzer->features().empty()));
|
||||
}
|
||||
|
||||
// get custom (known analyzer) authorized but wrong current db
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
arangodb::StaticStrings::SystemDatabase);
|
||||
v8::Isolate::CreateParams isolateParams;
|
||||
ArrayBufferAllocator arrayBufferAllocator;
|
||||
isolateParams.array_buffer_allocator = &arrayBufferAllocator;
|
||||
auto isolate =
|
||||
std::shared_ptr<v8::Isolate>(v8::Isolate::New(isolateParams),
|
||||
[](v8::Isolate* p) -> void { p->Dispose(); });
|
||||
ASSERT_TRUE((nullptr != isolate));
|
||||
v8::Isolate::Scope isolateScope(isolate.get()); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::internal::Isolate::Current()->InitializeLoggingAndCounters(); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::HandleScope handleScope(isolate.get()); // required for v8::Context::New(...), v8::ObjectTemplate::New(...) and TRI_AddMethodVocbase(...)
|
||||
auto context = v8::Context::New(isolate.get());
|
||||
v8::Context::Scope contextScope(context); // required for TRI_AddMethodVocbase(...)
|
||||
std::unique_ptr<TRI_v8_global_t> v8g(TRI_CreateV8Globals(isolate.get(), 0)); // create and set inside 'isolate' for use with 'TRI_GET_GLOBALS()'
|
||||
v8g->ArangoErrorTempl.Reset(isolate.get(), v8::ObjectTemplate::New(isolate.get())); // otherwise v8:-utils::CreateErrorObject(...) will fail
|
||||
v8g->_vocbase = &vocbase;
|
||||
arangodb::iresearch::TRI_InitV8Analyzers(*v8g, isolate.get());
|
||||
|
||||
auto v8Analyzers = v8::Local<v8::ObjectTemplate>::New(isolate.get(), v8g->IResearchAnalyzersTempl)
|
||||
->NewInstance();
|
||||
auto fn_get =
|
||||
v8Analyzers->Get(TRI_V8_ASCII_STRING(isolate.get(), "analyzer"));
|
||||
EXPECT_TRUE((fn_get->IsFunction()));
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "testVocbase::testAnalyzer1"),
|
||||
};
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
userMap
|
||||
.emplace("", arangodb::auth::User::newUser("", "", arangodb::auth::Source::LDAP))
|
||||
.first->second;
|
||||
user.grantDatabase(vocbase.name(), arangodb::auth::Level::RO); // for system collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
user.grantDatabase("testVocbase", arangodb::auth::Level::RO);
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
v8::TryCatch tryCatch(isolate.get());
|
||||
arangodb::velocypack::Builder responce;
|
||||
auto result =
|
||||
v8::Function::Cast(*fn_get)->CallAsFunction(context, fn_get,
|
||||
static_cast<int>(args.size()),
|
||||
args.data());
|
||||
EXPECT_TRUE(result.IsEmpty());
|
||||
EXPECT_TRUE(tryCatch.HasCaught());
|
||||
EXPECT_EQ(TRI_ERROR_NO_ERROR, TRI_V8ToVPack(isolate.get(), responce,
|
||||
tryCatch.Exception(), false));
|
||||
auto slice = responce.slice();
|
||||
EXPECT_TRUE((slice.isObject()));
|
||||
EXPECT_TRUE((slice.hasKey(arangodb::StaticStrings::ErrorNum) &&
|
||||
slice.get(arangodb::StaticStrings::ErrorNum).isNumber<int>() &&
|
||||
TRI_ERROR_FORBIDDEN ==
|
||||
slice.get(arangodb::StaticStrings::ErrorNum).getNumber<int>()));
|
||||
}
|
||||
// get custom (known analyzer) authorized from system with another current db
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
"testVocbase");
|
||||
v8::Isolate::CreateParams isolateParams;
|
||||
ArrayBufferAllocator arrayBufferAllocator;
|
||||
isolateParams.array_buffer_allocator = &arrayBufferAllocator;
|
||||
auto isolate =
|
||||
std::shared_ptr<v8::Isolate>(v8::Isolate::New(isolateParams),
|
||||
[](v8::Isolate* p) -> void { p->Dispose(); });
|
||||
ASSERT_TRUE((nullptr != isolate));
|
||||
v8::Isolate::Scope isolateScope(isolate.get()); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::internal::Isolate::Current()->InitializeLoggingAndCounters(); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::HandleScope handleScope(isolate.get()); // required for v8::Context::New(...), v8::ObjectTemplate::New(...) and TRI_AddMethodVocbase(...)
|
||||
auto context = v8::Context::New(isolate.get());
|
||||
v8::Context::Scope contextScope(context); // required for TRI_AddMethodVocbase(...)
|
||||
std::unique_ptr<TRI_v8_global_t> v8g(TRI_CreateV8Globals(isolate.get(), 0)); // create and set inside 'isolate' for use with 'TRI_GET_GLOBALS()'
|
||||
v8g->ArangoErrorTempl.Reset(isolate.get(), v8::ObjectTemplate::New(isolate.get())); // otherwise v8:-utils::CreateErrorObject(...) will fail
|
||||
v8g->_vocbase = &vocbase;
|
||||
arangodb::iresearch::TRI_InitV8Analyzers(*v8g, isolate.get());
|
||||
|
||||
auto v8Analyzers = v8::Local<v8::ObjectTemplate>::New(isolate.get(), v8g->IResearchAnalyzersTempl)
|
||||
->NewInstance();
|
||||
auto fn_get =
|
||||
v8Analyzers->Get(TRI_V8_ASCII_STRING(isolate.get(), "analyzer"));
|
||||
EXPECT_TRUE((fn_get->IsFunction()));
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {
|
||||
TRI_V8_STD_STRING(
|
||||
isolate.get(), arangodb::StaticStrings::SystemDatabase + "::testAnalyzer1"),
|
||||
};
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
userMap
|
||||
.emplace("", arangodb::auth::User::newUser("", "", arangodb::auth::Source::LDAP))
|
||||
.first->second;
|
||||
user.grantDatabase(arangodb::StaticStrings::SystemDatabase, arangodb::auth::Level::RO); // for system collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
user.grantDatabase("testVocbase", arangodb::auth::Level::RO);
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
auto result =
|
||||
v8::Function::Cast(*fn_get)->CallAsFunction(context, fn_get,
|
||||
static_cast<int>(args.size()),
|
||||
args.data());
|
||||
EXPECT_TRUE((!result.IsEmpty()));
|
||||
EXPECT_TRUE((result.ToLocalChecked()->IsObject()));
|
||||
auto* v8Analyzer = TRI_UnwrapClass<arangodb::iresearch::IResearchAnalyzerFeature::AnalyzerPool>(
|
||||
result.ToLocalChecked()->ToObject(TRI_IGETC).FromMaybe(v8::Local<v8::Object>()),
|
||||
WRP_IRESEARCH_ANALYZER_TYPE, TRI_IGETC);
|
||||
EXPECT_TRUE((false == !v8Analyzer));
|
||||
EXPECT_TRUE((arangodb::StaticStrings::SystemDatabase + "::testAnalyzer1" ==
|
||||
v8Analyzer->name()));
|
||||
EXPECT_TRUE((std::string("identity") == v8Analyzer->type()));
|
||||
EXPECT_EQUAL_SLICES(
|
||||
VPackSlice::emptyObjectSlice(),
|
||||
v8Analyzer->properties());
|
||||
EXPECT_TRUE((true == v8Analyzer->features().empty()));
|
||||
}
|
||||
|
||||
// get custom (known analyzer) not authorized
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
|
@ -2293,10 +2536,12 @@ TEST_F(V8AnalyzersTest, test_remove) {
|
|||
arangodb::application_features::ApplicationServer server(nullptr, nullptr);
|
||||
arangodb::iresearch::IResearchAnalyzerFeature* analyzers;
|
||||
arangodb::DatabaseFeature* dbFeature;
|
||||
arangodb::SystemDatabaseFeature* sysDbFeature(new arangodb::SystemDatabaseFeature(server));
|
||||
server.addFeature(new arangodb::QueryRegistryFeature(server)); // required for constructing TRI_vocbase_t
|
||||
server.addFeature(new arangodb::V8DealerFeature(server)); // required for DatabaseFeature::createDatabase(...)
|
||||
server.addFeature(dbFeature = new arangodb::DatabaseFeature(server)); // required for IResearchAnalyzerFeature::emplace(...)
|
||||
server.addFeature(analyzers = new arangodb::iresearch::IResearchAnalyzerFeature(server)); // required for running upgrade task
|
||||
server.addFeature(sysDbFeature);
|
||||
|
||||
auto cleanup = arangodb::scopeGuard([dbFeature](){ dbFeature->unprepare(); });
|
||||
|
||||
|
@ -2304,8 +2549,10 @@ TEST_F(V8AnalyzersTest, test_remove) {
|
|||
{
|
||||
auto const databases = arangodb::velocypack::Parser::fromJson(
|
||||
std::string("[ { \"name\": \"") +
|
||||
arangodb::StaticStrings::SystemDatabase + "\" } ]");
|
||||
arangodb::StaticStrings::SystemDatabase + "\" }, { \"name\" : \"testVocbase\"} ]");
|
||||
ASSERT_TRUE((TRI_ERROR_NO_ERROR == dbFeature->loadDatabases(databases->slice())));
|
||||
sysDbFeature->prepare();
|
||||
sysDbFeature->start();
|
||||
}
|
||||
{
|
||||
auto vocbase = dbFeature->useDatabase(arangodb::StaticStrings::SystemDatabase);
|
||||
|
@ -2313,16 +2560,39 @@ TEST_F(V8AnalyzersTest, test_remove) {
|
|||
*vocbase,
|
||||
arangodb::tests::AnalyzerCollectionName);
|
||||
}
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
ASSERT_TRUE((analyzers
|
||||
->emplace(result, arangodb::StaticStrings::SystemDatabase + "::testAnalyzer1",
|
||||
"identity", VPackSlice::noneSlice())
|
||||
.ok()));
|
||||
ASSERT_TRUE((analyzers
|
||||
->emplace(result, arangodb::StaticStrings::SystemDatabase + "::testAnalyzer2",
|
||||
"identity", VPackSlice::noneSlice())
|
||||
.ok()));
|
||||
|
||||
{
|
||||
auto vocbase = dbFeature->useDatabase("testVocbase");
|
||||
arangodb::methods::Collections::createSystem(
|
||||
*vocbase,
|
||||
arangodb::tests::AnalyzerCollectionName);
|
||||
}
|
||||
{
|
||||
arangodb::iresearch::IResearchAnalyzerFeature::EmplaceResult result;
|
||||
ASSERT_TRUE((analyzers
|
||||
->emplace(result, arangodb::StaticStrings::SystemDatabase + "::testAnalyzer1",
|
||||
"identity", VPackSlice::noneSlice())
|
||||
.ok()));
|
||||
ASSERT_TRUE((analyzers
|
||||
->emplace(result, arangodb::StaticStrings::SystemDatabase + "::testAnalyzer2",
|
||||
"identity", VPackSlice::noneSlice())
|
||||
.ok()));
|
||||
ASSERT_TRUE((analyzers
|
||||
->emplace(result, arangodb::StaticStrings::SystemDatabase + "::testAnalyzer3",
|
||||
"identity", VPackSlice::noneSlice())
|
||||
.ok()));
|
||||
ASSERT_TRUE((analyzers
|
||||
->emplace(result, "testVocbase::testAnalyzer1",
|
||||
"identity", VPackSlice::noneSlice())
|
||||
.ok()));
|
||||
ASSERT_TRUE((analyzers
|
||||
->emplace(result, "testVocbase::testAnalyzer2",
|
||||
"identity", VPackSlice::noneSlice())
|
||||
.ok()));
|
||||
ASSERT_TRUE((analyzers
|
||||
->emplace(result, "testVocbase::testAnalyzer3",
|
||||
"identity", VPackSlice::noneSlice())
|
||||
.ok()));
|
||||
}
|
||||
struct ExecContext : public arangodb::ExecContext {
|
||||
ExecContext()
|
||||
: arangodb::ExecContext(arangodb::ExecContext::Type::Default, "", "",
|
||||
|
@ -2420,7 +2690,7 @@ TEST_F(V8AnalyzersTest, test_remove) {
|
|||
EXPECT_TRUE((fn_remove->IsFunction()));
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {
|
||||
TRI_V8_STD_STRING(isolate.get(), arangodb::StaticStrings::SystemDatabase + "::unknown"),
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "unknown"),
|
||||
};
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
|
@ -2476,7 +2746,7 @@ TEST_F(V8AnalyzersTest, test_remove) {
|
|||
EXPECT_TRUE((fn_remove->IsFunction()));
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {
|
||||
TRI_V8_STD_STRING(isolate.get(), arangodb::StaticStrings::SystemDatabase + "::testAnalyzer1"),
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "testAnalyzer1"),
|
||||
};
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
|
@ -2535,7 +2805,7 @@ TEST_F(V8AnalyzersTest, test_remove) {
|
|||
EXPECT_TRUE((fn_remove->IsFunction()));
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {
|
||||
TRI_V8_STD_STRING(isolate.get(), arangodb::StaticStrings::SystemDatabase + "::testAnalyzer2"),
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "testAnalyzer2"),
|
||||
v8::False(isolate.get()),
|
||||
};
|
||||
auto inUseAnalyzer = analyzers->get(arangodb::StaticStrings::SystemDatabase +
|
||||
|
@ -2598,7 +2868,7 @@ TEST_F(V8AnalyzersTest, test_remove) {
|
|||
EXPECT_TRUE((fn_remove->IsFunction()));
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {
|
||||
TRI_V8_STD_STRING(isolate.get(), arangodb::StaticStrings::SystemDatabase + "::testAnalyzer2"),
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "testAnalyzer2"),
|
||||
v8::True(isolate.get()),
|
||||
};
|
||||
auto inUseAnalyzer = analyzers->get(arangodb::StaticStrings::SystemDatabase +
|
||||
|
@ -2651,7 +2921,7 @@ TEST_F(V8AnalyzersTest, test_remove) {
|
|||
EXPECT_TRUE((fn_remove->IsFunction()));
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {
|
||||
TRI_V8_STD_STRING(isolate.get(), arangodb::StaticStrings::SystemDatabase + "::testAnalyzer1"),
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "testAnalyzer1"),
|
||||
};
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
|
@ -2671,4 +2941,208 @@ TEST_F(V8AnalyzersTest, test_remove) {
|
|||
"::testAnalyzer1");
|
||||
EXPECT_TRUE((true == !analyzer));
|
||||
}
|
||||
// removal by system db name with ::
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
arangodb::StaticStrings::SystemDatabase);
|
||||
v8::Isolate::CreateParams isolateParams;
|
||||
ArrayBufferAllocator arrayBufferAllocator;
|
||||
isolateParams.array_buffer_allocator = &arrayBufferAllocator;
|
||||
auto isolate =
|
||||
std::shared_ptr<v8::Isolate>(v8::Isolate::New(isolateParams),
|
||||
[](v8::Isolate* p) -> void { p->Dispose(); });
|
||||
ASSERT_TRUE((nullptr != isolate));
|
||||
v8::Isolate::Scope isolateScope(isolate.get()); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::internal::Isolate::Current()->InitializeLoggingAndCounters(); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::HandleScope handleScope(isolate.get()); // required for v8::Context::New(...), v8::ObjectTemplate::New(...) and TRI_AddMethodVocbase(...)
|
||||
auto context = v8::Context::New(isolate.get());
|
||||
v8::Context::Scope contextScope(context); // required for TRI_AddMethodVocbase(...)
|
||||
std::unique_ptr<TRI_v8_global_t> v8g(TRI_CreateV8Globals(isolate.get(), 0)); // create and set inside 'isolate' for use with 'TRI_GET_GLOBALS()'
|
||||
v8g->ArangoErrorTempl.Reset(isolate.get(), v8::ObjectTemplate::New(isolate.get())); // otherwise v8:-utils::CreateErrorObject(...) will fail
|
||||
v8g->_vocbase = &vocbase;
|
||||
arangodb::iresearch::TRI_InitV8Analyzers(*v8g, isolate.get());
|
||||
|
||||
auto v8Analyzers = v8::Local<v8::ObjectTemplate>::New(isolate.get(), v8g->IResearchAnalyzersTempl)
|
||||
->NewInstance();
|
||||
auto fn_remove =
|
||||
v8Analyzers->Get(TRI_V8_ASCII_STRING(isolate.get(), "remove"));
|
||||
EXPECT_TRUE((fn_remove->IsFunction()));
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "::testAnalyzer3"),
|
||||
v8::False(isolate.get()),
|
||||
};
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
userMap
|
||||
.emplace("", arangodb::auth::User::newUser("", "", arangodb::auth::Source::LDAP))
|
||||
.first->second;
|
||||
user.grantDatabase(vocbase.name(), arangodb::auth::Level::RW); // for system collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
arangodb::velocypack::Builder responce;
|
||||
v8::TryCatch tryCatch(isolate.get());
|
||||
auto result = v8::Function::Cast(*fn_remove)
|
||||
->CallAsFunction(context, fn_remove,
|
||||
static_cast<int>(args.size()), args.data());
|
||||
EXPECT_TRUE(!result.IsEmpty());
|
||||
EXPECT_TRUE((result.ToLocalChecked()->IsUndefined()));
|
||||
auto analyzer = analyzers->get(arangodb::StaticStrings::SystemDatabase +
|
||||
"::testAnalyzer3");
|
||||
EXPECT_EQ(nullptr, analyzer);
|
||||
}
|
||||
// removal from wrong db
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
arangodb::StaticStrings::SystemDatabase);
|
||||
v8::Isolate::CreateParams isolateParams;
|
||||
ArrayBufferAllocator arrayBufferAllocator;
|
||||
isolateParams.array_buffer_allocator = &arrayBufferAllocator;
|
||||
auto isolate =
|
||||
std::shared_ptr<v8::Isolate>(v8::Isolate::New(isolateParams),
|
||||
[](v8::Isolate* p) -> void { p->Dispose(); });
|
||||
ASSERT_TRUE((nullptr != isolate));
|
||||
v8::Isolate::Scope isolateScope(isolate.get()); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::internal::Isolate::Current()->InitializeLoggingAndCounters(); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::HandleScope handleScope(isolate.get()); // required for v8::Context::New(...), v8::ObjectTemplate::New(...) and TRI_AddMethodVocbase(...)
|
||||
auto context = v8::Context::New(isolate.get());
|
||||
v8::Context::Scope contextScope(context); // required for TRI_AddMethodVocbase(...)
|
||||
std::unique_ptr<TRI_v8_global_t> v8g(TRI_CreateV8Globals(isolate.get(), 0)); // create and set inside 'isolate' for use with 'TRI_GET_GLOBALS()'
|
||||
v8g->ArangoErrorTempl.Reset(isolate.get(), v8::ObjectTemplate::New(isolate.get())); // otherwise v8:-utils::CreateErrorObject(...) will fail
|
||||
v8g->_vocbase = &vocbase;
|
||||
arangodb::iresearch::TRI_InitV8Analyzers(*v8g, isolate.get());
|
||||
|
||||
auto v8Analyzers = v8::Local<v8::ObjectTemplate>::New(isolate.get(), v8g->IResearchAnalyzersTempl)
|
||||
->NewInstance();
|
||||
auto fn_remove =
|
||||
v8Analyzers->Get(TRI_V8_ASCII_STRING(isolate.get(), "remove"));
|
||||
EXPECT_TRUE((fn_remove->IsFunction()));
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "testVocbase::testAnalyzer1"),
|
||||
v8::False(isolate.get()),
|
||||
};
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
userMap
|
||||
.emplace("", arangodb::auth::User::newUser("", "", arangodb::auth::Source::LDAP))
|
||||
.first->second;
|
||||
user.grantDatabase(vocbase.name(), arangodb::auth::Level::RW); // for system collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
user.grantDatabase("testVocbase", arangodb::auth::Level::RW); // for system collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
arangodb::velocypack::Builder responce;
|
||||
v8::TryCatch tryCatch(isolate.get());
|
||||
auto result = v8::Function::Cast(*fn_remove)
|
||||
->CallAsFunction(context, fn_remove,
|
||||
static_cast<int>(args.size()), args.data());
|
||||
EXPECT_TRUE((result.IsEmpty()));
|
||||
EXPECT_TRUE((tryCatch.HasCaught()));
|
||||
EXPECT_TRUE((TRI_ERROR_NO_ERROR == TRI_V8ToVPack(isolate.get(), responce,
|
||||
tryCatch.Exception(), false)));
|
||||
auto slice = responce.slice();
|
||||
EXPECT_TRUE((slice.isObject()));
|
||||
EXPECT_TRUE((slice.hasKey(arangodb::StaticStrings::ErrorNum) &&
|
||||
slice.get(arangodb::StaticStrings::ErrorNum).isNumber<int>() &&
|
||||
TRI_ERROR_FORBIDDEN ==
|
||||
slice.get(arangodb::StaticStrings::ErrorNum).getNumber<int>()));
|
||||
auto analyzer = analyzers->get("testVocbase::testAnalyzer1");
|
||||
EXPECT_NE(nullptr, analyzer);
|
||||
}
|
||||
// success removal from non-system db
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
"testVocbase");
|
||||
v8::Isolate::CreateParams isolateParams;
|
||||
ArrayBufferAllocator arrayBufferAllocator;
|
||||
isolateParams.array_buffer_allocator = &arrayBufferAllocator;
|
||||
auto isolate =
|
||||
std::shared_ptr<v8::Isolate>(v8::Isolate::New(isolateParams),
|
||||
[](v8::Isolate* p) -> void { p->Dispose(); });
|
||||
ASSERT_TRUE((nullptr != isolate));
|
||||
v8::Isolate::Scope isolateScope(isolate.get()); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::internal::Isolate::Current()->InitializeLoggingAndCounters(); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::HandleScope handleScope(isolate.get()); // required for v8::Context::New(...), v8::ObjectTemplate::New(...) and TRI_AddMethodVocbase(...)
|
||||
auto context = v8::Context::New(isolate.get());
|
||||
v8::Context::Scope contextScope(context); // required for TRI_AddMethodVocbase(...)
|
||||
std::unique_ptr<TRI_v8_global_t> v8g(TRI_CreateV8Globals(isolate.get(), 0)); // create and set inside 'isolate' for use with 'TRI_GET_GLOBALS()'
|
||||
v8g->ArangoErrorTempl.Reset(isolate.get(), v8::ObjectTemplate::New(isolate.get())); // otherwise v8:-utils::CreateErrorObject(...) will fail
|
||||
v8g->_vocbase = &vocbase;
|
||||
arangodb::iresearch::TRI_InitV8Analyzers(*v8g, isolate.get());
|
||||
|
||||
auto v8Analyzers = v8::Local<v8::ObjectTemplate>::New(isolate.get(), v8g->IResearchAnalyzersTempl)
|
||||
->NewInstance();
|
||||
auto fn_remove =
|
||||
v8Analyzers->Get(TRI_V8_ASCII_STRING(isolate.get(), "remove"));
|
||||
EXPECT_TRUE((fn_remove->IsFunction()));
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "testAnalyzer2"),
|
||||
};
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
userMap
|
||||
.emplace("", arangodb::auth::User::newUser("", "", arangodb::auth::Source::LDAP))
|
||||
.first->second;
|
||||
user.grantDatabase(vocbase.name(), arangodb::auth::Level::RW); // for system collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
auto result = v8::Function::Cast(*fn_remove)
|
||||
->CallAsFunction(context, fn_remove,
|
||||
static_cast<int>(args.size()), args.data());
|
||||
EXPECT_TRUE(!result.IsEmpty());
|
||||
EXPECT_TRUE((result.ToLocalChecked()->IsUndefined()));
|
||||
auto analyzer = analyzers->get("testVocbase::testAnalyzer2");
|
||||
EXPECT_EQ(nullptr, analyzer);
|
||||
}
|
||||
// success removal with db name prefix
|
||||
{
|
||||
TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1,
|
||||
"testVocbase");
|
||||
v8::Isolate::CreateParams isolateParams;
|
||||
ArrayBufferAllocator arrayBufferAllocator;
|
||||
isolateParams.array_buffer_allocator = &arrayBufferAllocator;
|
||||
auto isolate =
|
||||
std::shared_ptr<v8::Isolate>(v8::Isolate::New(isolateParams),
|
||||
[](v8::Isolate* p) -> void { p->Dispose(); });
|
||||
ASSERT_TRUE((nullptr != isolate));
|
||||
v8::Isolate::Scope isolateScope(isolate.get()); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::internal::Isolate::Current()->InitializeLoggingAndCounters(); // otherwise v8::Isolate::Logger() will fail (called from v8::Exception::Error)
|
||||
v8::HandleScope handleScope(isolate.get()); // required for v8::Context::New(...), v8::ObjectTemplate::New(...) and TRI_AddMethodVocbase(...)
|
||||
auto context = v8::Context::New(isolate.get());
|
||||
v8::Context::Scope contextScope(context); // required for TRI_AddMethodVocbase(...)
|
||||
std::unique_ptr<TRI_v8_global_t> v8g(TRI_CreateV8Globals(isolate.get(), 0)); // create and set inside 'isolate' for use with 'TRI_GET_GLOBALS()'
|
||||
v8g->ArangoErrorTempl.Reset(isolate.get(), v8::ObjectTemplate::New(isolate.get())); // otherwise v8:-utils::CreateErrorObject(...) will fail
|
||||
v8g->_vocbase = &vocbase;
|
||||
arangodb::iresearch::TRI_InitV8Analyzers(*v8g, isolate.get());
|
||||
|
||||
auto v8Analyzers = v8::Local<v8::ObjectTemplate>::New(isolate.get(), v8g->IResearchAnalyzersTempl)
|
||||
->NewInstance();
|
||||
auto fn_remove =
|
||||
v8Analyzers->Get(TRI_V8_ASCII_STRING(isolate.get(), "remove"));
|
||||
EXPECT_TRUE((fn_remove->IsFunction()));
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {
|
||||
TRI_V8_ASCII_STRING(isolate.get(), "testVocbase::testAnalyzer3"),
|
||||
};
|
||||
|
||||
arangodb::auth::UserMap userMap; // empty map, no user -> no permissions
|
||||
auto& user =
|
||||
userMap
|
||||
.emplace("", arangodb::auth::User::newUser("", "", arangodb::auth::Source::LDAP))
|
||||
.first->second;
|
||||
user.grantDatabase(vocbase.name(), arangodb::auth::Level::RW); // for system collections User::collectionAuthLevel(...) returns database auth::Level
|
||||
userManager->setAuthInfo(userMap); // set user map to avoid loading configuration from system database
|
||||
|
||||
auto result = v8::Function::Cast(*fn_remove)
|
||||
->CallAsFunction(context, fn_remove,
|
||||
static_cast<int>(args.size()), args.data());
|
||||
EXPECT_TRUE(!result.IsEmpty());
|
||||
EXPECT_TRUE((result.ToLocalChecked()->IsUndefined()));
|
||||
auto analyzer = analyzers->get("testVocbase::testAnalyzer3");
|
||||
EXPECT_EQ(nullptr, analyzer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -922,7 +922,73 @@ function IResearchFeatureDDLTestSuite () {
|
|||
} // forget variable `view`, it's invalid now
|
||||
assertEqual(db[viewName], undefined);
|
||||
},
|
||||
testLinkWithAnalyzerFromOtherDb: function() {
|
||||
let databaseNameAnalyzer = "testDatabaseAnalyzer";
|
||||
let databaseNameView = "testDatabaseView";
|
||||
let tmpAnalyzerName = "TmpIdentity";
|
||||
let systemAnalyzerName = "SystemIdentity";
|
||||
db._useDatabase("_system");
|
||||
try { db._dropDatabase(databaseNameAnalyzer);} catch(e) {}
|
||||
try { db._dropDatabase(databaseNameView);} catch(e) {}
|
||||
analyzers.save(systemAnalyzerName, "identity");
|
||||
db._createDatabase(databaseNameAnalyzer);
|
||||
db._createDatabase(databaseNameView);
|
||||
db._useDatabase(databaseNameAnalyzer);
|
||||
let tmpIdentity = analyzers.save(tmpAnalyzerName, "identity");
|
||||
assertTrue(tmpIdentity != null);
|
||||
tmpIdentity = undefined;
|
||||
db._useDatabase(databaseNameView);
|
||||
db._create("FOO");
|
||||
try {
|
||||
db._createView("FOO_view", "arangosearch", {links:{"FOO":{analyzers:[databaseNameAnalyzer + "::" + tmpAnalyzerName]}}});
|
||||
fail();
|
||||
} catch(e) {
|
||||
assertEqual(require("internal").errors.ERROR_BAD_PARAMETER.code,
|
||||
e.errorNum);
|
||||
}
|
||||
// but cross-db usage of system analyzers is ok
|
||||
db._createView("FOO_view", "arangosearch", {links:{"FOO":{analyzers:["::" + systemAnalyzerName]}}});
|
||||
db._createView("FOO_view2", "arangosearch", {links:{"FOO":{analyzers:["_system::" + systemAnalyzerName]}}});
|
||||
|
||||
db._useDatabase("_system");
|
||||
db._dropDatabase(databaseNameAnalyzer);
|
||||
db._dropDatabase(databaseNameView);
|
||||
analyzers.remove(systemAnalyzerName, true);
|
||||
},
|
||||
// Commented as this situation is not documented (user should not do this), will be adressed later
|
||||
//testLinkWithAnalyzerFromOtherDbByAnalyzerDefinitions: function() {
|
||||
// let databaseNameAnalyzer = "testDatabaseAnalyzer";
|
||||
// let databaseNameView = "testDatabaseView";
|
||||
|
||||
// db._useDatabase("_system");
|
||||
// try { db._dropDatabase(databaseNameAnalyzer);} catch(e) {}
|
||||
// try { db._dropDatabase(databaseNameView);} catch(e) {}
|
||||
// db._createDatabase(databaseNameAnalyzer);
|
||||
// db._createDatabase(databaseNameView);
|
||||
// db._useDatabase(databaseNameAnalyzer);
|
||||
// db._useDatabase(databaseNameView);
|
||||
// db._create("FOO");
|
||||
// try {
|
||||
// db._createView("FOO_view", "arangosearch",
|
||||
// {
|
||||
// links:{
|
||||
// "FOO":{
|
||||
// analyzerDefinitions:[{name:databaseNameAnalyzer + "::TmpIdentity", type: "identity"}],
|
||||
// analyzers:[databaseNameAnalyzer + "::TmpIdentity"]
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// fail();
|
||||
// } catch(e) {
|
||||
// // analyzerDefinitions should be ignored
|
||||
// // analyzer should not be found
|
||||
// assertEqual(require("internal").errors.ERROR_BAD_PARAMETER.code,
|
||||
// e.errorNum);
|
||||
// }
|
||||
// db._useDatabase("_system");
|
||||
// db._dropDatabase(databaseNameAnalyzer);
|
||||
// db._dropDatabase(databaseNameView);
|
||||
//},
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test ensure that view is deleted within deleted database
|
||||
/// Regression test for arangodb/release-3.4#153.
|
||||
|
@ -930,7 +996,7 @@ function IResearchFeatureDDLTestSuite () {
|
|||
testLeftViewInDroppedDatabase: function () {
|
||||
const dbName = 'TestDB';
|
||||
const viewName = 'TestView';
|
||||
|
||||
db._useDatabase("_system");
|
||||
try { db._dropDatabase(dbName); } catch (e) {}
|
||||
|
||||
db._createDatabase(dbName);
|
||||
|
@ -946,6 +1012,92 @@ function IResearchFeatureDDLTestSuite () {
|
|||
assertEqual(db[viewName], undefined);
|
||||
},
|
||||
|
||||
// test for public issue #9652
|
||||
testAnalyzerWithStopwordsNameConflict : function() {
|
||||
const dbName = "TestNameConflictDB";
|
||||
db._useDatabase("_system");
|
||||
try { db._dropDatabase(dbName); } catch (e) {}
|
||||
|
||||
db._createDatabase(dbName);
|
||||
db._useDatabase(dbName);
|
||||
|
||||
db._create("col1");
|
||||
db._create("col2");
|
||||
analyzers.save("custom_analyzer",
|
||||
"text",
|
||||
{
|
||||
locale: "en.UTF-8",
|
||||
case: "lower",
|
||||
stopwords: ["the", "of", "inc", "co", "plc", "ltd", "ag"],
|
||||
accent: false,
|
||||
stemming: false
|
||||
},
|
||||
["position", "norm","frequency"]);
|
||||
|
||||
let v = db._createView("view1", "arangosearch", {
|
||||
"links": {
|
||||
"col1": {
|
||||
"analyzers": ["identity"],
|
||||
"fields": { "name": { "analyzers": ["custom_analyzer"]}},
|
||||
"includeAllFields": false,
|
||||
"storeValues": "none",
|
||||
"trackListPositions": false
|
||||
},
|
||||
"col2": {
|
||||
"analyzers": ["identity"],
|
||||
"fields": { "name": { "analyzers": ["custom_analyzer"]}},
|
||||
"includeAllFields": false,
|
||||
"storeValues": "none",
|
||||
"trackListPositions": false
|
||||
}
|
||||
}});
|
||||
let properties = v.properties();
|
||||
assertTrue(Object === properties.links.constructor);
|
||||
assertEqual(2, Object.keys(properties.links).length);
|
||||
|
||||
assertTrue(Object === properties.links.col1.constructor);
|
||||
assertTrue(Object === properties.links.col1.fields.constructor);
|
||||
assertEqual(1, Object.keys(properties.links.col1.fields).length);
|
||||
assertTrue(Object === properties.links.col1.fields.name.constructor);
|
||||
assertTrue(Array === properties.links.col1.fields.name.analyzers.constructor);
|
||||
assertEqual(1, properties.links.col1.fields.name.analyzers.length);
|
||||
assertTrue(String === properties.links.col1.fields.name.analyzers[0].constructor);
|
||||
assertEqual("custom_analyzer", properties.links.col1.fields.name.analyzers[0]);
|
||||
assertTrue(Boolean === properties.links.col1.includeAllFields.constructor);
|
||||
assertEqual(false, properties.links.col1.includeAllFields);
|
||||
assertTrue(Boolean === properties.links.col1.trackListPositions.constructor);
|
||||
assertEqual(false, properties.links.col1.trackListPositions);
|
||||
assertTrue(String === properties.links.col1.storeValues.constructor);
|
||||
assertEqual("none", properties.links.col1.storeValues);
|
||||
assertTrue(Array === properties.links.col1.analyzers.constructor);
|
||||
assertEqual(1, properties.links.col1.analyzers.length);
|
||||
assertTrue(String === properties.links.col1.analyzers[0].constructor);
|
||||
assertEqual("identity", properties.links.col1.analyzers[0]);
|
||||
|
||||
|
||||
assertTrue(Object === properties.links.col2.constructor);
|
||||
assertTrue(Object === properties.links.col2.fields.constructor);
|
||||
assertEqual(1, Object.keys(properties.links.col2.fields).length);
|
||||
assertTrue(Object === properties.links.col2.fields.name.constructor);
|
||||
assertTrue(Array === properties.links.col2.fields.name.analyzers.constructor);
|
||||
assertEqual(1, properties.links.col2.fields.name.analyzers.length);
|
||||
assertTrue(String === properties.links.col2.fields.name.analyzers[0].constructor);
|
||||
assertEqual("custom_analyzer", properties.links.col2.fields.name.analyzers[0]);
|
||||
assertTrue(Boolean === properties.links.col2.includeAllFields.constructor);
|
||||
assertEqual(false, properties.links.col2.includeAllFields);
|
||||
assertTrue(Boolean === properties.links.col2.trackListPositions.constructor);
|
||||
assertEqual(false, properties.links.col2.trackListPositions);
|
||||
assertTrue(String === properties.links.col2.storeValues.constructor);
|
||||
assertEqual("none", properties.links.col2.storeValues);
|
||||
assertTrue(Array === properties.links.col2.analyzers.constructor);
|
||||
assertEqual(1, properties.links.col2.analyzers.length);
|
||||
assertTrue(String === properties.links.col2.analyzers[0].constructor);
|
||||
assertEqual("identity", properties.links.col2.analyzers[0]);
|
||||
|
||||
db._useDatabase("_system");
|
||||
db._dropDatabase(dbName);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -899,7 +899,73 @@ function IResearchFeatureDDLTestSuite () {
|
|||
assertEqual(i, r.z);
|
||||
});
|
||||
},
|
||||
testLinkWithAnalyzerFromOtherDb: function() {
|
||||
let databaseNameAnalyzer = "testDatabaseAnalyzer";
|
||||
let databaseNameView = "testDatabaseView";
|
||||
let tmpAnalyzerName = "TmpIdentity";
|
||||
let systemAnalyzerName = "SystemIdentity";
|
||||
db._useDatabase("_system");
|
||||
try { db._dropDatabase(databaseNameAnalyzer);} catch(e) {}
|
||||
try { db._dropDatabase(databaseNameView);} catch(e) {}
|
||||
analyzers.save(systemAnalyzerName, "identity");
|
||||
db._createDatabase(databaseNameAnalyzer);
|
||||
db._createDatabase(databaseNameView);
|
||||
db._useDatabase(databaseNameAnalyzer);
|
||||
let tmpIdentity = analyzers.save(tmpAnalyzerName, "identity");
|
||||
assertTrue(tmpIdentity != null);
|
||||
tmpIdentity = undefined;
|
||||
db._useDatabase(databaseNameView);
|
||||
db._create("FOO");
|
||||
try {
|
||||
db._createView("FOO_view", "arangosearch", {links:{"FOO":{analyzers:[databaseNameAnalyzer + "::" + tmpAnalyzerName]}}});
|
||||
fail();
|
||||
} catch(e) {
|
||||
assertEqual(require("internal").errors.ERROR_BAD_PARAMETER.code,
|
||||
e.errorNum);
|
||||
}
|
||||
// but cross-db usage of system analyzers is ok
|
||||
db._createView("FOO_view", "arangosearch", {links:{"FOO":{analyzers:["::" + systemAnalyzerName]}}});
|
||||
db._createView("FOO_view2", "arangosearch", {links:{"FOO":{analyzers:["_system::" + systemAnalyzerName]}}});
|
||||
|
||||
db._useDatabase("_system");
|
||||
db._dropDatabase(databaseNameAnalyzer);
|
||||
db._dropDatabase(databaseNameView);
|
||||
analyzers.remove(systemAnalyzerName, true);
|
||||
},
|
||||
// Commented as this situation is not documented (user should not do this), will be adressed later
|
||||
//testLinkWithAnalyzerFromOtherDbByAnalyzerDefinitions: function() {
|
||||
// let databaseNameAnalyzer = "testDatabaseAnalyzer";
|
||||
// let databaseNameView = "testDatabaseView";
|
||||
//
|
||||
// db._useDatabase("_system");
|
||||
// try { db._dropDatabase(databaseNameAnalyzer);} catch(e) {}
|
||||
// try { db._dropDatabase(databaseNameView);} catch(e) {}
|
||||
// db._createDatabase(databaseNameAnalyzer);
|
||||
// db._createDatabase(databaseNameView);
|
||||
// db._useDatabase(databaseNameAnalyzer);
|
||||
// db._useDatabase(databaseNameView);
|
||||
// db._create("FOO");
|
||||
// try {
|
||||
// db._createView("FOO_view", "arangosearch",
|
||||
// {
|
||||
// links:{
|
||||
// "FOO":{
|
||||
// analyzerDefinitions:[{name:databaseNameAnalyzer + "::TmpIdentity", type: "identity"}],
|
||||
// analyzers:[databaseNameAnalyzer + "::TmpIdentity"]
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// fail();
|
||||
// } catch(e) {
|
||||
// // analyzerDefinitions should be ignored
|
||||
// // analyzer should not be found
|
||||
// assertEqual(require("internal").errors.ERROR_BAD_PARAMETER.code,
|
||||
// e.errorNum);
|
||||
// }
|
||||
// db._useDatabase("_system");
|
||||
// db._dropDatabase(databaseNameAnalyzer);
|
||||
// db._dropDatabase(databaseNameView);
|
||||
//},
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test create & drop of a view with a link.
|
||||
/// Regression test for arangodb/backlog#486.
|
||||
|
@ -930,7 +996,7 @@ function IResearchFeatureDDLTestSuite () {
|
|||
testLeftViewInDroppedDatabase: function () {
|
||||
const dbName = 'TestDB';
|
||||
const viewName = 'TestView';
|
||||
|
||||
db._useDatabase("_system");
|
||||
try { db._dropDatabase(dbName); } catch (e) {}
|
||||
|
||||
db._createDatabase(dbName);
|
||||
|
@ -946,6 +1012,92 @@ function IResearchFeatureDDLTestSuite () {
|
|||
assertEqual(db[viewName], undefined);
|
||||
},
|
||||
|
||||
// test for public issue #9652
|
||||
testAnalyzerWithStopwordsNameConflict : function() {
|
||||
const dbName = "TestNameConflictDB";
|
||||
db._useDatabase("_system");
|
||||
try { db._dropDatabase(dbName); } catch (e) {}
|
||||
|
||||
db._createDatabase(dbName);
|
||||
db._useDatabase(dbName);
|
||||
|
||||
db._create("col1");
|
||||
db._create("col2");
|
||||
analyzers.save("custom_analyzer",
|
||||
"text",
|
||||
{
|
||||
locale: "en.UTF-8",
|
||||
case: "lower",
|
||||
stopwords: ["the", "of", "inc", "co", "plc", "ltd", "ag"],
|
||||
accent: false,
|
||||
stemming: false
|
||||
},
|
||||
["position", "norm","frequency"]);
|
||||
|
||||
let v = db._createView("view1", "arangosearch", {
|
||||
"links": {
|
||||
"col1": {
|
||||
"analyzers": ["identity"],
|
||||
"fields": { "name": { "analyzers": ["custom_analyzer"]}},
|
||||
"includeAllFields": false,
|
||||
"storeValues": "none",
|
||||
"trackListPositions": false
|
||||
},
|
||||
"col2": {
|
||||
"analyzers": ["identity"],
|
||||
"fields": { "name": { "analyzers": ["custom_analyzer"]}},
|
||||
"includeAllFields": false,
|
||||
"storeValues": "none",
|
||||
"trackListPositions": false
|
||||
}
|
||||
}});
|
||||
let properties = v.properties();
|
||||
assertTrue(Object === properties.links.constructor);
|
||||
assertEqual(2, Object.keys(properties.links).length);
|
||||
|
||||
assertTrue(Object === properties.links.col1.constructor);
|
||||
assertTrue(Object === properties.links.col1.fields.constructor);
|
||||
assertEqual(1, Object.keys(properties.links.col1.fields).length);
|
||||
assertTrue(Object === properties.links.col1.fields.name.constructor);
|
||||
assertTrue(Array === properties.links.col1.fields.name.analyzers.constructor);
|
||||
assertEqual(1, properties.links.col1.fields.name.analyzers.length);
|
||||
assertTrue(String === properties.links.col1.fields.name.analyzers[0].constructor);
|
||||
assertEqual("custom_analyzer", properties.links.col1.fields.name.analyzers[0]);
|
||||
assertTrue(Boolean === properties.links.col1.includeAllFields.constructor);
|
||||
assertEqual(false, properties.links.col1.includeAllFields);
|
||||
assertTrue(Boolean === properties.links.col1.trackListPositions.constructor);
|
||||
assertEqual(false, properties.links.col1.trackListPositions);
|
||||
assertTrue(String === properties.links.col1.storeValues.constructor);
|
||||
assertEqual("none", properties.links.col1.storeValues);
|
||||
assertTrue(Array === properties.links.col1.analyzers.constructor);
|
||||
assertEqual(1, properties.links.col1.analyzers.length);
|
||||
assertTrue(String === properties.links.col1.analyzers[0].constructor);
|
||||
assertEqual("identity", properties.links.col1.analyzers[0]);
|
||||
|
||||
|
||||
assertTrue(Object === properties.links.col2.constructor);
|
||||
assertTrue(Object === properties.links.col2.fields.constructor);
|
||||
assertEqual(1, Object.keys(properties.links.col2.fields).length);
|
||||
assertTrue(Object === properties.links.col2.fields.name.constructor);
|
||||
assertTrue(Array === properties.links.col2.fields.name.analyzers.constructor);
|
||||
assertEqual(1, properties.links.col2.fields.name.analyzers.length);
|
||||
assertTrue(String === properties.links.col2.fields.name.analyzers[0].constructor);
|
||||
assertEqual("custom_analyzer", properties.links.col2.fields.name.analyzers[0]);
|
||||
assertTrue(Boolean === properties.links.col2.includeAllFields.constructor);
|
||||
assertEqual(false, properties.links.col2.includeAllFields);
|
||||
assertTrue(Boolean === properties.links.col2.trackListPositions.constructor);
|
||||
assertEqual(false, properties.links.col2.trackListPositions);
|
||||
assertTrue(String === properties.links.col2.storeValues.constructor);
|
||||
assertEqual("none", properties.links.col2.storeValues);
|
||||
assertTrue(Array === properties.links.col2.analyzers.constructor);
|
||||
assertEqual(1, properties.links.col2.analyzers.length);
|
||||
assertTrue(String === properties.links.col2.analyzers[0].constructor);
|
||||
assertEqual("identity", properties.links.col2.analyzers[0]);
|
||||
|
||||
db._useDatabase("_system");
|
||||
db._dropDatabase(dbName);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*jshint globalstrict:false, strict:false, maxlen: 500 */
|
||||
/*global assertUndefined, assertEqual, assertTrue, assertFalse, fail, db._query */
|
||||
/*global assertUndefined, assertEqual, assertTrue, assertFalse, assertNotNull, fail, db._query */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
|
@ -55,42 +55,149 @@ function iResearchFeatureAqlTestSuite () {
|
|||
|
||||
testAnalyzersInvalidPropertiesDiscarded : function() {
|
||||
{
|
||||
try {analyzers.remove(db._name() + "::normPropAnalyzer"); } catch (e) {}
|
||||
try {analyzers.remove("normPropAnalyzer"); } catch (e) {}
|
||||
let analyzer = analyzers.save("normPropAnalyzer", "norm", { "locale":"en", "invalid_param":true});
|
||||
assertTrue(null != analyzer);
|
||||
assertTrue(null == analyzer.properties.invalid_param);
|
||||
analyzers.remove(db._name() + "::normPropAnalyzer", true);
|
||||
analyzers.remove("normPropAnalyzer", true);
|
||||
}
|
||||
{
|
||||
try {analyzers.remove(db._name() + "::textPropAnalyzer"); } catch (e) {}
|
||||
try {analyzers.remove("textPropAnalyzer"); } catch (e) {}
|
||||
let analyzer = analyzers.save("textPropAnalyzer", "text", {"stopwords" : [], "locale":"en", "invalid_param":true});
|
||||
assertTrue(null != analyzer);
|
||||
assertTrue(null == analyzer.properties.invalid_param);
|
||||
analyzers.remove(db._name() + "::textPropAnalyzer", true);
|
||||
analyzers.remove("textPropAnalyzer", true);
|
||||
}
|
||||
{
|
||||
try {analyzers.remove(db._name() + "::delimiterPropAnalyzer"); } catch (e) {}
|
||||
try {analyzers.remove("delimiterPropAnalyzer"); } catch (e) {}
|
||||
let analyzer = analyzers.save("delimiterPropAnalyzer", "delimiter", { "delimiter":"|", "invalid_param":true});
|
||||
assertTrue(null != analyzer);
|
||||
assertTrue(null == analyzer.properties.invalid_param);
|
||||
analyzers.remove(db._name() + "::delimiterPropAnalyzer", true);
|
||||
analyzers.remove("delimiterPropAnalyzer", true);
|
||||
}
|
||||
{
|
||||
try {analyzers.remove(db._name() + "::stemPropAnalyzer"); } catch (e) {}
|
||||
try {analyzers.remove("stemPropAnalyzer"); } catch (e) {}
|
||||
let analyzer = analyzers.save("stemPropAnalyzer", "stem", { "locale":"en", "invalid_param":true});
|
||||
assertTrue(null != analyzer);
|
||||
assertTrue(null == analyzer.properties.invalid_param);
|
||||
analyzers.remove(db._name() + "::stemPropAnalyzer", true);
|
||||
analyzers.remove("stemPropAnalyzer", true);
|
||||
}
|
||||
{
|
||||
try {analyzers.remove(db._name() + "::ngramPropAnalyzer"); } catch (e) {}
|
||||
try {analyzers.remove("ngramPropAnalyzer"); } catch (e) {}
|
||||
let analyzer = analyzers.save("ngramPropAnalyzer", "ngram", { "min":1, "max":5, "preserveOriginal":true, "invalid_param":true});
|
||||
assertTrue(null != analyzer);
|
||||
assertTrue(null == analyzer.properties.invalid_param);
|
||||
analyzers.remove(db._name() + "::ngramPropAnalyzer", true);
|
||||
analyzers.remove("ngramPropAnalyzer", true);
|
||||
}
|
||||
},
|
||||
|
||||
testAnalyzerRemovalWithDatabaseName_InSystem: function() {
|
||||
let dbName = "analyzerWrongDbName1";
|
||||
db._useDatabase("_system");
|
||||
try { db._dropDatabase(dbName); } catch (e) {}
|
||||
db._createDatabase(dbName);
|
||||
db._useDatabase(dbName);
|
||||
analyzers.save("MyTrigram", "ngram", { min: 2, max: 3, preserveOriginal: true });
|
||||
db._useDatabase("_system");
|
||||
try {
|
||||
analyzers.remove(dbName + "::MyTrigram");
|
||||
fail(); // removal with db name in wrong current used db should also fail
|
||||
} catch(e) {
|
||||
assertEqual(require("internal").errors.ERROR_FORBIDDEN .code,
|
||||
e.errorNum);
|
||||
}
|
||||
db._useDatabase(dbName);
|
||||
analyzers.remove(dbName + "::MyTrigram", true);
|
||||
db._useDatabase("_system");
|
||||
db._dropDatabase(dbName);
|
||||
},
|
||||
testAnalyzerCreateRemovalWithDatabaseName_InDb: function() {
|
||||
let dbName = "analyzerWrongDbName2";
|
||||
db._useDatabase("_system");
|
||||
try { db._dropDatabase(dbName); } catch (e) {}
|
||||
db._createDatabase(dbName);
|
||||
try {
|
||||
analyzers.save(dbName + "::MyTrigram", "ngram", { min: 2, max: 3, preserveOriginal: true });
|
||||
fail();
|
||||
} catch(e) {
|
||||
assertEqual(require("internal").errors.ERROR_FORBIDDEN.code,
|
||||
e.errorNum);
|
||||
}
|
||||
db._useDatabase(dbName);
|
||||
analyzers.save(dbName + "::MyTrigram", "ngram", { min: 2, max: 3, preserveOriginal: true });
|
||||
analyzers.remove(dbName + "::MyTrigram", true);
|
||||
db._useDatabase("_system");
|
||||
db._dropDatabase(dbName);
|
||||
},
|
||||
testAnalyzerCreateRemovalWithDatabaseName_InSystem: function() {
|
||||
let dbName = "analyzerWrongDbName3";
|
||||
db._useDatabase("_system");
|
||||
try { db._dropDatabase(dbName); } catch (e) {}
|
||||
try { analyzers.remove("MyTrigram"); } catch (e) {}
|
||||
db._createDatabase(dbName);
|
||||
db._useDatabase(dbName);
|
||||
// cross-db request should fail
|
||||
try {
|
||||
analyzers.save("::MyTrigram", "ngram", { min: 2, max: 3, preserveOriginal: true });
|
||||
fail();
|
||||
} catch(e) {
|
||||
assertEqual(require("internal").errors.ERROR_FORBIDDEN.code,
|
||||
e.errorNum);
|
||||
}
|
||||
try {
|
||||
analyzers.save("_system::MyTrigram", "ngram", { min: 2, max: 3, preserveOriginal: true });
|
||||
fail();
|
||||
} catch(e) {
|
||||
assertEqual(require("internal").errors.ERROR_FORBIDDEN.code,
|
||||
e.errorNum);
|
||||
}
|
||||
// in _system db requests should be ok
|
||||
db._useDatabase("_system");
|
||||
analyzers.save("::MyTrigram", "ngram", { min: 2, max: 3, preserveOriginal: true });
|
||||
analyzers.remove("::MyTrigram", true);
|
||||
analyzers.save("_system::MyTrigram", "ngram", { min: 2, max: 3, preserveOriginal: true });
|
||||
analyzers.remove("_system::MyTrigram", true);
|
||||
db._dropDatabase(dbName);
|
||||
},
|
||||
testAnalyzerInvalidName: function() {
|
||||
let dbName = "analyzerWrongDbName4";
|
||||
db._useDatabase("_system");
|
||||
try { db._dropDatabase(dbName); } catch (e) {}
|
||||
db._createDatabase(dbName);
|
||||
db._useDatabase(dbName);
|
||||
try {
|
||||
// invalid ':' in name
|
||||
analyzers.save(dbName + "::MyTr:igram", "ngram", { min: 2, max: 3, preserveOriginal: true });
|
||||
fail();
|
||||
} catch(e) {
|
||||
assertEqual(require("internal").errors.ERROR_BAD_PARAMETER.code,
|
||||
e.errorNum);
|
||||
}
|
||||
db._useDatabase("_system");
|
||||
db._dropDatabase(dbName);
|
||||
},
|
||||
testAnalyzerGetFromOtherDatabase: function() {
|
||||
let dbName = "analyzerDbName";
|
||||
let anotherDbName = "anotherDbName";
|
||||
db._useDatabase("_system");
|
||||
try { db._dropDatabase(dbName); } catch (e) {}
|
||||
try { db._dropDatabase(anotherDbName); } catch (e) {}
|
||||
db._createDatabase(dbName);
|
||||
db._createDatabase(anotherDbName);
|
||||
db._useDatabase(dbName);
|
||||
let analyzer = analyzers.save("MyTrigram", "ngram", { min: 2, max: 3, preserveOriginal: true });
|
||||
assertNotNull(analyzer);
|
||||
db._useDatabase(anotherDbName);
|
||||
try {
|
||||
analyzers.analyzer(dbName + "::MyTrigram");
|
||||
fail();
|
||||
} catch(e) {
|
||||
assertEqual(require("internal").errors.ERROR_FORBIDDEN .code,
|
||||
e.errorNum);
|
||||
}
|
||||
db._useDatabase("_system");
|
||||
db._dropDatabase(dbName);
|
||||
db._dropDatabase(anotherDbName);
|
||||
},
|
||||
testAnalyzers: function() {
|
||||
let oldList = analyzers.toArray();
|
||||
let oldListInCollection = db._analyzers.toArray();
|
||||
|
@ -146,7 +253,7 @@ function iResearchFeatureAqlTestSuite () {
|
|||
}
|
||||
|
||||
// removal
|
||||
analyzers.remove(db._name() + "::testAnalyzer");
|
||||
analyzers.remove("testAnalyzer");
|
||||
assertTrue(null === analyzers.analyzer(db._name() + "::testAnalyzer"));
|
||||
assertEqual(oldList.length, analyzers.toArray().length);
|
||||
// check the analyzers collection in database
|
||||
|
@ -173,7 +280,7 @@ function iResearchFeatureAqlTestSuite () {
|
|||
|
||||
testAnalyzersPrefix: function() {
|
||||
let dbName = "TestDB";
|
||||
|
||||
db._useDatabase("_system");
|
||||
try { db._dropDatabase(dbName); } catch (e) {}
|
||||
db._createDatabase(dbName);
|
||||
db._useDatabase(dbName);
|
||||
|
@ -187,31 +294,6 @@ function iResearchFeatureAqlTestSuite () {
|
|||
db._useDatabase(dbName);
|
||||
analyzers.save("testAnalyzer", "identity", {}, [ "norm" ]);
|
||||
|
||||
// retrieval (system)
|
||||
db._useDatabase("_system");
|
||||
|
||||
{
|
||||
let analyzer = analyzers.analyzer("testAnalyzer");
|
||||
assertTrue(null !== analyzer);
|
||||
assertEqual(db._name() + "::testAnalyzer", analyzer.name());
|
||||
assertEqual("identity", analyzer.type());
|
||||
assertEqual(0, Object.keys(analyzer.properties()).length);
|
||||
assertTrue(Array === analyzer.features().constructor);
|
||||
assertEqual(1, analyzer.features().length);
|
||||
assertEqual([ "frequency" ], analyzer.features());
|
||||
}
|
||||
|
||||
{
|
||||
let analyzer = analyzers.analyzer(dbName + "::testAnalyzer");
|
||||
assertTrue(null !== analyzer);
|
||||
assertEqual(dbName + "::testAnalyzer", analyzer.name());
|
||||
assertEqual("identity", analyzer.type());
|
||||
assertEqual(0, Object.keys(analyzer.properties()).length);
|
||||
assertTrue(Array === analyzer.features().constructor);
|
||||
assertEqual(1, analyzer.features().length);
|
||||
assertEqual([ "norm" ], analyzer.features());
|
||||
}
|
||||
|
||||
// retrieval (dbName)
|
||||
db._useDatabase(dbName);
|
||||
|
||||
|
@ -245,7 +327,9 @@ function iResearchFeatureAqlTestSuite () {
|
|||
// removal
|
||||
analyzers.remove("testAnalyzer", true);
|
||||
assertTrue(null === analyzers.analyzer("testAnalyzer"));
|
||||
analyzers.remove("::testAnalyzer", true);
|
||||
db._useDatabase("_system");
|
||||
analyzers.remove("testAnalyzer", true);
|
||||
db._useDatabase(dbName); // switch back to check analyzer with global name
|
||||
assertTrue(null === analyzers.analyzer("::testAnalyzer"));
|
||||
assertEqual(oldList.length, analyzers.toArray().length);
|
||||
|
||||
|
|
|
@ -184,10 +184,17 @@ function ViewSuite () {
|
|||
var def = db._createView("def", "arangosearch", {});
|
||||
assertEqual(def.name(), "def");
|
||||
var views = db._views();
|
||||
|
||||
let expectedViews = new Set();
|
||||
expectedViews.add(abc.name());
|
||||
expectedViews.add(def.name());
|
||||
|
||||
assertTrue(Array.isArray(views));
|
||||
assertEqual(views.length, 2);
|
||||
assertEqual(abc.name(), views[0].name());
|
||||
assertEqual(def.name(), views[1].name());
|
||||
assertEqual(views.length, expectedViews.size);
|
||||
for (var i = 0; i < views.length; i++) {
|
||||
expectedViews.delete(views[i].name());
|
||||
}
|
||||
assertEqual(0, expectedViews.size);
|
||||
abc.drop();
|
||||
def.drop();
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue