diff options
Diffstat (limited to 'searchcore/src/tests/proton')
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); |