summaryrefslogtreecommitdiffstats
path: root/searchcore/src/tests/proton
diff options
context:
space:
mode:
Diffstat (limited to 'searchcore/src/tests/proton')
-rw-r--r--searchcore/src/tests/proton/attribute/attribute_test.cpp179
-rw-r--r--searchcore/src/tests/proton/attribute/document_field_extractor/document_field_extractor_test.cpp33
-rw-r--r--searchcore/src/tests/proton/documentdb/feedview/feedview_test.cpp53
-rw-r--r--searchcore/src/tests/proton/feedoperation/feedoperation_test.cpp7
-rw-r--r--searchcore/src/tests/proton/matching/matching_test.cpp73
-rw-r--r--searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp142
6 files changed, 314 insertions, 173 deletions
diff --git a/searchcore/src/tests/proton/attribute/attribute_test.cpp b/searchcore/src/tests/proton/attribute/attribute_test.cpp
index ee5f29255fb..634f69a3820 100644
--- a/searchcore/src/tests/proton/attribute/attribute_test.cpp
+++ b/searchcore/src/tests/proton/attribute/attribute_test.cpp
@@ -1,6 +1,4 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/log/log.h>
-LOG_SETUP("attribute_test");
#include <vespa/config-attributes.h>
#include <vespa/document/fieldvalue/document.h>
@@ -15,6 +13,7 @@ LOG_SETUP("attribute_test");
#include <vespa/searchcommon/attribute/attributecontent.h>
#include <vespa/searchcore/proton/attribute/attribute_collection_spec_factory.h>
#include <vespa/searchcore/proton/attribute/attribute_writer.h>
+#include <vespa/searchcore/proton/attribute/ifieldupdatecallback.h>
#include <vespa/searchcore/proton/attribute/attributemanager.h>
#include <vespa/searchcore/proton/attribute/filter_attribute_manager.h>
#include <vespa/searchcore/proton/attribute/imported_attributes_repo.h>
@@ -44,6 +43,9 @@ LOG_SETUP("attribute_test");
#include <vespa/vespalib/testkit/testapp.h>
#include <vespa/searchcommon/attribute/iattributevector.h>
+#include <vespa/log/log.h>
+LOG_SETUP("attribute_test");
+
namespace vespa { namespace config { namespace search {}}}
using namespace config;
@@ -139,6 +141,7 @@ struct Fixture
: Fixture(1)
{
}
+ ~Fixture();
void allocAttributeWriter() {
_aw = std::make_unique<AttributeWriter>(_m);
}
@@ -155,8 +158,12 @@ struct Fixture
_aw->put(serialNum, doc, lid, immediateCommit, emptyCallback);
}
void update(SerialNum serialNum, const DocumentUpdate &upd,
+ DocumentIdT lid, bool immediateCommit, IFieldUpdateCallback & onUpdate) {
+ _aw->update(serialNum, upd, lid, immediateCommit, emptyCallback, onUpdate);
+ }
+ void update(SerialNum serialNum, const Document &doc,
DocumentIdT lid, bool immediateCommit) {
- _aw->update(serialNum, upd, lid, immediateCommit, emptyCallback);
+ _aw->update(serialNum, doc, lid, immediateCommit, emptyCallback);
}
void remove(SerialNum serialNum, DocumentIdT lid, bool immediateCommit = true) {
_aw->remove(serialNum, lid, immediateCommit, emptyCallback);
@@ -172,6 +179,7 @@ struct Fixture
}
};
+Fixture::~Fixture() = default;
TEST_F("require that attribute writer handles put", Fixture)
{
@@ -442,8 +450,9 @@ TEST_F("require that attribute writer handles update", Fixture)
upd.addUpdate(FieldUpdate(upd.getType().getField("a2"))
.addUpdate(ArithmeticValueUpdate(ArithmeticValueUpdate::Add, 10)));
+ DummyFieldUpdateCallback onUpdate;
bool immediateCommit = true;
- f.update(2, upd, 1, immediateCommit);
+ f.update(2, upd, 1, immediateCommit, onUpdate);
attribute::IntegerContent ibuf;
ibuf.fill(*a1, 1);
@@ -453,9 +462,9 @@ TEST_F("require that attribute writer handles update", Fixture)
EXPECT_EQUAL(1u, ibuf.size());
EXPECT_EQUAL(30u, ibuf[0]);
- f.update(2, upd, 1, immediateCommit); // same sync token as previous
+ f.update(2, upd, 1, immediateCommit, onUpdate); // same sync token as previous
try {
- f.update(1, upd, 1, immediateCommit); // lower sync token than previous
+ f.update(1, upd, 1, immediateCommit, onUpdate); // lower sync token than previous
EXPECT_TRUE(true); // update is ignored
} catch (vespalib::IllegalStateException & e) {
LOG(info, "Got expected exception: '%s'", e.getMessage().c_str());
@@ -488,7 +497,8 @@ TEST_F("require that attribute writer handles predicate update", Fixture)
EXPECT_EQUAL(1u, index.getZeroConstraintDocs().size());
EXPECT_FALSE(index.getIntervalIndex().lookup(PredicateHash::hash64("foo=bar")).valid());
bool immediateCommit = true;
- f.update(2, upd, 1, immediateCommit);
+ DummyFieldUpdateCallback onUpdate;
+ f.update(2, upd, 1, immediateCommit, onUpdate);
EXPECT_EQUAL(0u, index.getZeroConstraintDocs().size());
EXPECT_TRUE(index.getIntervalIndex().lookup(PredicateHash::hash64("foo=bar")).valid());
}
@@ -675,7 +685,8 @@ TEST_F("require that attribute writer handles tensor assign update", Fixture)
upd.addUpdate(FieldUpdate(upd.getType().getField("a1"))
.addUpdate(AssignValueUpdate(new_value)));
bool immediateCommit = true;
- f.update(2, upd, 1, immediateCommit);
+ DummyFieldUpdateCallback onUpdate;
+ f.update(2, upd, 1, immediateCommit, onUpdate);
EXPECT_EQUAL(2u, a1->getNumDocs());
EXPECT_TRUE(tensorAttribute != nullptr);
tensor2 = tensorAttribute->getTensor(1);
@@ -773,6 +784,158 @@ TEST_F("require that AttributeWriter::forceCommit() clears search cache in impor
EXPECT_EQUAL(0u, f._m->getImportedAttributes()->get("imported_b")->getSearchCache()->size());
}
+struct StructFixtureBase : public Fixture
+{
+ DocumentType _type;
+ const Field _valueField;
+ StructDataType _structFieldType;
+
+ StructFixtureBase()
+ : Fixture(),
+ _type("test"),
+ _valueField("value", 2, *DataType::INT, true),
+ _structFieldType("struct")
+ {
+ addAttribute({"value", AVConfig(AVBasicType::INT32, AVCollectionType::SINGLE)}, createSerialNum);
+ _type.addField(_valueField);
+ _structFieldType.addField(_valueField);
+ }
+ ~StructFixtureBase();
+
+ std::unique_ptr<StructFieldValue>
+ makeStruct()
+ {
+ return std::make_unique<StructFieldValue>(_structFieldType);
+ }
+
+ std::unique_ptr<StructFieldValue>
+ makeStruct(const int32_t value)
+ {
+ auto ret = makeStruct();
+ ret->setValue(_valueField, IntFieldValue(value));
+ return ret;
+ }
+
+ std::unique_ptr<Document>
+ makeDoc()
+ {
+ return std::make_unique<Document>(_type, DocumentId("id::test::1"));
+ }
+};
+
+StructFixtureBase::~StructFixtureBase() = default;
+
+struct StructArrayFixture : public StructFixtureBase
+{
+ using StructFixtureBase::makeDoc;
+ const ArrayDataType _structArrayFieldType;
+ const Field _structArrayField;
+
+ StructArrayFixture()
+ : StructFixtureBase(),
+ _structArrayFieldType(_structFieldType),
+ _structArrayField("array", _structArrayFieldType, true)
+ {
+ addAttribute({"array.value", AVConfig(AVBasicType::INT32, AVCollectionType::ARRAY)}, createSerialNum);
+ _type.addField(_structArrayField);
+ }
+ ~StructArrayFixture();
+
+ std::unique_ptr<Document>
+ makeDoc(int32_t value, const std::vector<int32_t> &arrayValues)
+ {
+ auto doc = makeDoc();
+ doc->setValue(_valueField, IntFieldValue(value));
+ ArrayFieldValue s(_structArrayFieldType);
+ for (const auto &arrayValue : arrayValues) {
+ s.add(*makeStruct(arrayValue));
+ }
+ doc->setValue(_structArrayField, s);
+ return doc;
+ }
+ void checkAttrs(uint32_t lid, int32_t value, const std::vector<int32_t> &arrayValues) {
+ auto valueAttr = _m->getAttribute("value")->getSP();
+ auto arrayValueAttr = _m->getAttribute("array.value")->getSP();
+ EXPECT_EQUAL(value, valueAttr->getInt(lid));
+ attribute::IntegerContent ibuf;
+ ibuf.fill(*arrayValueAttr, lid);
+ EXPECT_EQUAL(arrayValues.size(), ibuf.size());
+ for (size_t i = 0; i < arrayValues.size(); ++i) {
+ EXPECT_EQUAL(arrayValues[i], ibuf[i]);
+ }
+ }
+};
+
+StructArrayFixture::~StructArrayFixture() = default;
+
+TEST_F("require that update with doc argument updates compound attributes (array)", StructArrayFixture)
+{
+ auto doc = f.makeDoc(10, {11, 12});
+ f.put(10, *doc, 1);
+ TEST_DO(f.checkAttrs(1, 10, {11, 12}));
+ doc = f.makeDoc(20, {21});
+ f.update(11, *doc, 1, true);
+ TEST_DO(f.checkAttrs(1, 10, {21}));
+}
+
+struct StructMapFixture : public StructFixtureBase
+{
+ using StructFixtureBase::makeDoc;
+ const MapDataType _structMapFieldType;
+ const Field _structMapField;
+
+ StructMapFixture()
+ : StructFixtureBase(),
+ _structMapFieldType(*DataType::INT, _structFieldType),
+ _structMapField("map", _structMapFieldType, true)
+ {
+ addAttribute({"map.value.value", AVConfig(AVBasicType::INT32, AVCollectionType::ARRAY)}, createSerialNum);
+ addAttribute({"map.key", AVConfig(AVBasicType::INT32, AVCollectionType::ARRAY)}, createSerialNum);
+ _type.addField(_structMapField);
+ }
+
+ std::unique_ptr<Document>
+ makeDoc(int32_t value, const std::map<int32_t, int32_t> &mapValues)
+ {
+ auto doc = makeDoc();
+ doc->setValue(_valueField, IntFieldValue(value));
+ MapFieldValue s(_structMapFieldType);
+ for (const auto &mapValue : mapValues) {
+ s.put(IntFieldValue(mapValue.first), *makeStruct(mapValue.second));
+ }
+ doc->setValue(_structMapField, s);
+ return doc;
+ }
+ void checkAttrs(uint32_t lid, int32_t expValue, const std::map<int32_t, int32_t> &expMap) {
+ auto valueAttr = _m->getAttribute("value")->getSP();
+ auto mapKeyAttr = _m->getAttribute("map.key")->getSP();
+ auto mapValueAttr = _m->getAttribute("map.value.value")->getSP();
+ EXPECT_EQUAL(expValue, valueAttr->getInt(lid));
+ attribute::IntegerContent mapKeys;
+ mapKeys.fill(*mapKeyAttr, lid);
+ attribute::IntegerContent mapValues;
+ mapValues.fill(*mapValueAttr, lid);
+ EXPECT_EQUAL(expMap.size(), mapValues.size());
+ EXPECT_EQUAL(expMap.size(), mapKeys.size());
+ size_t i = 0;
+ for (const auto &expMapElem : expMap) {
+ EXPECT_EQUAL(expMapElem.first, mapKeys[i]);
+ EXPECT_EQUAL(expMapElem.second, mapValues[i]);
+ ++i;
+ }
+ }
+};
+
+TEST_F("require that update with doc argument updates compound attributes (map)", StructMapFixture)
+{
+ auto doc = f.makeDoc(10, {{1, 11}, {2, 12}});
+ f.put(10, *doc, 1);
+ TEST_DO(f.checkAttrs(1, 10, {{1, 11}, {2, 12}}));
+ doc = f.makeDoc(20, {{42, 21}});
+ f.update(11, *doc, 1, true);
+ TEST_DO(f.checkAttrs(1, 10, {{42, 21}}));
+}
+
TEST_MAIN()
{
vespalib::rmdir(test_dir, true);
diff --git a/searchcore/src/tests/proton/attribute/document_field_extractor/document_field_extractor_test.cpp b/searchcore/src/tests/proton/attribute/document_field_extractor/document_field_extractor_test.cpp
index d13e4207a9d..bad27938d4b 100644
--- a/searchcore/src/tests/proton/attribute/document_field_extractor/document_field_extractor_test.cpp
+++ b/searchcore/src/tests/proton/attribute/document_field_extractor/document_field_extractor_test.cpp
@@ -86,19 +86,6 @@ makeStringWeightedSet(const std::vector<std::pair<vespalib::string, int32_t>> &a
return result;
}
-template <typename F1, typename F2>
-void
-checkFieldPathChange(F1 f1, F2 f2, const vespalib::string &path, bool same)
-{
- FieldPath fieldPath1 = f1.makeFieldPath(path);
- FieldPath fieldPath2 = f2.makeFieldPath(path);
- EXPECT_TRUE(!fieldPath1.empty());
- EXPECT_TRUE(!fieldPath2.empty());
- EXPECT_TRUE(DocumentFieldExtractor::isSupported(fieldPath1));
- EXPECT_TRUE(DocumentFieldExtractor::isSupported(fieldPath2));
- EXPECT_EQUAL(same, DocumentFieldExtractor::isCompatible(fieldPath1, fieldPath2));
-}
-
}
struct FixtureBase
@@ -354,26 +341,6 @@ TEST_F("require that unknown field gives null value", FixtureBase(false))
TEST_DO(f.assertExtracted("unknown", std::unique_ptr<FieldValue>()));
}
-TEST("require that type changes are detected")
-{
- TEST_DO(checkFieldPathChange(SimpleFixture(false), SimpleFixture(false), "weight", true));
- TEST_DO(checkFieldPathChange(SimpleFixture(false), SimpleFixture(true), "weight", false));
- TEST_DO(checkFieldPathChange(ArrayFixture(false), ArrayFixture(false), "weight", true));
- TEST_DO(checkFieldPathChange(ArrayFixture(false), ArrayFixture(true), "weight", false));
- TEST_DO(checkFieldPathChange(SimpleFixture(false), ArrayFixture(false), "weight", false));
- TEST_DO(checkFieldPathChange(WeightedSetFixture(false), WeightedSetFixture(false), "weight", true));
- TEST_DO(checkFieldPathChange(WeightedSetFixture(false), WeightedSetFixture(true), "weight", false));
- TEST_DO(checkFieldPathChange(SimpleFixture(false), WeightedSetFixture(false), "weight", false));
- TEST_DO(checkFieldPathChange(ArrayFixture(false), WeightedSetFixture(false), "weight", false));
- TEST_DO(checkFieldPathChange(StructArrayFixture(false), StructArrayFixture(false), "s.weight", true));
- TEST_DO(checkFieldPathChange(StructArrayFixture(false), StructArrayFixture(true), "s.weight", false));
- TEST_DO(checkFieldPathChange(StructMapFixture(false, false), StructMapFixture(false, false), "s.value.weight", true));
- TEST_DO(checkFieldPathChange(StructMapFixture(false, false), StructMapFixture(true, false), "s.value.weight", false));
- TEST_DO(checkFieldPathChange(StructMapFixture(false, false), StructMapFixture(false, true), "s.value.weight", false));
- TEST_DO(checkFieldPathChange(StructMapFixture(false, false), StructMapFixture(false, false), "s.key", true));
- TEST_DO(checkFieldPathChange(StructMapFixture(false, false), StructMapFixture(false, true), "s.key", false));
-}
-
TEST_MAIN()
{
TEST_RUN_ALL();
diff --git a/searchcore/src/tests/proton/documentdb/feedview/feedview_test.cpp b/searchcore/src/tests/proton/documentdb/feedview/feedview_test.cpp
index 00eb59f120a..5d040024e63 100644
--- a/searchcore/src/tests/proton/documentdb/feedview/feedview_test.cpp
+++ b/searchcore/src/tests/proton/documentdb/feedview/feedview_test.cpp
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/searchcore/proton/attribute/i_attribute_writer.h>
+#include <vespa/searchcore/proton/attribute/ifieldupdatecallback.h>
#include <vespa/searchcore/proton/test/bucketfactory.h>
#include <vespa/searchcore/proton/common/commit_time_tracker.h>
#include <vespa/searchcore/proton/common/feedtoken.h>
@@ -316,21 +317,23 @@ struct MyAttributeWriter : public IAttributeWriter
std::set<vespalib::string> _attrs;
proton::IAttributeManager::SP _mgr;
MyTracer &_tracer;
+
MyAttributeWriter(MyTracer &tracer);
~MyAttributeWriter();
- virtual std::vector<AttributeVector *>
+
+ std::vector<AttributeVector *>
getWritableAttributes() const override {
return std::vector<AttributeVector *>();
}
- virtual AttributeVector *getWritableAttribute(const vespalib::string &attrName) const override {
+ AttributeVector *getWritableAttribute(const vespalib::string &attrName) const override {
if (_attrs.count(attrName) == 0) {
return nullptr;
}
AttrMap::const_iterator itr = _attrMap.find(attrName);
return ((itr == _attrMap.end()) ? nullptr : itr->second.get());
}
- virtual void put(SerialNum serialNum, const document::Document &doc, DocumentIdT lid,
- bool immediateCommit, OnWriteDoneType) override {
+ void put(SerialNum serialNum, const document::Document &doc, DocumentIdT lid,
+ bool immediateCommit, OnWriteDoneType) override {
_putSerial = serialNum;
_putDocId = doc.getId();
_putLid = lid;
@@ -339,8 +342,8 @@ struct MyAttributeWriter : public IAttributeWriter
++_commitCount;
}
}
- virtual void remove(SerialNum serialNum, DocumentIdT lid,
- bool immediateCommit, OnWriteDoneType) override {
+ void remove(SerialNum serialNum, DocumentIdT lid,
+ bool immediateCommit, OnWriteDoneType) override {
_removeSerial = serialNum;
_removeLid = lid;
_tracer.traceRemove(attributeAdapterTypeName, serialNum, lid, immediateCommit);
@@ -348,37 +351,45 @@ struct MyAttributeWriter : public IAttributeWriter
++_commitCount;
}
}
- virtual void remove(const LidVector & lidsToRemove, SerialNum serialNum,
- bool immediateCommit, OnWriteDoneType) override {
+ void remove(const LidVector & lidsToRemove, SerialNum serialNum,
+ bool immediateCommit, OnWriteDoneType) override {
for (uint32_t lid : lidsToRemove) {
LOG(info, "MyAttributeAdapter::remove(): serialNum(%" PRIu64 "), docId(%u)", serialNum, lid);
_removes.push_back(lid);
_tracer.traceRemove(attributeAdapterTypeName, serialNum, lid, immediateCommit);
}
}
- virtual void update(SerialNum serialNum, const document::DocumentUpdate &upd,
- DocumentIdT lid, bool, OnWriteDoneType) override {
+ void update(SerialNum serialNum, const document::DocumentUpdate &upd,
+ DocumentIdT lid, bool, OnWriteDoneType, IFieldUpdateCallback & onUpdate) override {
_updateSerial = serialNum;
_updateDocId = upd.getId();
_updateLid = lid;
+ for (const auto & fieldUpdate : upd.getUpdates()) {
+ search::AttributeVector * attr = getWritableAttribute(fieldUpdate.getField().getName());
+ onUpdate.onUpdateField(fieldUpdate.getField().getName(), attr);
+ }
}
- virtual void heartBeat(SerialNum) override { ++_heartBeatCount; }
- virtual void compactLidSpace(uint32_t wantedLidLimit, SerialNum serialNum) override {
+ void update(SerialNum serialNum, const document::Document &doc, DocumentIdT lid,
+ bool immediateCommit, OnWriteDoneType) override {
(void) serialNum;
+ (void) doc;
+ (void) lid;
+ (void) immediateCommit;
+ }
+ void heartBeat(SerialNum) override { ++_heartBeatCount; }
+ void compactLidSpace(uint32_t wantedLidLimit, SerialNum ) override {
_wantedLidLimit = wantedLidLimit;
}
- virtual const proton::IAttributeManager::SP &getAttributeManager() const override {
+ const proton::IAttributeManager::SP &getAttributeManager() const override {
return _mgr;
}
void forceCommit(SerialNum serialNum, OnWriteDoneType) override {
- (void) serialNum; ++_commitCount;
+ ++_commitCount;
_tracer.traceCommit(attributeAdapterTypeName, serialNum);
}
- virtual void onReplayDone(uint32_t docIdLimit) override
- {
- (void) docIdLimit;
- }
+ void onReplayDone(uint32_t ) override { }
+ bool getHasCompoundAttribute() const override { return false; }
};
MyAttributeWriter::MyAttributeWriter(MyTracer &tracer)
@@ -396,7 +407,7 @@ MyAttributeWriter::MyAttributeWriter(MyTracer &tracer)
cfg3.setTensorType(ValueType::from_spec("tensor(x[10])"));
_attrMap["a3"] = search::AttributeFactory::createAttribute("test3", cfg3);
}
-MyAttributeWriter::~MyAttributeWriter() {}
+MyAttributeWriter::~MyAttributeWriter() = default;
struct MyTransport : public feedtoken::ITransport
{
@@ -420,7 +431,7 @@ struct MyResultHandler : public IGenericResultHandler
{
vespalib::Gate _gate;
MyResultHandler() : _gate() {}
- virtual void handle(const storage::spi::Result &) override {
+ void handle(const storage::spi::Result &) override {
_gate.countDown();
}
void await() { _gate.await(); }
@@ -446,7 +457,7 @@ SchemaContext::SchemaContext() :
_schema->addSummaryField(Schema::SummaryField("s1", DataType::STRING, CollectionType::SINGLE));
_builder.reset(new DocBuilder(*_schema));
}
-SchemaContext::~SchemaContext() {}
+SchemaContext::~SchemaContext() = default;
struct DocumentContext
diff --git a/searchcore/src/tests/proton/feedoperation/feedoperation_test.cpp b/searchcore/src/tests/proton/feedoperation/feedoperation_test.cpp
index a6d7f12f199..681d3543ee1 100644
--- a/searchcore/src/tests/proton/feedoperation/feedoperation_test.cpp
+++ b/searchcore/src/tests/proton/feedoperation/feedoperation_test.cpp
@@ -23,6 +23,7 @@
#include <vespa/document/update/documentupdate.h>
#include <vespa/document/update/assignvalueupdate.h>
#include <vespa/document/fieldvalue/fieldvalues.h>
+#include <vespa/document/serialization/vespadocumentserializer.h>
#include <vespa/document/repo/configbuilder.h>
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/document/datatype/documenttype.h>
@@ -282,8 +283,10 @@ TEST_F("require that we can deserialize old update operations", Fixture)
BucketId bucket(toBucket(docId.getGlobalId()));
auto upd(f.makeUpdate());
{
- UpdateOperation op(UpdateOperation::makeOldUpdate(bucket, Timestamp(10), upd));
- op.serialize(stream);
+ UpdateOperation op(bucket, Timestamp(10), upd);
+ op.serializeDocumentOperationOnly(stream);
+ document::VespaDocumentSerializer serializer(stream);
+ serializer.write42(*op.getUpdate());
}
{
UpdateOperation op(FeedOperation::UPDATE_42);
diff --git a/searchcore/src/tests/proton/matching/matching_test.cpp b/searchcore/src/tests/proton/matching/matching_test.cpp
index 62c61406f67..a770fff3f5f 100644
--- a/searchcore/src/tests/proton/matching/matching_test.cpp
+++ b/searchcore/src/tests/proton/matching/matching_test.cpp
@@ -61,6 +61,36 @@ void inject_match_phase_limiting(Properties &setup, const vespalib::string &attr
setup.import(cfg);
}
+FakeResult make_elem_result(const std::vector<std::pair<uint32_t,std::vector<uint32_t> > > &match_data) {
+ FakeResult result;
+ uint32_t pos_should_be_ignored = 0;
+ for (const auto &doc: match_data) {
+ result.doc(doc.first);
+ for (const auto &elem: doc.second) {
+ result.elem(elem).pos(++pos_should_be_ignored);
+ }
+ }
+ return result;
+}
+
+vespalib::string make_simple_stack_dump(const vespalib::string &field,
+ const vespalib::string &term)
+{
+ QueryBuilder<ProtonNodeTypes> builder;
+ builder.addStringTerm(term, field, 1, search::query::Weight(1));
+ return StackDumpCreator::create(*builder.build());
+}
+
+vespalib::string make_same_element_stack_dump(const vespalib::string &a1_term,
+ const vespalib::string &f1_term)
+{
+ QueryBuilder<ProtonNodeTypes> builder;
+ builder.addSameElement(2, "ignored field name");
+ builder.addStringTerm(a1_term, "a1", 1, search::query::Weight(1));
+ builder.addStringTerm(f1_term, "f1", 2, search::query::Weight(1));
+ return StackDumpCreator::create(*builder.build());
+}
+
//-----------------------------------------------------------------------------
const uint32_t NUM_DOCS = 1000;
@@ -238,6 +268,13 @@ struct MyWorld {
searchContext.attr().addResult("a1", term, result);
}
+ void add_same_element_results(const vespalib::string &a1_term, const vespalib::string &f1_0_term) {
+ auto a1_result = make_elem_result({{10, {1}}, {20, {2}}, {21, {2}}});
+ auto f1_0_result = make_elem_result({{10, {2}}, {20, {2}}, {21, {2}}});
+ searchContext.attr().addResult("a1", a1_term, a1_result);
+ searchContext.idx(0).getFake().addResult("f1", f1_0_term, f1_0_result);
+ }
+
void basicResults() {
searchContext.idx(0).getFake().addResult("f1", "foo",
FakeResult()
@@ -249,26 +286,32 @@ struct MyWorld {
.doc(600).doc(700).doc(800).doc(900));
}
- void setStackDump(Request &request, const vespalib::string &field,
- const vespalib::string &term) {
- QueryBuilder<ProtonNodeTypes> builder;
- builder.addStringTerm(term, field, 1, search::query::Weight(1));
- vespalib::string stack_dump =
- StackDumpCreator::create(*builder.build());
+ void setStackDump(Request &request, const vespalib::string &stack_dump) {
request.stackDump.assign(stack_dump.data(),
stack_dump.data() + stack_dump.size());
}
- SearchRequest::SP createSimpleRequest(const vespalib::string &field,
- const vespalib::string &term)
+ SearchRequest::SP createRequest(const vespalib::string &stack_dump)
{
SearchRequest::SP request(new SearchRequest);
request->setTimeout(60 * fastos::TimeStamp::SEC);
- setStackDump(*request, field, term);
+ setStackDump(*request, stack_dump);
request->maxhits = 10;
return request;
}
+ SearchRequest::SP createSimpleRequest(const vespalib::string &field,
+ const vespalib::string &term)
+ {
+ return createRequest(make_simple_stack_dump(field, term));
+ }
+
+ SearchRequest::SP createSameElementRequest(const vespalib::string &a1_term,
+ const vespalib::string &f1_term)
+ {
+ return createRequest(make_same_element_stack_dump(a1_term, f1_term));
+ }
+
Matcher::SP createMatcher() {
return std::make_shared<Matcher>(schema, config, clock, queryLimiter, constantValueRepo, 0);
}
@@ -317,7 +360,7 @@ struct MyWorld {
const vespalib::string & term)
{
DocsumRequest::SP request(new DocsumRequest);
- setStackDump(*request, field, term);
+ setStackDump(*request, make_simple_stack_dump(field, term));
// match a subset of basic result + request for a non-hit (not
// sorted on docid)
@@ -800,4 +843,14 @@ TEST("require that fields are tagged with data type") {
EXPECT_EQUAL(predicate_field->get_data_type(), FieldInfo::DataType::BOOLEANTREE);
}
+TEST("require that same element search works (note that this does not test/use the attribute element iterator wrapper)") {
+ MyWorld world;
+ world.basicSetup();
+ world.add_same_element_results("foo", "bar");
+ SearchRequest::SP request = world.createSameElementRequest("foo", "bar");
+ SearchReply::UP reply = world.performSearch(request, 1);
+ ASSERT_EQUAL(1u, reply->hits.size());
+ EXPECT_EQUAL(document::DocumentId("doc::20").getGlobalId(), reply->hits[0].gid);
+}
+
TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp b/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp
index 9262f9a7b6f..705a27c7fc3 100644
--- a/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp
+++ b/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp
@@ -68,24 +68,8 @@ createUpd(const DocumentType& docType, const DocumentId &docId)
return document::DocumentUpdate::SP(new document::DocumentUpdate(docType, docId));
}
-
-document::Document::UP
-clone(const document::Document::SP &doc)
-{
- return document::Document::UP(doc->clone());
-}
-
-
-document::DocumentUpdate::UP
-clone(const document::DocumentUpdate::SP &upd)
-{
- return document::DocumentUpdate::UP(upd->clone());
-}
-
-
storage::spi::ClusterState
-createClusterState(const storage::lib::State& nodeState =
- storage::lib::State::UP)
+createClusterState(const storage::lib::State& nodeState = storage::lib::State::UP)
{
using storage::lib::Distribution;
using storage::lib::Node;
@@ -99,11 +83,7 @@ createClusterState(const storage::lib::State& nodeState =
StorDistributionConfigBuilder dc;
cstate.setNodeState(Node(NodeType::STORAGE, 0),
- NodeState(NodeType::STORAGE,
- nodeState,
- "dummy desc",
- 1.0,
- 1));
+ NodeState(NodeType::STORAGE, nodeState, "dummy desc", 1.0, 1));
cstate.setClusterState(State::UP);
dc.redundancy = 1;
dc.readyCopies = 1;
@@ -222,8 +202,7 @@ struct MyHandler : public IPersistenceHandler, IBucketFreezer {
void handleUpdate(FeedToken token, const Bucket& bucket,
Timestamp timestamp, const document::DocumentUpdate::SP& upd) override {
- token->setResult(ResultUP(new storage::spi::UpdateResult(existingTimestamp)),
- existingTimestamp > 0);
+ token->setResult(ResultUP(new storage::spi::UpdateResult(existingTimestamp)), existingTimestamp > 0);
handle(token, bucket, timestamp, upd->getId());
}
@@ -312,8 +291,7 @@ struct MyHandler : public IPersistenceHandler, IBucketFreezer {
return frozen.find(bucket.getBucketId().getId()) != frozen.end();
}
bool wasFrozen(const Bucket &bucket) {
- return was_frozen.find(bucket.getBucketId().getId())
- != was_frozen.end();
+ return was_frozen.find(bucket.getBucketId().getId()) != was_frozen.end();
}
};
@@ -335,7 +313,7 @@ HandlerSet::HandlerSet()
handler1(static_cast<MyHandler &>(*phandler1.get())),
handler2(static_cast<MyHandler &>(*phandler2.get()))
{}
-HandlerSet::~HandlerSet() {}
+HandlerSet::~HandlerSet() = default;
DocumentType type1(createDocType("type1", 1));
DocumentType type2(createDocType("type2", 2));
@@ -405,8 +383,8 @@ struct SimpleResourceWriteFilter : public IResourceWriteFilter
_message()
{}
- virtual bool acceptWriteOperation() const override { return _acceptWriteOperation; }
- virtual State getAcceptState() const override {
+ bool acceptWriteOperation() const override { return _acceptWriteOperation; }
+ State getAcceptState() const override {
return IResourceWriteFilter::State(acceptWriteOperation(), _message);
}
};
@@ -475,8 +453,7 @@ TEST_F("require that getPartitionStates() prepares all handlers", SimpleFixture)
TEST_F("require that puts are routed to handler", SimpleFixture)
{
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
f.engine.put(bucket1, tstamp1, doc1, context);
assertHandler(bucket1, tstamp1, docId1, f.hset.handler1);
assertHandler(bucket0, tstamp0, docId0, f.hset.handler2);
@@ -485,20 +462,16 @@ TEST_F("require that puts are routed to handler", SimpleFixture)
assertHandler(bucket1, tstamp1, docId1, f.hset.handler1);
assertHandler(bucket1, tstamp1, docId2, f.hset.handler2);
- EXPECT_EQUAL(
- Result(Result::PERMANENT_ERROR, "No handler for document type 'type3'"),
- f.engine.put(bucket1, tstamp1, doc3, context));
+ EXPECT_EQUAL(Result(Result::PERMANENT_ERROR, "No handler for document type 'type3'"),
+ f.engine.put(bucket1, tstamp1, doc3, context));
}
TEST_F("require that puts with old id scheme are rejected", SimpleFixture) {
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
- EXPECT_EQUAL(
- Result(Result::PERMANENT_ERROR, "Old id scheme not supported in "
- "elastic mode (doc:old:id-scheme)"),
- f.engine.put(bucket1, tstamp1, old_doc, context));
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
+ EXPECT_EQUAL(Result(Result::PERMANENT_ERROR, "Old id scheme not supported in elastic mode (doc:old:id-scheme)"),
+ f.engine.put(bucket1, tstamp1, old_doc, context));
}
@@ -508,8 +481,7 @@ TEST_F("require that put is rejected if resource limit is reached", SimpleFixtur
f._writeFilter._message = "Disk is full";
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
EXPECT_EQUAL(
Result(Result::RESOURCE_EXHAUSTED,
"Put operation rejected for document 'doc:old:id-scheme': 'Disk is full'"),
@@ -520,8 +492,7 @@ TEST_F("require that put is rejected if resource limit is reached", SimpleFixtur
TEST_F("require that updates are routed to handler", SimpleFixture)
{
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
f.hset.handler1.setExistingTimestamp(tstamp2);
UpdateResult ur = f.engine.update(bucket1, tstamp1, upd1, context);
assertHandler(bucket1, tstamp1, docId1, f.hset.handler1);
@@ -534,9 +505,8 @@ TEST_F("require that updates are routed to handler", SimpleFixture)
assertHandler(bucket1, tstamp1, docId2, f.hset.handler2);
EXPECT_EQUAL(tstamp3, ur.getExistingTimestamp());
- EXPECT_EQUAL(
- Result(Result::PERMANENT_ERROR, "No handler for document type 'type3'"),
- f.engine.update(bucket1, tstamp1, upd3, context));
+ EXPECT_EQUAL(Result(Result::PERMANENT_ERROR, "No handler for document type 'type3'"),
+ f.engine.update(bucket1, tstamp1, upd3, context));
}
@@ -546,8 +516,7 @@ TEST_F("require that update is rejected if resource limit is reached", SimpleFix
f._writeFilter._message = "Disk is full";
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
EXPECT_EQUAL(
Result(Result::RESOURCE_EXHAUSTED,
@@ -559,8 +528,7 @@ TEST_F("require that update is rejected if resource limit is reached", SimpleFix
TEST_F("require that removes are routed to handlers", SimpleFixture)
{
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
RemoveResult rr = f.engine.remove(bucket1, tstamp1, docId3, context);
assertHandler(bucket0, tstamp0, docId0, f.hset.handler1);
assertHandler(bucket0, tstamp0, docId0, f.hset.handler2);
@@ -598,8 +566,7 @@ TEST_F("require that remove is NOT rejected if resource limit is reached", Simpl
f._writeFilter._message = "Disk is full";
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
EXPECT_EQUAL(RemoveResult(false), f.engine.remove(bucket1, tstamp1, docId1, context));
}
@@ -628,8 +595,7 @@ TEST_F("require that setActiveState() is routed to handlers and merged", SimpleF
f.hset.handler1.bucketStateResult = Result(Result::TRANSIENT_ERROR, "err1");
f.hset.handler2.bucketStateResult = Result(Result::PERMANENT_ERROR, "err2");
- Result result = f.engine.setActiveState(bucket1,
- storage::spi::BucketInfo::NOT_ACTIVE);
+ Result result = f.engine.setActiveState(bucket1, storage::spi::BucketInfo::NOT_ACTIVE);
EXPECT_EQUAL(Result::PERMANENT_ERROR, result.getErrorCode());
EXPECT_EQUAL("err1, err2", result.getErrorMessage());
EXPECT_EQUAL(storage::spi::BucketInfo::NOT_ACTIVE, f.hset.handler1.lastBucketState);
@@ -651,16 +617,12 @@ TEST_F("require that getBucketInfo() is routed to handlers and merged", SimpleFi
}
-TEST_F("require that createBucket() is routed to handlers and merged",
- SimpleFixture)
+TEST_F("require that createBucket() is routed to handlers and merged", SimpleFixture)
{
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
- f.hset.handler1._createBucketResult =
- Result(Result::TRANSIENT_ERROR, "err1a");
- f.hset.handler2._createBucketResult =
- Result(Result::PERMANENT_ERROR, "err2a");
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
+ f.hset.handler1._createBucketResult = Result(Result::TRANSIENT_ERROR, "err1a");
+ f.hset.handler2._createBucketResult = Result(Result::PERMANENT_ERROR, "err2a");
Result result = f.engine.createBucket(bucket1, context);
EXPECT_EQUAL(Result::PERMANENT_ERROR, result.getErrorCode());
@@ -671,8 +633,7 @@ TEST_F("require that createBucket() is routed to handlers and merged",
TEST_F("require that deleteBucket() is routed to handlers and merged", SimpleFixture)
{
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
f.hset.handler1.deleteBucketResult = Result(Result::TRANSIENT_ERROR, "err1");
f.hset.handler2.deleteBucketResult = Result(Result::PERMANENT_ERROR, "err2");
@@ -691,10 +652,8 @@ TEST_F("require that getModifiedBuckets() is routed to handlers and merged", Sim
TEST_F("require that get is sent to all handlers", SimpleFixture) {
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
- GetResult result = f.engine.get(bucket1, document::AllFields(), docId1,
- context);
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
+ GetResult result = f.engine.get(bucket1, document::AllFields(), docId1, context);
EXPECT_EQUAL(docId1, f.hset.handler1.lastDocId);
EXPECT_EQUAL(docId1, f.hset.handler2.lastDocId);
@@ -704,8 +663,7 @@ TEST_F("require that get freezes the bucket", SimpleFixture) {
EXPECT_FALSE(f.hset.handler1.wasFrozen(bucket1));
EXPECT_FALSE(f.hset.handler2.wasFrozen(bucket1));
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
f.engine.get(bucket1, document::AllFields(), docId1, context);
EXPECT_TRUE(f.hset.handler1.wasFrozen(bucket1));
EXPECT_TRUE(f.hset.handler2.wasFrozen(bucket1));
@@ -717,10 +675,8 @@ TEST_F("require that get returns the first document found", SimpleFixture) {
f.hset.handler1.setDocument(*doc1, tstamp1);
f.hset.handler2.setDocument(*doc2, tstamp2);
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
- GetResult result = f.engine.get(bucket1, document::AllFields(), docId1,
- context);
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
+ GetResult result = f.engine.get(bucket1, document::AllFields(), docId1, context);
EXPECT_EQUAL(docId1, f.hset.handler1.lastDocId);
EXPECT_EQUAL(DocumentId(), f.hset.handler2.lastDocId);
@@ -732,8 +688,7 @@ TEST_F("require that get returns the first document found", SimpleFixture) {
TEST_F("require that createIterator does", SimpleFixture) {
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
CreateIteratorResult result =
f.engine.createIterator(bucket1, document::AllFields(), selection,
storage::spi::NEWEST_DOCUMENT_ONLY, context);
@@ -741,15 +696,13 @@ TEST_F("require that createIterator does", SimpleFixture) {
EXPECT_TRUE(result.getIteratorId());
uint64_t max_size = 1024;
- IterateResult it_result =
- f.engine.iterate(result.getIteratorId(), max_size, context);
+ IterateResult it_result = f.engine.iterate(result.getIteratorId(), max_size, context);
EXPECT_FALSE(it_result.hasError());
}
TEST_F("require that iterator ids are unique", SimpleFixture) {
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
CreateIteratorResult result =
f.engine.createIterator(bucket1, document::AllFields(), selection,
storage::spi::NEWEST_DOCUMENT_ONLY, context);
@@ -764,10 +717,8 @@ TEST_F("require that iterator ids are unique", SimpleFixture) {
TEST_F("require that iterate requires valid iterator", SimpleFixture) {
uint64_t max_size = 1024;
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
- IterateResult it_result = f.engine.iterate(IteratorId(1), max_size,
- context);
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
+ IterateResult it_result = f.engine.iterate(IteratorId(1), max_size, context);
EXPECT_TRUE(it_result.hasError());
EXPECT_EQUAL(Result::PERMANENT_ERROR, it_result.getErrorCode());
EXPECT_EQUAL("Unknown iterator with id 1", it_result.getErrorMessage());
@@ -786,16 +737,14 @@ TEST_F("require that iterate returns documents", SimpleFixture) {
f.hset.handler2.setDocument(*doc2, tstamp2);
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
uint64_t max_size = 1024;
CreateIteratorResult result =
f.engine.createIterator(bucket1, document::AllFields(), selection,
storage::spi::NEWEST_DOCUMENT_ONLY, context);
EXPECT_TRUE(result.getIteratorId());
- IterateResult it_result =
- f.engine.iterate(result.getIteratorId(), max_size, context);
+ IterateResult it_result = f.engine.iterate(result.getIteratorId(), max_size, context);
EXPECT_FALSE(it_result.hasError());
EXPECT_EQUAL(2u, it_result.getEntries().size());
}
@@ -804,33 +753,28 @@ TEST_F("require that destroyIterator prevents iteration", SimpleFixture) {
f.hset.handler1.setDocument(*doc1, tstamp1);
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
CreateIteratorResult create_result =
f.engine.createIterator(bucket1, document::AllFields(), selection,
storage::spi::NEWEST_DOCUMENT_ONLY, context);
EXPECT_TRUE(create_result.getIteratorId());
- Result result = f.engine.destroyIterator(create_result.getIteratorId(),
- context);
+ Result result = f.engine.destroyIterator(create_result.getIteratorId(), context);
EXPECT_FALSE(result.hasError());
uint64_t max_size = 1024;
- IterateResult it_result =
- f.engine.iterate(create_result.getIteratorId(), max_size, context);
+ IterateResult it_result = f.engine.iterate(create_result.getIteratorId(), max_size, context);
EXPECT_TRUE(it_result.hasError());
EXPECT_EQUAL(Result::PERMANENT_ERROR, it_result.getErrorCode());
string msg_prefix = "Unknown iterator with id";
- EXPECT_EQUAL(msg_prefix,
- it_result.getErrorMessage().substr(0, msg_prefix.size()));
+ EXPECT_EQUAL(msg_prefix, it_result.getErrorMessage().substr(0, msg_prefix.size()));
}
TEST_F("require that buckets are frozen during iterator life", SimpleFixture) {
EXPECT_FALSE(f.hset.handler1.isFrozen(bucket1));
EXPECT_FALSE(f.hset.handler2.isFrozen(bucket1));
storage::spi::LoadType loadType(0, "default");
- Context context(loadType, storage::spi::Priority(0),
- storage::spi::Trace::TraceLevel(0));
+ Context context(loadType, storage::spi::Priority(0), storage::spi::Trace::TraceLevel(0));
CreateIteratorResult create_result =
f.engine.createIterator(bucket1, document::AllFields(), selection,
storage::spi::NEWEST_DOCUMENT_ONLY, context);