diff options
31 files changed, 407 insertions, 480 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/PlatformBundles.java b/config-model/src/main/java/com/yahoo/vespa/model/container/PlatformBundles.java index 5f363ff993f..3252077a79d 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/PlatformBundles.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/PlatformBundles.java @@ -24,7 +24,7 @@ import static com.yahoo.vespa.model.container.ContainerModelEvaluation.ONNXRUNTI */ public class PlatformBundles { - private enum JarSuffix { + public enum JarSuffix { JAR_WITH_DEPS("-jar-with-dependencies.jar"), DEPLOY("-deploy.jar"); diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/secret/Key.java b/container-disc/src/main/java/com/yahoo/container/jdisc/secret/Key.java deleted file mode 100644 index 3de482b9cc6..00000000000 --- a/container-disc/src/main/java/com/yahoo/container/jdisc/secret/Key.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.yahoo.container.jdisc.secret; - -import java.util.Objects; - -public class Key { - - private final String keyGroup; - private final String keyName; - - public Key(String keyGroup, String keyName) { - this.keyGroup = keyGroup; - this.keyName = keyName; - } - - public String keyGroup() { - return keyGroup; - } - - public String keyName() { - return keyName; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Key that = (Key) o; - if ( ! (that.keyGroup.equals(keyGroup))) return false; - if ( ! (that.keyName.equals(keyName))) return false; - return true; - } - - @Override - public int hashCode() { - return Objects.hash(keyGroup, keyName); - } - - @Override - public String toString() { return "key group: " + keyGroup + ", key name: " + keyName; } - -} diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/secret/Secret.java b/container-disc/src/main/java/com/yahoo/container/jdisc/secret/Secret.java deleted file mode 100644 index fef0ba804eb..00000000000 --- a/container-disc/src/main/java/com/yahoo/container/jdisc/secret/Secret.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.yahoo.container.jdisc.secret; - -import com.yahoo.security.YBase64; -import com.yahoo.text.Utf8; - -import java.util.Arrays; -import java.util.Objects; - -public class Secret { - - private final Key key; - private final byte[] secret; - private final int version; - - public Secret(Key key, byte[] secret, int version) { - this.key = key; - this.secret = secret; - this.version = version; - } - - public String keyGroup() { - return key.keyGroup(); - } - - public String keyName() { - return key.keyName(); - } - - public byte[] secret() { - return secret; - } - - public String secretAsString() { return Utf8.toString(secret); } - - /** @return secret value for keys that are auto-rotated by CKMS */ - public byte[] secretAsYbase64Decoded() { return YBase64.decode(secret); } - - public int version() { - return version; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Secret that = (Secret) o; - if ( ! (that.key.equals(key))) return false; - if ( ! (Arrays.equals(that.secret, secret))) return false; - if (that.version != (version)) return false; - return true; - } - - @Override - public int hashCode() { - return Objects.hash(key, version, Arrays.hashCode(secret)); - } - -} diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/secret/TypedSecretStore.java b/container-disc/src/main/java/com/yahoo/container/jdisc/secret/TypedSecretStore.java deleted file mode 100644 index 5bb00e836f5..00000000000 --- a/container-disc/src/main/java/com/yahoo/container/jdisc/secret/TypedSecretStore.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.yahoo.container.jdisc.secret; - -import com.yahoo.container.jdisc.secretstore.SecretStore; - -import java.util.List; - -public interface TypedSecretStore extends SecretStore { - - Secret getSecret(Key key); - - Secret getSecret(Key key, int version); - - /** Lists the existing versions of this secret (nonnegative integers) */ - default List<Secret> listSecretVersions(Key key) { - throw new UnsupportedOperationException("Secret store does not support listing versions"); - } - -} diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/secret/package-info.java b/container-disc/src/main/java/com/yahoo/container/jdisc/secret/package-info.java deleted file mode 100644 index c80c6e66066..00000000000 --- a/container-disc/src/main/java/com/yahoo/container/jdisc/secret/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -@ExportPackage -package com.yahoo.container.jdisc.secret; - -import com.yahoo.osgi.annotation.ExportPackage; diff --git a/dependency-versions/pom.xml b/dependency-versions/pom.xml index ea055e97476..e06b8e0dd4b 100644 --- a/dependency-versions/pom.xml +++ b/dependency-versions/pom.xml @@ -33,7 +33,7 @@ <!-- DO NOT UPGRADE THESE TO A NEW MAJOR VERSION WITHOUT CHECKING FOR BINARY COMPATIBILITY --> <aopalliance.vespa.version>1.0</aopalliance.vespa.version> - <error-prone-annotations.vespa.version>2.26.0</error-prone-annotations.vespa.version> + <error-prone-annotations.vespa.version>2.26.1</error-prone-annotations.vespa.version> <guava.vespa.version>33.0.0-jre</guava.vespa.version> <guice.vespa.version>6.0.0</guice.vespa.version> <jackson2.vespa.version>2.16.2</jackson2.vespa.version> diff --git a/document/abi-spec.json b/document/abi-spec.json index ca4b4da3ca0..5096039a941 100644 --- a/document/abi-spec.json +++ b/document/abi-spec.json @@ -2863,7 +2863,8 @@ "public abstract void write(com.yahoo.document.Document)", "public abstract void write(com.yahoo.document.DocumentId)", "public abstract void write(com.yahoo.document.DocumentType)", - "public abstract void write(com.yahoo.document.DocumentRemove)" + "public abstract void write(com.yahoo.document.DocumentRemove)", + "public abstract void write(com.yahoo.document.DocumentUpdate)" ], "fields" : [ ] }, diff --git a/document/src/main/java/com/yahoo/document/DocumentUpdate.java b/document/src/main/java/com/yahoo/document/DocumentUpdate.java index d3063b76feb..20d9b352d2d 100644 --- a/document/src/main/java/com/yahoo/document/DocumentUpdate.java +++ b/document/src/main/java/com/yahoo/document/DocumentUpdate.java @@ -147,7 +147,7 @@ public class DocumentUpdate extends DocumentOperation implements Iterable<FieldP Map.Entry<Integer, FieldUpdate> entry = iter.next(); FieldUpdate update = entry.getValue(); if (!update.isEmpty()) { - ValueUpdate last = update.getValueUpdate(update.size() - 1); + ValueUpdate<?> last = update.getValueUpdate(update.size() - 1); if (last instanceof AssignValueUpdate) { FieldValue currentValue = doc.getFieldValue(update.getField()); if ((currentValue != null) && currentValue.equals(last.getValue())) { @@ -190,7 +190,7 @@ public class DocumentUpdate extends DocumentOperation implements Iterable<FieldP /** Returns the type of the document this updates * - * @return The documentype of the document + * @return The document type of the document */ public DocumentType getDocumentType() { return documentType; @@ -357,9 +357,7 @@ public class DocumentUpdate extends DocumentOperation implements Iterable<FieldP @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof DocumentUpdate)) return false; - - DocumentUpdate that = (DocumentUpdate) o; + if (!(o instanceof DocumentUpdate that)) return false; if (docId != null ? !docId.equals(that.docId) : that.docId != null) return false; if (documentType != null ? !documentType.equals(that.documentType) : that.documentType != null) return false; @@ -413,7 +411,7 @@ public class DocumentUpdate extends DocumentOperation implements Iterable<FieldP } /** - * Returns whether or not this field update contains any field- or field path updates. + * Returns whether this field update contains any field- or field path updates. * * @return True if this update is empty. */ diff --git a/document/src/main/java/com/yahoo/document/json/JsonWriter.java b/document/src/main/java/com/yahoo/document/json/JsonWriter.java index 9cbadb65f10..2b0ba138466 100644 --- a/document/src/main/java/com/yahoo/document/json/JsonWriter.java +++ b/document/src/main/java/com/yahoo/document/json/JsonWriter.java @@ -9,6 +9,7 @@ import com.yahoo.document.Document; import com.yahoo.document.DocumentId; import com.yahoo.document.DocumentRemove; import com.yahoo.document.DocumentType; +import com.yahoo.document.DocumentUpdate; import com.yahoo.document.Field; import com.yahoo.document.annotation.AnnotationReference; import com.yahoo.document.datatypes.Array; @@ -264,6 +265,7 @@ public class JsonWriter implements DocumentWriter { // NOP, fetched from Document } + @Override public void write(DocumentRemove documentRemove) { try { generator.writeStartObject(); @@ -277,6 +279,12 @@ public class JsonWriter implements DocumentWriter { } } + @Override + public void write(DocumentUpdate documentUpdate) { + var serializer = new DocumentUpdateJsonSerializer(generator); + serializer.serialize(documentUpdate); + } + /** * Utility method to easily serialize a single document. * diff --git a/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateWriter.java b/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateWriter.java index 0202ec8bf23..b9cc439ad54 100644 --- a/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateWriter.java +++ b/document/src/main/java/com/yahoo/document/serialization/DocumentUpdateWriter.java @@ -17,8 +17,7 @@ import com.yahoo.document.update.TensorRemoveUpdate; /** * Interface for writing document updates in custom serializers. * - * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a> - * @since 5.1.27 + * @author Einar M R Rosenvinge */ public interface DocumentUpdateWriter { void write(DocumentUpdate update); diff --git a/document/src/main/java/com/yahoo/document/serialization/DocumentWriter.java b/document/src/main/java/com/yahoo/document/serialization/DocumentWriter.java index 10483d8609f..16125926fe6 100644 --- a/document/src/main/java/com/yahoo/document/serialization/DocumentWriter.java +++ b/document/src/main/java/com/yahoo/document/serialization/DocumentWriter.java @@ -5,6 +5,7 @@ import com.yahoo.document.Document; import com.yahoo.document.DocumentId; import com.yahoo.document.DocumentRemove; import com.yahoo.document.DocumentType; +import com.yahoo.document.DocumentUpdate; /** * @author ravishar @@ -20,4 +21,6 @@ public interface DocumentWriter extends FieldWriter { void write(DocumentRemove documentRemove); + void write(DocumentUpdate documentUpdate); + } diff --git a/document/src/vespa/document/select/branch.cpp b/document/src/vespa/document/select/branch.cpp index 02f767c96b5..6035b5fe9a0 100644 --- a/document/src/vespa/document/select/branch.cpp +++ b/document/src/vespa/document/select/branch.cpp @@ -39,6 +39,10 @@ namespace { ResultList traceAndValue(const T& value, std::ostream& out, const Node& leftNode, const Node& rightNode) { + out << "And (lhs):\n"; + (void)leftNode.trace(value, out); + out << "And (rhs):\n"; + (void)rightNode.trace(value, out); out << "And - Left branch returned " << leftNode.contains(value) << ".\n"; out << "And - Right branch returned " << rightNode.contains(value) << ".\n"; return leftNode.contains(value) && rightNode.contains(value); @@ -83,6 +87,10 @@ namespace { ResultList traceOrValue(const T& value, std::ostream& out, const Node& leftNode, const Node& rightNode) { + out << "Or (lhs):\n"; + (void)leftNode.trace(value, out); + out << "Or (rhs):\n"; + (void)rightNode.trace(value, out); out << "Or - Left branch returned " << leftNode.contains(value) << ".\n"; out << "Or - Right branch returned " << rightNode.contains(value) << ".\n"; return leftNode.contains(value) || rightNode.contains(value); @@ -122,6 +130,8 @@ namespace { template<typename T> ResultList traceNotValue(const T& value, std::ostream& out, const Node& node) { + out << "Not:\n"; + (void)node.trace(value, out); out << "Not - Child returned " << node.contains(value) << ". Returning opposite.\n"; return !node.contains(value); diff --git a/messagebus/src/tests/sequencer/CMakeLists.txt b/messagebus/src/tests/sequencer/CMakeLists.txt index bdcd4d1b2da..0c00209f3c7 100644 --- a/messagebus/src/tests/sequencer/CMakeLists.txt +++ b/messagebus/src/tests/sequencer/CMakeLists.txt @@ -5,5 +5,6 @@ vespa_add_executable(messagebus_sequencer_test_app TEST DEPENDS messagebus_messagebus-test messagebus + GTest::gtest ) vespa_add_test(NAME messagebus_sequencer_test_app COMMAND messagebus_sequencer_test_app) diff --git a/messagebus/src/tests/sequencer/sequencer.cpp b/messagebus/src/tests/sequencer/sequencer.cpp index 3fb905bce7a..8814ff45f1d 100644 --- a/messagebus/src/tests/sequencer/sequencer.cpp +++ b/messagebus/src/tests/sequencer/sequencer.cpp @@ -4,7 +4,7 @@ #include <vespa/messagebus/sequencer.h> #include <vespa/messagebus/routablequeue.h> #include <vespa/messagebus/emptyreply.h> -#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/gtest/gtest.h> #include <cinttypes> #include <vespa/log/log.h> @@ -82,32 +82,13 @@ struct MyQueue : public RoutableQueue { } }; -class Test : public vespalib::TestApp { -private: - void testSyncNone(); - void testSyncId(); - -public: - int Main() override { - TEST_INIT("sequencer_test"); - - testSyncNone(); TEST_FLUSH(); - testSyncId(); TEST_FLUSH(); - - TEST_DONE(); - } -}; - -TEST_APPHOOK(Test); - // -------------------------------------------------------------------------------- // // Tests. // // -------------------------------------------------------------------------------- -void -Test::testSyncNone() +TEST(SequencerTest, test_sync_none) { MyQueue src; MyQueue dst; @@ -118,28 +99,27 @@ Test::testSyncNone() seq.handleMessage(src.createMessage(false, 0)); seq.handleMessage(src.createMessage(false, 0)); seq.handleMessage(src.createMessage(false, 0)); - EXPECT_EQUAL(0u, src.size()); - EXPECT_EQUAL(5u, dst.size()); + EXPECT_EQ(0u, src.size()); + EXPECT_EQ(5u, dst.size()); dst.replyNext(); dst.replyNext(); dst.replyNext(); dst.replyNext(); dst.replyNext(); - EXPECT_EQUAL(5u, src.size()); - EXPECT_EQUAL(0u, dst.size()); + EXPECT_EQ(5u, src.size()); + EXPECT_EQ(0u, dst.size()); EXPECT_TRUE(src.checkReply(false, 0)); EXPECT_TRUE(src.checkReply(false, 0)); EXPECT_TRUE(src.checkReply(false, 0)); EXPECT_TRUE(src.checkReply(false, 0)); EXPECT_TRUE(src.checkReply(false, 0)); - EXPECT_EQUAL(0u, src.size()); - EXPECT_EQUAL(0u, dst.size()); + EXPECT_EQ(0u, src.size()); + EXPECT_EQ(0u, dst.size()); } -void -Test::testSyncId() +TEST(SequencerTest, test_sync_id) { MyQueue src; MyQueue dst; @@ -150,8 +130,8 @@ Test::testSyncId() seq.handleMessage(src.createMessage(true, 3)); seq.handleMessage(src.createMessage(true, 4)); seq.handleMessage(src.createMessage(true, 5)); - EXPECT_EQUAL(0u, src.size()); - EXPECT_EQUAL(5u, dst.size()); + EXPECT_EQ(0u, src.size()); + EXPECT_EQ(5u, dst.size()); seq.handleMessage(src.createMessage(true, 1)); seq.handleMessage(src.createMessage(true, 5)); @@ -159,16 +139,16 @@ Test::testSyncId() seq.handleMessage(src.createMessage(true, 10)); seq.handleMessage(src.createMessage(true, 4)); seq.handleMessage(src.createMessage(true, 3)); - EXPECT_EQUAL(0u, src.size()); - EXPECT_EQUAL(6u, dst.size()); + EXPECT_EQ(0u, src.size()); + EXPECT_EQ(6u, dst.size()); dst.replyNext(); dst.replyNext(); dst.replyNext(); dst.replyNext(); dst.replyNext(); - EXPECT_EQUAL(5u, src.size()); - EXPECT_EQUAL(6u, dst.size()); + EXPECT_EQ(5u, src.size()); + EXPECT_EQ(6u, dst.size()); dst.replyNext(); dst.replyNext(); @@ -176,8 +156,8 @@ Test::testSyncId() dst.replyNext(); dst.replyNext(); dst.replyNext(); - EXPECT_EQUAL(11u, src.size()); - EXPECT_EQUAL(0u, dst.size()); + EXPECT_EQ(11u, src.size()); + EXPECT_EQ(0u, dst.size()); EXPECT_TRUE(src.checkReply(true, 1)); EXPECT_TRUE(src.checkReply(true, 2)); @@ -190,6 +170,8 @@ Test::testSyncId() EXPECT_TRUE(src.checkReply(true, 3)); EXPECT_TRUE(src.checkReply(true, 4)); EXPECT_TRUE(src.checkReply(true, 5)); - EXPECT_EQUAL(0u, src.size()); - EXPECT_EQUAL(0u, dst.size()); + EXPECT_EQ(0u, src.size()); + EXPECT_EQ(0u, dst.size()); } + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchcore/src/tests/proton/common/cachedselect_test.cpp b/searchcore/src/tests/proton/common/cachedselect_test.cpp index 8c2913a3d1b..a0c8fef3b83 100644 --- a/searchcore/src/tests/proton/common/cachedselect_test.cpp +++ b/searchcore/src/tests/proton/common/cachedselect_test.cpp @@ -102,7 +102,8 @@ makeDocTypeRepo() addField("aa", DataType::T_INT). addField("aaa", Array(DataType::T_INT)). addField("aaw", Wset(DataType::T_INT)). - addField("ab", DataType::T_INT)); + addField("ab", DataType::T_INT)). + imported_field("my_imported_field"); builder.document(doc_type_id + 1, type_name_2, Struct(header_name_2), Struct(body_name_2). addField("ic", DataType::T_STRING). @@ -152,12 +153,17 @@ checkSelect(const NodeUP &sel, void checkSelect(const CachedSelect::SP &cs, + uint32_t docId, const Document &doc, const Result &exp) { + SelectContext ctx(*cs); + ctx._docId = docId; + ctx._doc = &doc; + ctx.getAttributeGuards(); bool expSessionContains = (cs->preDocOnlySelect() || (exp == Result::True)); - EXPECT_TRUE(checkSelect(cs->docSelect(), Context(doc), exp)); - EXPECT_EQUAL(expSessionContains, cs->createSession()->contains(doc)); + EXPECT_TRUE(checkSelect(cs->docSelect(), ctx, exp)); + EXPECT_EQUAL(expSessionContains, cs->createSession()->contains_doc(ctx)); } void @@ -170,7 +176,7 @@ checkSelect(const CachedSelect::SP &cs, ctx._docId = docId; ctx.getAttributeGuards(); EXPECT_TRUE(checkSelect((cs->preDocOnlySelect() ? cs->preDocOnlySelect() : cs->preDocSelect()), ctx, exp)); - EXPECT_EQUAL(expSessionContains, cs->createSession()->contains(ctx)); + EXPECT_EQUAL(expSessionContains, cs->createSession()->contains_pre_doc(ctx)); } void @@ -271,18 +277,22 @@ MyDB::addDoc(uint32_t lid, Document::UP doc(makeDoc(_repo, docId, ia, ib, aa, ab)); _docIdToLid[docId] = lid; - _lidToDocSP[lid] = Document::SP(doc.release()); - AttributeGuard::UP guard = _amgr.getAttribute("aa"); - AttributeVector &av = *guard->get(); - if (lid >= av.getNumDocs()) { - AttributeVector::DocId checkDocId(0u); - ASSERT_TRUE(av.addDoc(checkDocId)); - ASSERT_EQUAL(lid, checkDocId); - } - IntegerAttribute &iav(static_cast<IntegerAttribute &>(av)); - AttributeVector::largeint_t laa(aa); - EXPECT_TRUE(iav.update(lid, laa)); - av.commit(); + _lidToDocSP[lid] = std::move(doc); + auto add_attr_value = [lid, aa](auto guard) { + AttributeVector &av = *guard->get(); + if (lid >= av.getNumDocs()) { + AttributeVector::DocId checkDocId(0u); + ASSERT_TRUE(av.addDoc(checkDocId)); + ASSERT_EQUAL(lid, checkDocId); + } + auto &iav(dynamic_cast<IntegerAttribute &>(av)); + AttributeVector::largeint_t laa(aa); + EXPECT_TRUE(iav.update(lid, laa)); + av.commit(); + }; + + add_attr_value(_amgr.getAttribute("aa")); + add_attr_value(_amgr.getAttribute("my_imported_field")); } @@ -327,15 +337,14 @@ TestFixture::TestFixture() _amgr.addAttribute("aa"); _amgr.addAttribute("aaa", AttributeFactory::createAttribute("aaa", {BasicType::INT32, CollectionType::ARRAY})); _amgr.addAttribute("aaw", AttributeFactory::createAttribute("aaw", {BasicType::INT32, CollectionType::WSET})); + // "Faked" imported attribute, as in `selectpruner_test.cpp` + _amgr.addAttribute("my_imported_field", AttributeFactory::createAttribute("my_imported_field", { BasicType::INT32 })); - _db.reset(new MyDB(*_repoUP, _amgr)); + _db = std::make_unique<MyDB>(*_repoUP, _amgr); } -TestFixture::~TestFixture() -{ -} - +TestFixture::~TestFixture() = default; CachedSelect::SP TestFixture::testParse(const string &selection, @@ -475,45 +484,45 @@ TEST_F("Test that basic select works", TestFixture) cs = f.testParse("test.ia == \"hello\"", "test"); TEST_DO(assertEquals(Stats().fieldNodes(1).attrFieldNodes(0).svAttrFieldNodes(0), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::True)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::False)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::False)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::False)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::True)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::False)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::False)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::False)); cs = f.testParse("test.ia.foo == \"hello\"", "test"); TEST_DO(assertEquals(Stats().allInvalid(), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::Invalid)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::Invalid)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::Invalid)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); cs = f.testParse("test.ia[2] == \"hello\"", "test"); TEST_DO(assertEquals(Stats().allInvalid(), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::Invalid)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::Invalid)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::Invalid)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); cs = f.testParse("test.ia{foo} == \"hello\"", "test"); TEST_DO(assertEquals(Stats().allInvalid(), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::Invalid)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::Invalid)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::Invalid)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); cs = f.testParse("test.ia < \"hello\"", "test"); TEST_DO(assertEquals(Stats().fieldNodes(1).attrFieldNodes(0).svAttrFieldNodes(0), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::False)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::True)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::True)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::False)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::True)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::True)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); cs = f.testParse("test.aa == 3", "test"); TEST_DO(assertEquals(Stats().preDocOnlySelect().fieldNodes(1).attrFieldNodes(1).svAttrFieldNodes(1), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::False)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::True)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::False)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::False)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::False)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::True)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::False)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::False)); TEST_DO(checkSelect(cs, 1u, Result::False)); TEST_DO(checkSelect(cs, 2u, Result::True)); TEST_DO(checkSelect(cs, 3u, Result::False)); @@ -521,24 +530,24 @@ TEST_F("Test that basic select works", TestFixture) cs = f.testParse("test.aa.foo == 3", "test"); TEST_DO(assertEquals(Stats().allInvalid(), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::Invalid)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::Invalid)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::Invalid)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); cs = f.testParse("test.aa[2] == 3", "test"); TEST_DO(assertEquals(Stats().allInvalid(), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::Invalid)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::Invalid)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::Invalid)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); cs = f.testParse("test.aa{4} > 3", "test"); TEST_DO(assertEquals(Stats().allInvalid(), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::Invalid)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::Invalid)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::Invalid)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); cs = f.testParse("test.aaa[2] == 3", "test"); TEST_DO(assertEquals(Stats().fieldNodes(1).attrFieldNodes(1).svAttrFieldNodes(0), *cs)); @@ -548,10 +557,10 @@ TEST_F("Test that basic select works", TestFixture) cs = f.testParse("test.aa < 45", "test"); TEST_DO(assertEquals(Stats().preDocOnlySelect().fieldNodes(1).attrFieldNodes(1).svAttrFieldNodes(1), *cs)); - TEST_DO(checkSelect(cs, db.getDoc(1u), Result::False)); - TEST_DO(checkSelect(cs, db.getDoc(2u), Result::True)); - TEST_DO(checkSelect(cs, db.getDoc(3u), Result::Invalid)); - TEST_DO(checkSelect(cs, db.getDoc(4u), Result::Invalid)); + TEST_DO(checkSelect(cs, 1u, db.getDoc(1u), Result::False)); + TEST_DO(checkSelect(cs, 2u, db.getDoc(2u), Result::True)); + TEST_DO(checkSelect(cs, 3u, db.getDoc(3u), Result::Invalid)); + TEST_DO(checkSelect(cs, 4u, db.getDoc(4u), Result::Invalid)); TEST_DO(checkSelect(cs, 1u, Result::False, false)); TEST_DO(checkSelect(cs, 2u, Result::True, true)); TEST_DO(checkSelect(cs, 3u, Result::Invalid, false)); @@ -580,9 +589,9 @@ TEST_F("Test that single value attribute combined with non-attribute field resul TEST_DO(checkSelect(cs, 1u, Result::Invalid, true)); TEST_DO(checkSelect(cs, 2u, Result::Invalid, true)); TEST_DO(checkSelect(cs, 3u, Result::False, false)); - TEST_DO(checkSelect(cs, f.db().getDoc(1u), Result::True)); - TEST_DO(checkSelect(cs, f.db().getDoc(2u), Result::False)); - TEST_DO(checkSelect(cs, f.db().getDoc(3u), Result::False)); + TEST_DO(checkSelect(cs, 1u, f.db().getDoc(1u), Result::True)); + TEST_DO(checkSelect(cs, 2u, f.db().getDoc(2u), Result::False)); + TEST_DO(checkSelect(cs, 3u, f.db().getDoc(3u), Result::False)); } TEST_F("Test that single value attribute with complex attribute field results in pre-document select pruner", PreDocSelectFixture) @@ -593,9 +602,39 @@ TEST_F("Test that single value attribute with complex attribute field results in TEST_DO(checkSelect(cs, 1u, Result::Invalid, true)); TEST_DO(checkSelect(cs, 2u, Result::Invalid, true)); TEST_DO(checkSelect(cs, 3u, Result::False, false)); - TEST_DO(checkSelect(cs, f.db().getDoc(1u), Result::False)); - TEST_DO(checkSelect(cs, f.db().getDoc(2u), Result::False)); - TEST_DO(checkSelect(cs, f.db().getDoc(3u), Result::False)); + TEST_DO(checkSelect(cs, 1u, f.db().getDoc(1u), Result::False)); + TEST_DO(checkSelect(cs, 2u, f.db().getDoc(2u), Result::False)); + TEST_DO(checkSelect(cs, 3u, f.db().getDoc(3u), Result::False)); +} + +TEST_F("Imported field can be used in pre-doc selections with only attribute fields", PreDocSelectFixture) { + auto cs = f.testParse("test.my_imported_field == 3", "test"); + TEST_DO(assertEquals(Stats().preDocOnlySelect().fieldNodes(1).attrFieldNodes(1).svAttrFieldNodes(1), *cs)); + + TEST_DO(checkSelect(cs, 1u, Result::True, true)); + TEST_DO(checkSelect(cs, 2u, Result::True, true)); + TEST_DO(checkSelect(cs, 3u, Result::False, false)); + // Cannot match against document here since preDocOnly is set; will just return false. + TEST_DO(checkSelect(cs, 1u, f.db().getDoc(1u), Result::False)); + TEST_DO(checkSelect(cs, 2u, f.db().getDoc(2u), Result::False)); + TEST_DO(checkSelect(cs, 3u, f.db().getDoc(3u), Result::False)); +} + +TEST_F("Imported field can be used in doc selections with mixed attribute/non-attribute fields", PreDocSelectFixture) { + // `id.namespace` requires a doc store fetch and cannot be satisfied by attributes alone + auto cs = f.testParse("test.my_imported_field == 3 and id.namespace != 'foo'", "test"); + TEST_DO(assertEquals(Stats().preDocSelect().fieldNodes(2).attrFieldNodes(1).svAttrFieldNodes(1), *cs)); + + // 2 first checks cannot be completed in pre-doc stage alone + TEST_DO(checkSelect(cs, 1u, Result::Invalid, true)); // -> doc eval stage + TEST_DO(checkSelect(cs, 2u, Result::Invalid, true)); // -> doc eval stage + TEST_DO(checkSelect(cs, 3u, Result::False, false)); // short-circuited since attr value 7 != 3 + // When matching against a concrete document, it's crucial that the selection AST contains + // attribute references for at least all imported fields, or we'll implicitly fall back to + // returning null for all imported fields (as they do not exist in the document itself). + TEST_DO(checkSelect(cs, 1u, f.db().getDoc(1u), Result::True)); + TEST_DO(checkSelect(cs, 2u, f.db().getDoc(2u), Result::True)); + TEST_DO(checkSelect(cs, 3u, f.db().getDoc(3u), Result::False)); } TEST_F("Test performance when using attributes", TestFixture) diff --git a/searchcore/src/tests/proton/common/selectpruner_test.cpp b/searchcore/src/tests/proton/common/selectpruner_test.cpp index e175836b838..1f71da5aeda 100644 --- a/searchcore/src/tests/proton/common/selectpruner_test.cpp +++ b/searchcore/src/tests/proton/common/selectpruner_test.cpp @@ -799,6 +799,12 @@ TEST_F("Imported fields with matching attribute names are supported", TestFixtur "test.my_imported_field > 0"); } +TEST_F("Imported fields can be used alongside non-attribute fields", TestFixture) +{ + f.testPrune("test.my_imported_field > 0 and id.namespace != \"foo\"", + "test.my_imported_field > 0 and id.namespace != \"foo\""); +} + // Edge case: document type reconfigured but attribute not yet visible in Proton TEST_F("Imported fields without matching attribute are mapped to constant NullValue", TestFixture) { diff --git a/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.cpp b/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.cpp index d94b0a4c909..d22fed89ad1 100644 --- a/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.cpp +++ b/searchcore/src/vespa/searchcore/proton/common/attributefieldvaluenode.cpp @@ -40,7 +40,7 @@ std::unique_ptr<document::select::Value> AttributeFieldValueNode:: getValue(const Context &context) const { - const auto &sc(static_cast<const SelectContext &>(context)); + const auto &sc(dynamic_cast<const SelectContext &>(context)); uint32_t docId(sc._docId); assert(docId != 0u); const auto& v = sc.guarded_attribute_at_index(_attr_guard_index); diff --git a/searchcore/src/vespa/searchcore/proton/common/cachedselect.cpp b/searchcore/src/vespa/searchcore/proton/common/cachedselect.cpp index 293ed3bdcb9..9f890f5d480 100644 --- a/searchcore/src/vespa/searchcore/proton/common/cachedselect.cpp +++ b/searchcore/src/vespa/searchcore/proton/common/cachedselect.cpp @@ -35,13 +35,16 @@ public: uint32_t _mvAttrs; uint32_t _complexAttrs; - uint32_t getFieldNodes() const { return _fieldNodes; } + [[nodiscard]] uint32_t getFieldNodes() const { return _fieldNodes; } - static uint32_t invalidIdx() { + constexpr static uint32_t invalidIdx() noexcept { return std::numeric_limits<uint32_t>::max(); } AttrVisitor(const search::IAttributeManager &amgr, CachedSelect::AttributeVectors &attributes); + AttrVisitor(const search::IAttributeManager &amgr, + CachedSelect::AttributeVectors &attributes, + AttrMap existing_attr_map); ~AttrVisitor() override; /* @@ -62,6 +65,18 @@ AttrVisitor::AttrVisitor(const search::IAttributeManager &amgr, CachedSelect::At _complexAttrs(0u) {} +AttrVisitor::AttrVisitor(const search::IAttributeManager &amgr, + CachedSelect::AttributeVectors &attributes, + AttrMap existing_attr_map) + : CloningVisitor(), + _amap(std::move(existing_attr_map)), + _amgr(amgr), + _attributes(attributes), + _svAttrs(0u), + _mvAttrs(0u), + _complexAttrs(0u) +{} + AttrVisitor::~AttrVisitor() = default; bool isSingleValueThatWeHandle(BasicType type) { @@ -130,7 +145,7 @@ CachedSelect::Session::Session(std::unique_ptr<document::select::Node> docSelect } bool -CachedSelect::Session::contains(const SelectContext &context) const +CachedSelect::Session::contains_pre_doc(const SelectContext &context) const { if (_preDocSelect && (_preDocSelect->contains(context) == document::select::Result::False)) { return false; @@ -140,10 +155,10 @@ CachedSelect::Session::contains(const SelectContext &context) const } bool -CachedSelect::Session::contains(const document::Document &doc) const +CachedSelect::Session::contains_doc(const SelectContext &context) const { return (_preDocOnlySelect) || - (_docSelect && (_docSelect->contains(doc) == document::select::Result::True)); + (_docSelect && (_docSelect->contains(context) == document::select::Result::True)); } const document::select::Node & @@ -177,8 +192,12 @@ CachedSelect::setPreDocumentSelect(const search::IAttributeManager &attrMgr, if (_fieldNodes == _svAttrFieldNodes) { _preDocOnlySelect = std::move(allAttrVisitor.getNode()); } else if (_svAttrFieldNodes > 0) { - _attributes.clear(); - AttrVisitor someAttrVisitor(attrMgr, _attributes); + // Also let document-level selection use attribute wiring; otherwise imported fields + // would not resolve to anything, as these do not exist in the concrete document itself. + _docSelect = std::move(allAttrVisitor.getNode()); + [[maybe_unused]] size_t attrs_before = _attributes.size(); + AttrVisitor someAttrVisitor(attrMgr, _attributes, std::move(allAttrVisitor._amap)); + assert(_attributes.size() == attrs_before); noDocsPruner.getNode()->visit(someAttrVisitor); _preDocSelect = std::move(someAttrVisitor.getNode()); } diff --git a/searchcore/src/vespa/searchcore/proton/common/cachedselect.h b/searchcore/src/vespa/searchcore/proton/common/cachedselect.h index b0660399f6f..89f002bd939 100644 --- a/searchcore/src/vespa/searchcore/proton/common/cachedselect.h +++ b/searchcore/src/vespa/searchcore/proton/common/cachedselect.h @@ -42,9 +42,10 @@ public: Session(std::unique_ptr<document::select::Node> docSelect, std::unique_ptr<document::select::Node> preDocOnlySelect, std::unique_ptr<document::select::Node> preDocSelect); - bool contains(const SelectContext &context) const; - bool contains(const document::Document &doc) const; - const document::select::Node &selectNode() const; + [[nodiscard]] bool contains_pre_doc(const SelectContext &context) const; + // Precondition: context must have non-nullptr _doc + [[nodiscard]] bool contains_doc(const SelectContext &context) const; + [[nodiscard]] const document::select::Node &selectNode() const; }; using AttributeVectors = std::vector<std::shared_ptr<search::attribute::ReadableAttributeVector>>; diff --git a/searchcore/src/vespa/searchcore/proton/common/selectpruner.h b/searchcore/src/vespa/searchcore/proton/common/selectpruner.h index 3612914fc6f..3322a07ebd7 100644 --- a/searchcore/src/vespa/searchcore/proton/common/selectpruner.h +++ b/searchcore/src/vespa/searchcore/proton/common/selectpruner.h @@ -36,7 +36,7 @@ public: class SelectPruner : public document::select::CloningVisitor, - public SelectPrunerBase + public SelectPrunerBase { public: private: @@ -53,16 +53,16 @@ public: bool hasFields, bool hasDocuments); - SelectPruner(const SelectPruner *rhs); - virtual ~SelectPruner(); + explicit SelectPruner(const SelectPruner *rhs); + ~SelectPruner() override; - uint32_t getFieldNodes() const { return _fieldNodes; } - uint32_t getAttrFieldNodes() const { return _attrFieldNodes; } - const document::select::ResultSet & getResultSet() const { return _resultSet; } - bool isFalse() const; - bool isTrue() const; - bool isInvalid() const; - bool isConst() const; + [[nodiscard]] uint32_t getFieldNodes() const noexcept { return _fieldNodes; } + [[nodiscard]] uint32_t getAttrFieldNodes() const noexcept { return _attrFieldNodes; } + [[nodiscard]] const document::select::ResultSet & getResultSet() const noexcept { return _resultSet; } + [[nodiscard]] bool isFalse() const; + [[nodiscard]] bool isTrue() const; + [[nodiscard]] bool isInvalid() const; + [[nodiscard]] bool isConst() const; void trace(std::ostream &t); void process(const document::select::Node &node); private: @@ -83,8 +83,8 @@ private: void setTernaryConst(bool val); void set_null_value_node(); void resolveTernaryConst(bool wantInverted); - bool isInvalidVal() const; - bool isNullVal() const; + [[nodiscard]] bool isInvalidVal() const; + [[nodiscard]] bool isNullVal() const; void swap(SelectPruner &rhs); }; diff --git a/searchcore/src/vespa/searchcore/proton/persistenceengine/document_iterator.cpp b/searchcore/src/vespa/searchcore/proton/persistenceengine/document_iterator.cpp index e9d233ef6ec..85c0eb0c1f2 100644 --- a/searchcore/src/vespa/searchcore/proton/persistenceengine/document_iterator.cpp +++ b/searchcore/src/vespa/searchcore/proton/persistenceengine/document_iterator.cpp @@ -171,28 +171,31 @@ public: } } - bool willAlwaysFail() const { return _willAlwaysFail; } + [[nodiscard]] bool willAlwaysFail() const noexcept { return _willAlwaysFail; } - bool match(const search::DocumentMetaData & meta) const { + [[nodiscard]] bool match(const search::DocumentMetaData & meta) const { if (meta.lid >= _docidLimit) { return false; } if (_dscTrue || _metaOnly) { return true; } - if (_selectCxt) { - _selectCxt->_docId = meta.lid; - } if (!_gidFilter.gid_might_match_selection(meta.gid)) { return false; } - return _selectSession->contains(*_selectCxt); + assert(_selectCxt); + _selectCxt->_docId = meta.lid; + _selectCxt->_doc = nullptr; + return _selectSession->contains_pre_doc(*_selectCxt); } - bool match(const search::DocumentMetaData & meta, const Document * doc) const { + [[nodiscard]] bool match(const search::DocumentMetaData & meta, const Document * doc) const { if (_dscTrue || _metaOnly) { return true; } - return (doc && (doc->getId().getGlobalId() == meta.gid) && _selectSession->contains(*doc)); + assert(_selectCxt); + _selectCxt->_docId = meta.lid; + _selectCxt->_doc = doc; + return (doc && (doc->getId().getGlobalId() == meta.gid) && _selectSession->contains_doc(*_selectCxt)); } private: bool _dscTrue; diff --git a/searchlib/src/tests/diskindex/bitvector/CMakeLists.txt b/searchlib/src/tests/diskindex/bitvector/CMakeLists.txt index b227d3d5fa8..f70a1efd23c 100644 --- a/searchlib/src/tests/diskindex/bitvector/CMakeLists.txt +++ b/searchlib/src/tests/diskindex/bitvector/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_bitvector_test-diskindex_app TEST bitvector_test.cpp DEPENDS searchlib + GTest::gtest ) vespa_add_test(NAME searchlib_bitvector_test-diskindex_app COMMAND searchlib_bitvector_test-diskindex_app) diff --git a/searchlib/src/tests/diskindex/bitvector/bitvector_test.cpp b/searchlib/src/tests/diskindex/bitvector/bitvector_test.cpp index 6032b7156ff..5e4b8763534 100644 --- a/searchlib/src/tests/diskindex/bitvector/bitvector_test.cpp +++ b/searchlib/src/tests/diskindex/bitvector/bitvector_test.cpp @@ -1,16 +1,13 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/searchlib/index/field_length_info.h> #include <vespa/searchlib/diskindex/bitvectordictionary.h> #include <vespa/searchlib/diskindex/fieldwriter.h> #include <vespa/searchlib/index/dummyfileheadercontext.h> #include <vespa/searchcommon/common/schema.h> +#include <vespa/vespalib/gtest/gtest.h> #include <filesystem> -#include <vespa/log/log.h> -LOG_SETUP("bitvector_test"); - using namespace search::index; using search::index::schema::DataType; @@ -58,38 +55,57 @@ FieldWriterWrapper::add(uint32_t docId) daf.elements().emplace_back(0); daf.elements().back().setNumOccs(1); daf.word_positions().emplace_back(0); - //LOG(info, "add(%" PRIu64 ", %u)", wordNum, docId); _writer.add(daf); return *this; } -class Test : public vespalib::TestApp +struct TestParam { + bool directio; + bool readmmap; +}; + +std::ostream& operator<<(std::ostream& os, const TestParam& param) +{ + os << (param.directio ? "directio" : "normal") << (param.readmmap ? "mmap" : "read"); + return os; +} + +class BitVectorTest : public ::testing::TestWithParam<TestParam> { -private: +protected: Schema _schema; uint32_t _indexId; -public: - void requireThatDictionaryHandlesNoEntries(bool directio, bool readmmap); - void requireThatDictionaryHandlesMultipleEntries(bool directio, bool readmmap); - - Test(); - ~Test() override; - int Main() override; + BitVectorTest(); + ~BitVectorTest() override; }; -void -Test::requireThatDictionaryHandlesNoEntries(bool directio, bool readmmap) +BitVectorTest::BitVectorTest() + : ::testing::TestWithParam<TestParam>(), + _schema(), + _indexId(0) +{ + _schema.addIndexField(Schema::IndexField("f1", DataType::STRING)); +} + +BitVectorTest::~BitVectorTest() = default; + +INSTANTIATE_TEST_SUITE_P(BitVectorMultiTest, BitVectorTest, + ::testing::Values(TestParam{false, false}, TestParam{true, false}, TestParam{false, true}), + ::testing::PrintToStringParamName()); + +TEST_P(BitVectorTest, require_that_dictionary_handles_no_entries) { TuneFileSeqWrite tuneFileWrite; TuneFileRandRead tuneFileRead; DummyFileHeaderContext fileHeaderContext; - if (directio) { + if (GetParam().directio) { tuneFileWrite.setWantDirectIO(); tuneFileRead.setWantDirectIO(); } - if (readmmap) + if (GetParam().readmmap) { tuneFileRead.setWantMemoryMap(); + } std::filesystem::create_directory(std::filesystem::path("dump")); FieldWriterWrapper fww(5, 2, "dump/1/"); EXPECT_TRUE(fww.open(_schema, _indexId, tuneFileWrite, fileHeaderContext)); @@ -100,25 +116,25 @@ Test::requireThatDictionaryHandlesNoEntries(bool directio, bool readmmap) BitVectorDictionary dict; BitVectorKeyScope bvScope(BitVectorKeyScope::PERFIELD_WORDS); EXPECT_TRUE(dict.open("dump/1/", tuneFileRead, bvScope)); - EXPECT_EQUAL(5u, dict.getDocIdLimit()); - EXPECT_EQUAL(0u, dict.getEntries().size()); + EXPECT_EQ(5u, dict.getDocIdLimit()); + EXPECT_EQ(0u, dict.getEntries().size()); EXPECT_FALSE(dict.lookup(1)); EXPECT_FALSE(dict.lookup(2)); } -void -Test::requireThatDictionaryHandlesMultipleEntries(bool directio, bool readmmap) +TEST_P(BitVectorTest, require_that_dictionary_handles_multiple_entries) { TuneFileSeqWrite tuneFileWrite; TuneFileRandRead tuneFileRead; DummyFileHeaderContext fileHeaderContext; - if (directio) { + if (GetParam().directio) { tuneFileWrite.setWantDirectIO(); tuneFileRead.setWantDirectIO(); } - if (readmmap) + if (GetParam().readmmap) { tuneFileRead.setWantMemoryMap(); + } FieldWriterWrapper fww(64, 6, "dump/2/"); EXPECT_TRUE(fww.open(_schema, _indexId, tuneFileWrite, fileHeaderContext)); // must have >16 docs in order to create bitvector for a word @@ -149,16 +165,16 @@ Test::requireThatDictionaryHandlesMultipleEntries(bool directio, bool readmmap) BitVectorDictionary dict; BitVectorKeyScope bvScope(BitVectorKeyScope::PERFIELD_WORDS); EXPECT_TRUE(dict.open("dump/2/", tuneFileRead, bvScope)); - EXPECT_EQUAL(64u, dict.getDocIdLimit()); - EXPECT_EQUAL(2u, dict.getEntries().size()); + EXPECT_EQ(64u, dict.getDocIdLimit()); + EXPECT_EQ(2u, dict.getEntries().size()); BitVectorWordSingleKey e; e = dict.getEntries()[0]; - EXPECT_EQUAL(1u, e._wordNum); - EXPECT_EQUAL(17u, e._numDocs); + EXPECT_EQ(1u, e._wordNum); + EXPECT_EQ(17u, e._numDocs); e = dict.getEntries()[1]; - EXPECT_EQUAL(5u, e._wordNum); - EXPECT_EQUAL(23u, e._numDocs); + EXPECT_EQ(5u, e._wordNum); + EXPECT_EQ(23u, e._numDocs); EXPECT_FALSE(dict.lookup(2)); EXPECT_FALSE(dict.lookup(3)); @@ -174,33 +190,14 @@ Test::requireThatDictionaryHandlesMultipleEntries(bool directio, bool readmmap) EXPECT_TRUE(*bv5exp == *bv5act); } -Test::Test() - : _schema(), - _indexId(0) -{ - _schema.addIndexField(Schema::IndexField("f1", DataType::STRING)); } -Test::~Test() = default; - int -Test::Main() +main(int argc, char* argv[]) { - TEST_INIT("bitvector_test"); - - if (_argc > 0) { - DummyFileHeaderContext::setCreator(_argv[0]); + ::testing::InitGoogleTest(&argc, argv); + if (argc > 0) { + search::index::DummyFileHeaderContext::setCreator(argv[0]); } - TEST_DO(requireThatDictionaryHandlesNoEntries(false, false)); - TEST_DO(requireThatDictionaryHandlesMultipleEntries(false, false)); - TEST_DO(requireThatDictionaryHandlesNoEntries(true, false)); - TEST_DO(requireThatDictionaryHandlesMultipleEntries(true, false)); - TEST_DO(requireThatDictionaryHandlesNoEntries(false, true)); - TEST_DO(requireThatDictionaryHandlesMultipleEntries(false, true)); - - TEST_DONE(); + return RUN_ALL_TESTS(); } - -} - -TEST_APPHOOK(search::diskindex::Test); diff --git a/searchlib/src/tests/fef/attributecontent/CMakeLists.txt b/searchlib/src/tests/fef/attributecontent/CMakeLists.txt index 48d8375dbb9..d9c88fb9eaf 100644 --- a/searchlib/src/tests/fef/attributecontent/CMakeLists.txt +++ b/searchlib/src/tests/fef/attributecontent/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_attributecontent_test_app TEST attributecontent_test.cpp DEPENDS searchlib + GTest::gtest ) vespa_add_test(NAME searchlib_attributecontent_test_app COMMAND searchlib_attributecontent_test_app) diff --git a/searchlib/src/tests/fef/attributecontent/attributecontent_test.cpp b/searchlib/src/tests/fef/attributecontent/attributecontent_test.cpp index 1c75d47a134..d501d259ea5 100644 --- a/searchlib/src/tests/fef/attributecontent/attributecontent_test.cpp +++ b/searchlib/src/tests/fef/attributecontent/attributecontent_test.cpp @@ -1,34 +1,21 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/searchcommon/attribute/attributecontent.h> #include <vespa/searchcommon/attribute/config.h> #include <vespa/searchlib/attribute/attributefactory.h> #include <vespa/searchlib/attribute/integerbase.h> -#include <vespa/log/log.h> -LOG_SETUP("attributecontent_test"); +#include <vespa/vespalib/gtest/gtest.h> using namespace search::attribute; -namespace search { -namespace fef { +namespace search::fef { -class Test : public vespalib::TestApp { -private: - void testWriteAndRead(); - void testFill(); - -public: - int Main() override; -}; - -void -Test::testWriteAndRead() +TEST(AttributeContentTest, test_write_and_read) { using UintContent = search::attribute::AttributeContent<uint32_t>; UintContent buf; - EXPECT_EQUAL(buf.capacity(), 16u); - EXPECT_EQUAL(buf.size(), 0u); + EXPECT_EQ(buf.capacity(), 16u); + EXPECT_EQ(buf.size(), 0u); uint32_t i; uint32_t * data; @@ -37,34 +24,33 @@ Test::testWriteAndRead() *data = i; } buf.setSize(16); - EXPECT_EQUAL(buf.size(), 16u); + EXPECT_EQ(buf.size(), 16u); for (i = 0, itr = buf.begin(); itr != buf.end(); ++i, ++itr) { - EXPECT_EQUAL(*itr, i); - EXPECT_EQUAL(buf[i], i); + EXPECT_EQ(*itr, i); + EXPECT_EQ(buf[i], i); } - EXPECT_EQUAL(i, 16u); + EXPECT_EQ(i, 16u); buf.allocate(10); - EXPECT_EQUAL(buf.capacity(), 16u); - EXPECT_EQUAL(buf.size(), 16u); + EXPECT_EQ(buf.capacity(), 16u); + EXPECT_EQ(buf.size(), 16u); buf.allocate(32); - EXPECT_EQUAL(buf.capacity(), 32u); - EXPECT_EQUAL(buf.size(), 0u); + EXPECT_EQ(buf.capacity(), 32u); + EXPECT_EQ(buf.size(), 0u); for (i = 0, data = buf.data(); i < 32; ++i, ++data) { *data = i; } buf.setSize(32); - EXPECT_EQUAL(buf.size(), 32u); + EXPECT_EQ(buf.size(), 32u); for (i = 0, itr = buf.begin(); itr != buf.end(); ++i, ++itr) { - EXPECT_EQUAL(*itr, i); - EXPECT_EQUAL(buf[i], i); + EXPECT_EQ(*itr, i); + EXPECT_EQ(buf[i], i); } - EXPECT_EQUAL(i, 32u); + EXPECT_EQ(i, 32u); } -void -Test::testFill() +TEST(AttributeContentTest, test_fill) { Config cfg(BasicType::INT32, CollectionType::ARRAY); AttributeVector::SP av = AttributeFactory::createAttribute("aint32", cfg); @@ -77,29 +63,17 @@ Test::testFill() const IAttributeVector & iav = *av.get(); IntegerContent buf; buf.fill(iav, 0); - EXPECT_EQUAL(1u, buf.size()); - EXPECT_EQUAL(10, buf[0]); + EXPECT_EQ(1u, buf.size()); + EXPECT_EQ(10, buf[0]); buf.fill(iav, 1); - EXPECT_EQUAL(2u, buf.size()); - EXPECT_EQUAL(20, buf[0]); - EXPECT_EQUAL(30, buf[1]); + EXPECT_EQ(2u, buf.size()); + EXPECT_EQ(20, buf[0]); + EXPECT_EQ(30, buf[1]); buf.fill(iav, 0); - EXPECT_EQUAL(1u, buf.size()); - EXPECT_EQUAL(10, buf[0]); + EXPECT_EQ(1u, buf.size()); + EXPECT_EQ(10, buf[0]); } -int -Test::Main() -{ - TEST_INIT("attributecontent_test"); - - testWriteAndRead(); - testFill(); - - TEST_DONE(); } -} // namespace fef -} // namespace search - -TEST_APPHOOK(search::fef::Test); +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/fef/featurenameparser/CMakeLists.txt b/searchlib/src/tests/fef/featurenameparser/CMakeLists.txt index e7874558122..cb040472a6f 100644 --- a/searchlib/src/tests/fef/featurenameparser/CMakeLists.txt +++ b/searchlib/src/tests/fef/featurenameparser/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_featurenameparser_test_app TEST featurenameparser_test.cpp DEPENDS searchlib + GTest::gtest ) vespa_add_test(NAME searchlib_featurenameparser_test_app COMMAND searchlib_featurenameparser_test_app) diff --git a/searchlib/src/tests/fef/featurenameparser/featurenameparser_test.cpp b/searchlib/src/tests/fef/featurenameparser/featurenameparser_test.cpp index 90a9135389a..ee22a49f8db 100644 --- a/searchlib/src/tests/fef/featurenameparser/featurenameparser_test.cpp +++ b/searchlib/src/tests/fef/featurenameparser/featurenameparser_test.cpp @@ -1,13 +1,15 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/log/log.h> -LOG_SETUP("featurenameparser_test"); -#include <vespa/vespalib/testkit/test_kit.h> -#include <vespa/vespalib/testkit/testapp.h> -#include <vespa/vespalib/util/size_literals.h> + #include <vespa/searchlib/fef/featurenameparser.h> +#include <vespa/vespalib/gtest/gtest.h> +#include <vespa/vespalib/testkit/test_path.h> +#include <vespa/vespalib/util/size_literals.h> #include <vector> #include <string> +#include <vespa/log/log.h> +LOG_SETUP("featurenameparser_test"); + using namespace search::fef; struct ParamList { @@ -31,20 +33,10 @@ std::ostream &operator<<(std::ostream &os, const ParamList &pl) { return os; } -class Test : public vespalib::TestApp -{ -public: - bool testParse(const vespalib::string &input, bool valid, - const vespalib::string &base, ParamList pl, - const vespalib::string &output); - void testFile(const vespalib::string &name); - int Main() override; -}; - bool -Test::testParse(const vespalib::string &input, bool valid, - const vespalib::string &base, ParamList pl, - const vespalib::string &output) +testParse(const vespalib::string &input, bool valid, + const vespalib::string &base, ParamList pl, + const vespalib::string &output) { bool ok = true; FeatureNameParser parser(input); @@ -52,15 +44,15 @@ Test::testParse(const vespalib::string &input, bool valid, LOG(warning, "parse error: input:'%s', rest:'%s'", input.c_str(), input.substr(parser.parsedBytes()).c_str()); } - ok &= EXPECT_EQUAL(parser.valid(), valid); - ok &= EXPECT_EQUAL(parser.baseName(), base); - ok &= EXPECT_EQUAL(ParamList(parser.parameters()), pl); - ok &= EXPECT_EQUAL(parser.output(), output); + EXPECT_EQ(parser.valid(), valid) << (ok = false, ""); + EXPECT_EQ(parser.baseName(), base) << (ok = false, ""); + EXPECT_EQ(ParamList(parser.parameters()), pl) << (ok = false, ""); + EXPECT_EQ(parser.output(), output) << (ok = false, ""); return ok; } void -Test::testFile(const vespalib::string &name) +testFile(const vespalib::string &name) { char buf[4_Ki]; uint32_t lineN = 0; @@ -76,13 +68,16 @@ Test::testFile(const vespalib::string &name) continue; } uint32_t idx = line.find("<=>"); - if (!EXPECT_TRUE(idx < line.size())) { + bool failed = false; + EXPECT_TRUE(idx < line.size()) << (failed = true, ""); + if (failed) { LOG(error, "(%s:%u): malformed line: '%s'", name.c_str(), lineN, line.c_str()); } else { vespalib::string input = line.substr(0, idx); vespalib::string expect = line.substr(idx + strlen("<=>")); - if (!EXPECT_EQUAL(FeatureNameParser(input).featureName(), expect)) { + EXPECT_EQ(FeatureNameParser(input).featureName(), expect) << (failed = true, ""); + if (failed) { LOG(error, "(%s:%u): test failed: '%s'", name.c_str(), lineN, line.c_str()); } @@ -92,42 +87,54 @@ Test::testFile(const vespalib::string &name) fclose(f); } -int -Test::Main() +TEST(FeatureNameParserTest, test_normal_cases) { - TEST_INIT("featurenameparser_test"); - // normal cases EXPECT_TRUE(testParse("foo", true, "foo", ParamList(), "")); EXPECT_TRUE(testParse("foo.out", true, "foo", ParamList(), "out")); EXPECT_TRUE(testParse("foo(a)", true, "foo", ParamList().add("a"), "")); EXPECT_TRUE(testParse("foo(a,b)", true, "foo", ParamList().add("a").add("b"), "")); EXPECT_TRUE(testParse("foo(a,b).out", true, "foo", ParamList().add("a").add("b"), "out")); +} +TEST(FeatureNameParserTest, test_0_in_feature_name) +{ // @ in feature name (for macros) EXPECT_TRUE(testParse("foo@", true, "foo@", ParamList(), "")); EXPECT_TRUE(testParse("foo@.out", true, "foo@", ParamList(), "out")); EXPECT_TRUE(testParse("foo@(a)", true, "foo@", ParamList().add("a"), "")); EXPECT_TRUE(testParse("foo@(a,b)", true, "foo@", ParamList().add("a").add("b"), "")); EXPECT_TRUE(testParse("foo@(a,b).out", true, "foo@", ParamList().add("a").add("b"), "out")); +} +TEST(FeatureNameParserTest, test_dollar_in_feature_name) +{ // $ in feature name (for macros) EXPECT_TRUE(testParse("foo$", true, "foo$", ParamList(), "")); EXPECT_TRUE(testParse("foo$.out", true, "foo$", ParamList(), "out")); EXPECT_TRUE(testParse("foo$(a)", true, "foo$", ParamList().add("a"), "")); EXPECT_TRUE(testParse("foo$(a,b)", true, "foo$", ParamList().add("a").add("b"), "")); EXPECT_TRUE(testParse("foo$(a,b).out", true, "foo$", ParamList().add("a").add("b"), "out")); +} +TEST(FeatureNameParserTest, test_de_quoting_of_parameters) +{ // de-quoting of parameters EXPECT_TRUE(testParse("foo(a,\"b\")", true, "foo", ParamList().add("a").add("b"), "")); EXPECT_TRUE(testParse("foo(a,\" b \")", true, "foo", ParamList().add("a").add(" b "), "")); EXPECT_TRUE(testParse("foo( \"a\" , \" b \" )", true, "foo", ParamList().add("a").add(" b "), "")); EXPECT_TRUE(testParse("foo(\"\\\"\\\\\\t\\n\\r\\f\\x20\")", true, "foo", ParamList().add("\"\\\t\n\r\f "), "")); +} +TEST(FeatureNameParserTest, test_no_default_output_when_ending_with_dot) +{ // only default output if '.' not specified EXPECT_TRUE(testParse("foo.", false, "", ParamList(), "")); EXPECT_TRUE(testParse("foo(a,b).", false, "", ParamList(), "")); +} +TEST(FeatureNameParserTest, test_string_cannot_end_in_parmeter_list) +{ // string cannot end in parameter list EXPECT_TRUE(testParse("foo(", false, "", ParamList(), "")); EXPECT_TRUE(testParse("foo(a", false, "", ParamList(), "")); @@ -135,7 +142,10 @@ Test::Main() EXPECT_TRUE(testParse("foo(a\\)", false, "", ParamList(), "")); EXPECT_TRUE(testParse("foo(a,", false, "", ParamList(), "")); EXPECT_TRUE(testParse("foo(a,b", false, "", ParamList(), "")); +} +TEST(FeatureNameParserTest, test_empty_parameters) +{ // empty parameters EXPECT_TRUE(testParse("foo()", true, "foo", ParamList().add(""), "")); EXPECT_TRUE(testParse("foo(,)", true, "foo", ParamList().add("").add(""), "")); @@ -144,9 +154,11 @@ Test::Main() EXPECT_TRUE(testParse("foo( )", true, "foo", ParamList().add(""), "")); EXPECT_TRUE(testParse("foo( , , )", true, "foo", ParamList().add("").add("").add(""), "")); EXPECT_TRUE(testParse("foo( \t , \n , \r , \f )", true, "foo", ParamList().add("").add("").add("").add(""), "")); +} +TEST(FeatureNameParserTest, test_cases_from_file) +{ testFile(TEST_PATH("parsetest.txt")); - TEST_DONE(); } -TEST_APPHOOK(Test); +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/fef/parameter/CMakeLists.txt b/searchlib/src/tests/fef/parameter/CMakeLists.txt index da847e061f9..b238e09c98b 100644 --- a/searchlib/src/tests/fef/parameter/CMakeLists.txt +++ b/searchlib/src/tests/fef/parameter/CMakeLists.txt @@ -4,5 +4,6 @@ vespa_add_executable(searchlib_parameter_test_app TEST parameter_test.cpp DEPENDS searchlib + GTest::gtest ) vespa_add_test(NAME searchlib_parameter_test_app NO_VALGRIND COMMAND searchlib_parameter_test_app) diff --git a/searchlib/src/tests/fef/parameter/parameter_test.cpp b/searchlib/src/tests/fef/parameter/parameter_test.cpp index fa29f16f1d5..a8acd2ea34d 100644 --- a/searchlib/src/tests/fef/parameter/parameter_test.cpp +++ b/searchlib/src/tests/fef/parameter/parameter_test.cpp @@ -1,32 +1,34 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/log/log.h> -LOG_SETUP("parameter_test"); -#include <vespa/vespalib/testkit/testapp.h> #include <vespa/searchlib/fef/parametervalidator.h> #include <vespa/searchlib/fef/test/indexenvironment.h> #include <vespa/searchlib/fef/test/indexenvironmentbuilder.h> +#include <vespa/vespalib/gtest/gtest.h> + +#include <vespa/log/log.h> +LOG_SETUP("parameter_test"); using namespace search::fef::test; using CollectionType = search::fef::FieldInfo::CollectionType; using DataType = search::fef::FieldInfo::DataType; -namespace search { -namespace fef { +namespace search::fef { class StringList : public std::vector<vespalib::string> { public: StringList & add(const vespalib::string & str) { push_back(str); return *this; } }; -class ParameterTest : public vespalib::TestApp { -private: +class ParameterTest : public ::testing::Test { +protected: using PDS = ParameterDescriptions; using PT = ParameterType; using P = Parameter; using SL = StringList; using PVR = ParameterValidator::Result; + ParameterTest(); + ~ParameterTest() override; bool assertParameter(const Parameter & exp, const Parameter & act); bool validate(const IIndexEnvironment & env, const std::vector<vespalib::string> & params, @@ -35,24 +37,20 @@ private: const std::vector<vespalib::string> & params, const ParameterDescriptions & descs, const ParameterValidator::Result & result); - - void testDescriptions(); - void testValidator(); - void testParameters(); - -public: - int Main() override; }; +ParameterTest::ParameterTest() = default; +ParameterTest::~ParameterTest() = default; + bool ParameterTest::assertParameter(const Parameter & exp, const Parameter & act) { bool retval = true; - if (!EXPECT_EQUAL(exp.getType(), act.getType())) retval = false; - if (!EXPECT_EQUAL(exp.getValue(), act.getValue())) retval = false; - if (!EXPECT_EQUAL(exp.asDouble(), act.asDouble())) retval = false; - if (!EXPECT_EQUAL(exp.asInteger(), act.asInteger())) retval = false; - if (!EXPECT_EQUAL(exp.asField(), act.asField())) retval = false; + EXPECT_EQ(exp.getType(), act.getType()) << (retval = false, ""); + EXPECT_EQ(exp.getValue(), act.getValue()) << (retval = false, ""); + EXPECT_EQ(exp.asDouble(), act.asDouble()) << (retval = false, ""); + EXPECT_EQ(exp.asInteger(), act.asInteger()) << (retval = false, ""); + EXPECT_EQ(exp.asField(), act.asField()) << (retval = false, ""); return retval; } @@ -76,8 +74,15 @@ ParameterTest::validate(const IIndexEnvironment & env, if (!validate(env, params, descs)) return false; ParameterValidator pv(env, params, descs); ParameterValidator::Result actual = pv.validate(); - if (!EXPECT_EQUAL(result.getTag(), actual.getTag())) return false; - if (!EXPECT_EQUAL(result.getParameters().size(), actual.getParameters().size())) return false; + bool failed = false; + EXPECT_EQ(result.getTag(), actual.getTag()) << (failed = true, ""); + if (failed) { + return false; + } + EXPECT_EQ(result.getParameters().size(), actual.getParameters().size()) << (failed = true, ""); + if (failed) { + return false; + } bool retval = true; for (size_t i = 0; i < result.getParameters().size(); ++i) { if (!assertParameter(result.getParameters()[i], actual.getParameters()[i])) retval = false; @@ -85,52 +90,50 @@ ParameterTest::validate(const IIndexEnvironment & env, return retval; } -void -ParameterTest::testDescriptions() +TEST_F(ParameterTest, test_descriptions) { PDS descs = PDS(). desc().indexField(ParameterCollection::SINGLE).indexField(ParameterCollection::ARRAY).indexField(ParameterCollection::WEIGHTEDSET).attribute(ParameterCollection::ANY).attributeField(ParameterCollection::ANY).field(). desc(5).feature().number().string().attribute(ParameterCollection::ANY). desc().string().number().repeat(2); const PDS::DescriptionVector & v = descs.getDescriptions(); - EXPECT_EQUAL(v.size(), 3u); - EXPECT_EQUAL(v[0].getTag(), 0u); + EXPECT_EQ(v.size(), 3u); + EXPECT_EQ(v[0].getTag(), 0u); EXPECT_TRUE(!v[0].hasRepeat()); - EXPECT_EQUAL(v[0].getParams().size(), 6u); - EXPECT_EQUAL(v[0].getParam(0).type, ParameterType::INDEX_FIELD); - EXPECT_EQUAL(v[0].getParam(1).type, ParameterType::INDEX_FIELD); - EXPECT_EQUAL(v[0].getParam(2).type, ParameterType::INDEX_FIELD); - EXPECT_EQUAL(v[0].getParam(3).type, ParameterType::ATTRIBUTE); - EXPECT_EQUAL(v[0].getParam(4).type, ParameterType::ATTRIBUTE_FIELD); - EXPECT_EQUAL(v[0].getParam(5).type, ParameterType::FIELD); - EXPECT_EQUAL(v[0].getParam(0).collection, ParameterCollection::SINGLE); - EXPECT_EQUAL(v[0].getParam(1).collection, ParameterCollection::ARRAY); - EXPECT_EQUAL(v[0].getParam(2).collection, ParameterCollection::WEIGHTEDSET); - EXPECT_EQUAL(v[0].getParam(3).collection, ParameterCollection::ANY); - EXPECT_EQUAL(v[0].getParam(4).collection, ParameterCollection::ANY); - EXPECT_EQUAL(v[0].getParam(5).collection, ParameterCollection::ANY); + EXPECT_EQ(v[0].getParams().size(), 6u); + EXPECT_EQ(v[0].getParam(0).type, ParameterType::INDEX_FIELD); + EXPECT_EQ(v[0].getParam(1).type, ParameterType::INDEX_FIELD); + EXPECT_EQ(v[0].getParam(2).type, ParameterType::INDEX_FIELD); + EXPECT_EQ(v[0].getParam(3).type, ParameterType::ATTRIBUTE); + EXPECT_EQ(v[0].getParam(4).type, ParameterType::ATTRIBUTE_FIELD); + EXPECT_EQ(v[0].getParam(5).type, ParameterType::FIELD); + EXPECT_EQ(v[0].getParam(0).collection, ParameterCollection::SINGLE); + EXPECT_EQ(v[0].getParam(1).collection, ParameterCollection::ARRAY); + EXPECT_EQ(v[0].getParam(2).collection, ParameterCollection::WEIGHTEDSET); + EXPECT_EQ(v[0].getParam(3).collection, ParameterCollection::ANY); + EXPECT_EQ(v[0].getParam(4).collection, ParameterCollection::ANY); + EXPECT_EQ(v[0].getParam(5).collection, ParameterCollection::ANY); - EXPECT_EQUAL(v[1].getTag(), 5u); + EXPECT_EQ(v[1].getTag(), 5u); EXPECT_TRUE(!v[1].hasRepeat()); - EXPECT_EQUAL(v[1].getParams().size(), 4u); - EXPECT_EQUAL(v[1].getParam(0).type, ParameterType::FEATURE); - EXPECT_EQUAL(v[1].getParam(1).type, ParameterType::NUMBER); - EXPECT_EQUAL(v[1].getParam(2).type, ParameterType::STRING); - EXPECT_EQUAL(v[1].getParam(3).type, ParameterType::ATTRIBUTE); + EXPECT_EQ(v[1].getParams().size(), 4u); + EXPECT_EQ(v[1].getParam(0).type, ParameterType::FEATURE); + EXPECT_EQ(v[1].getParam(1).type, ParameterType::NUMBER); + EXPECT_EQ(v[1].getParam(2).type, ParameterType::STRING); + EXPECT_EQ(v[1].getParam(3).type, ParameterType::ATTRIBUTE); - EXPECT_EQUAL(v[2].getTag(), 6u); + EXPECT_EQ(v[2].getTag(), 6u); EXPECT_TRUE(v[2].hasRepeat()); - EXPECT_EQUAL(v[2].getParams().size(), 2u); - EXPECT_EQUAL(v[2].getParam(0).type, ParameterType::STRING); - EXPECT_EQUAL(v[2].getParam(1).type, ParameterType::NUMBER); - EXPECT_EQUAL(v[2].getParam(2).type, ParameterType::STRING); - EXPECT_EQUAL(v[2].getParam(3).type, ParameterType::NUMBER); - EXPECT_EQUAL(v[2].getParam(4).type, ParameterType::STRING); - EXPECT_EQUAL(v[2].getParam(5).type, ParameterType::NUMBER); + EXPECT_EQ(v[2].getParams().size(), 2u); + EXPECT_EQ(v[2].getParam(0).type, ParameterType::STRING); + EXPECT_EQ(v[2].getParam(1).type, ParameterType::NUMBER); + EXPECT_EQ(v[2].getParam(2).type, ParameterType::STRING); + EXPECT_EQ(v[2].getParam(3).type, ParameterType::NUMBER); + EXPECT_EQ(v[2].getParam(4).type, ParameterType::STRING); + EXPECT_EQ(v[2].getParam(5).type, ParameterType::NUMBER); } -void -ParameterTest::testValidator() +TEST_F(ParameterTest, test_validator) { IndexEnvironment env; IndexEnvironmentBuilder builder(env); @@ -201,8 +204,7 @@ ParameterTest::testValidator() EXPECT_TRUE(!validate(env, SL().add("str").add("bar").add("foo").add("bar"), d2)); } -void -ParameterTest::testParameters() +TEST_F(ParameterTest, test_parameters) { IndexEnvironment env; IndexEnvironmentBuilder builder(env); @@ -254,20 +256,6 @@ ParameterTest::testParameters() PVR(20).addParameter(P(PT::STRING, "baz")))); // second desc matching } -int -ParameterTest::Main() -{ - TEST_INIT("parameter_test"); - - testDescriptions(); - testValidator(); - testParameters(); - - TEST_DONE(); } -} -} - -TEST_APPHOOK(search::fef::ParameterTest); - +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/vespaclient-java/src/main/java/com/yahoo/vespa/feed/perf/SimpleFeeder.java b/vespaclient-java/src/main/java/com/yahoo/vespa/feed/perf/SimpleFeeder.java index 3a7fe8f75c6..386468e85e8 100644 --- a/vespaclient-java/src/main/java/com/yahoo/vespa/feed/perf/SimpleFeeder.java +++ b/vespaclient-java/src/main/java/com/yahoo/vespa/feed/perf/SimpleFeeder.java @@ -192,6 +192,10 @@ public class SimpleFeeder implements ReplyHandler { addCommaAndNewline(); writer.write(op.getDocumentRemove()); } + case UPDATE -> { + addCommaAndNewline(); + writer.write(op.getDocumentUpdate()); + } default -> { /* TODO: No more operations supported yet */ } } numReplies.incrementAndGet(); diff --git a/vespaclient-java/src/test/java/com/yahoo/vespa/feed/perf/SimpleFeederTest.java b/vespaclient-java/src/test/java/com/yahoo/vespa/feed/perf/SimpleFeederTest.java index 2810303fad3..6776b71eea6 100644 --- a/vespaclient-java/src/test/java/com/yahoo/vespa/feed/perf/SimpleFeederTest.java +++ b/vespaclient-java/src/test/java/com/yahoo/vespa/feed/perf/SimpleFeederTest.java @@ -87,10 +87,11 @@ public class SimpleFeederTest { "", "(.+\n)+" + "\\s*\\d+,\\s*3,.+\n"); - assertEquals(96, dump.size()); + assertEquals(169, dump.size()); assertEquals(""" [ {"id":"id:simple:simple::0","fields":{"my_str":"foo"}}, + {"update":"id:simple:simple::1","fields":{"my_str":{"assign":"bar"}}}, {"remove":"id:simple:simple::2"} ]""", dump.toString()); |