diff options
author | Geir Storli <geirst@yahooinc.com> | 2023-04-27 14:01:00 +0000 |
---|---|---|
committer | Geir Storli <geirst@yahooinc.com> | 2023-04-27 14:11:03 +0000 |
commit | 232b1d3460c1a15aa64e1aae3f516dbfda290701 (patch) | |
tree | fce0623f10d0656bf90010b0d80fd8561b339019 /streamingvisitors/src/tests/searchvisitor/searchvisitor_test.cpp | |
parent | f5dd3cb5d31875cf596adc01f2207f690afe553f (diff) |
Test basic query execution in search visitor.
Diffstat (limited to 'streamingvisitors/src/tests/searchvisitor/searchvisitor_test.cpp')
-rw-r--r-- | streamingvisitors/src/tests/searchvisitor/searchvisitor_test.cpp | 224 |
1 files changed, 177 insertions, 47 deletions
diff --git a/streamingvisitors/src/tests/searchvisitor/searchvisitor_test.cpp b/streamingvisitors/src/tests/searchvisitor/searchvisitor_test.cpp index 5521994e60e..b93a2c25f82 100644 --- a/streamingvisitors/src/tests/searchvisitor/searchvisitor_test.cpp +++ b/streamingvisitors/src/tests/searchvisitor/searchvisitor_test.cpp @@ -1,6 +1,8 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/document/base/testdocrepo.h> +#include <vespa/document/datatype/documenttype.h> +#include <vespa/document/fieldvalue/document.h> #include <vespa/document/repo/documenttyperepo.h> #include <vespa/persistence/spi/docentry.h> #include <vespa/searchlib/query/tree/querybuilder.h> @@ -22,27 +24,149 @@ using namespace storage; namespace streaming { -class SearchVisitorTest : public testing::Test -{ +vespalib::string get_doc_id(int id) { + return "id:test:test::" + std::to_string(id); +} + +/** + * This class reflects the document type defined in cfg/test.sd. + */ +struct MyDocument { + int id; + MyDocument(int id_in) : id(id_in) {} + std::unique_ptr<Document> to_document(const DocumentTypeRepo& repo, const DataType& doc_type) const { + auto result = std::make_unique<Document>(repo, doc_type, DocumentId(get_doc_id(id))); + result->setValue("id", std::make_unique<IntFieldValue>(id)); + return result; + } +}; + +using DocumentVector = std::vector<MyDocument>; + +struct MyHit { + vespalib::string doc_id; + double rank; + MyHit(int id, double rank_in) noexcept : doc_id(get_doc_id(id)), rank(rank_in) {} + MyHit(int id) noexcept : doc_id(get_doc_id(id)), rank(0.0) {} + MyHit(const vespalib::string& doc_id_in, double rank_in) noexcept : doc_id(doc_id_in), rank(rank_in) {} + bool operator==(const MyHit& rhs) const { + return (doc_id == rhs.doc_id) && + (rank == rhs.rank); + } +}; + +using HitVector = std::vector<MyHit>; + +std::ostream& operator<<(std::ostream& oss, const MyHit& hit) { + oss << "{doc_id=" << hit.doc_id << ",rank=" << hit.rank << "}"; + return oss; +} + +class RequestBuilder { +private: + vdslib::Parameters _params; + QueryBuilder<SimpleQueryNodeTypes> _builder; + int32_t _term_id; + +public: + RequestBuilder() : _params(), _builder(), _term_id(1) + { + search_cluster("mycl"); + rank_profile("myrank"); + summary_class("mysum"); + summary_count(10); + } + RequestBuilder& set_param(const vespalib::string& key, const vespalib::string& value) { + _params.set(key, value); + return *this; + } + RequestBuilder& search_cluster(const vespalib::string& value) { return set_param("searchcluster", value); } + RequestBuilder& rank_profile(const vespalib::string& value) { return set_param("rankprofile", value); } + RequestBuilder& summary_class(const vespalib::string& value) { return set_param("summaryclass", value); } + RequestBuilder& summary_count(uint32_t value) { return set_param("summarycount", std::to_string(value)); } + RequestBuilder& string_term(const vespalib::string& term, const vespalib::string& field) { + _builder.addStringTerm(term, field, _term_id++, Weight(100)); + return *this; + } + RequestBuilder& number_term(const vespalib::string& term, const vespalib::string& field) { + _builder.addNumberTerm(term, field, _term_id++, Weight(100)); + return *this; + } + vdslib::Parameters build() { + auto node = _builder.build(); + vespalib::string query_stack_dump = StackDumpCreator::create(*node); + _params.set("query", query_stack_dump); + return _params; + } +}; + +struct VisitorSession { + std::unique_ptr<SearchVisitor> search_visitor; + Visitor& visitor; + Visitor::HitCounter hit_counter; + VisitorSession(SearchVisitor* sv) + : search_visitor(sv), + visitor(*search_visitor), + hit_counter() + { + } + void handle_documents(Visitor::DocEntryList& docs) { + document::BucketId bucket_id; + visitor.handleDocuments(bucket_id, docs, hit_counter); + } + std::unique_ptr<documentapi::QueryResultMessage> generate_query_result() { + return search_visitor->generate_query_result(hit_counter); + } +}; + +class SearchVisitorTest : public testing::Test { public: framework::defaultimplementation::FakeClock _clock; StorageComponentRegisterImpl _componentRegister; std::unique_ptr<StorageComponent> _component; SearchEnvironment _env; - void testCreateSearchVisitor(const vespalib::string & dir, const vdslib::Parameters & parameters); + SearchVisitorFactory _factory; + std::shared_ptr<DocumentTypeRepo> _repo; + const document::DocumentType* _doc_type; SearchVisitorTest(); ~SearchVisitorTest() override; + + std::unique_ptr<VisitorSession> make_visitor_session(const vdslib::Parameters& params) { + VisitorFactory& factory(_factory); + auto *visitor = factory.makeVisitor(*_component, _env, params); + auto *search_visitor = dynamic_cast<SearchVisitor *>(visitor); + assert(search_visitor != nullptr); + return std::make_unique<VisitorSession>(search_visitor); + } + Visitor::DocEntryList make_documents(const std::vector<MyDocument>& docs) const { + Visitor::DocEntryList result; + for (const auto& doc : docs) { + result.push_back(spi::DocEntry::create(spi::Timestamp(), + doc.to_document(*_repo, *_doc_type))); + } + return result; + } + std::unique_ptr<documentapi::QueryResultMessage> execute_query(const vdslib::Parameters& params, + const DocumentVector& docs) { + auto session = make_visitor_session(params); + auto entries = make_documents(docs); + session->handle_documents(entries); + return session->generate_query_result(); + } }; SearchVisitorTest::SearchVisitorTest() : _componentRegister(), - _env(::config::ConfigUri("dir:cfg")) + _env(::config::ConfigUri("dir:cfg")), + _factory(::config::ConfigUri("dir:cfg")), + _repo(std::make_shared<DocumentTypeRepo>(readDocumenttypesConfig("cfg/documenttypes.cfg"))), + _doc_type(_repo->getDocumentType("test")) { - _componentRegister.setNodeInfo("mycluster", lib::NodeType::STORAGE, 1); + assert(_doc_type != nullptr); + _componentRegister.setNodeInfo("mycl", lib::NodeType::STORAGE, 1); _componentRegister.setClock(_clock); - auto repo = std::make_shared<DocumentTypeRepo>(readDocumenttypesConfig("cfg/documenttypes.cfg")); - _componentRegister.setDocumentTypeRepo(repo); + _componentRegister.setDocumentTypeRepo(_repo); _component = std::make_unique<StorageComponent>(_componentRegister, "storage"); } @@ -51,61 +175,67 @@ SearchVisitorTest::~SearchVisitorTest() _env.clear_thread_local_env_map(); } -Visitor::DocEntryList -createDocuments(const vespalib::string & dir) +TEST_F(SearchVisitorTest, search_environment_is_configured) +{ + EXPECT_TRUE(_env.getVSMAdapter("mycl") != nullptr); + EXPECT_TRUE(_env.getRankManager("mycl") != nullptr); +} + +HitVector +to_hit_vector(vdslib::SearchResult& res) +{ + HitVector result; + const char* doc_id; + double rank; + for (size_t i = 0; i < res.getHitCount(); ++i) { + res.getHit(i, doc_id, rank); + result.emplace_back(vespalib::string(doc_id), rank); + } + return result; +} + +HitVector +to_hit_vector(vdslib::DocumentSummary& sum) { - (void) dir; - Visitor::DocEntryList documents; - spi::Timestamp ts; - auto e = spi::DocEntry::create(ts, std::make_unique<Document>()); - documents.push_back(std::move(e)); - return documents; + HitVector result; + const char* doc_id; + const void* buf; + size_t sz; + for (size_t i = 0; i < sum.getSummaryCount(); ++i) { + sum.getSummary(i, doc_id, buf, sz); + result.emplace_back(vespalib::string(doc_id), 0.0); + } + return result; } void -SearchVisitorTest::testCreateSearchVisitor(const vespalib::string & dir, const vdslib::Parameters & params) +expect_hits(const HitVector& exp_hits, documentapi::QueryResultMessage& res) { - ::config::ConfigUri uri(dir); - SearchVisitorFactory sFactory(uri); - VisitorFactory & factory(sFactory); - std::unique_ptr<Visitor> sv(static_cast<SearchVisitor *>(factory.makeVisitor(*_component, _env, params))); - document::BucketId bucketId; - Visitor::DocEntryList documents(createDocuments(dir)); - Visitor::HitCounter hitCounter; - sv->handleDocuments(bucketId, documents, hitCounter); + EXPECT_EQ(exp_hits.size(), res.getSearchResult().getHitCount()); + EXPECT_EQ(exp_hits, to_hit_vector(res.getSearchResult())); } -TEST_F(SearchVisitorTest, test_search_environment) +void +expect_summary(const HitVector& exp_summary, documentapi::QueryResultMessage& res) { - EXPECT_TRUE(_env.getVSMAdapter("simple") != nullptr); - EXPECT_TRUE(_env.getRankManager("simple") != nullptr); + EXPECT_EQ(exp_summary.size(), res.getDocumentSummary().getSummaryCount()); + EXPECT_EQ(exp_summary, to_hit_vector(res.getDocumentSummary())); } -TEST_F(SearchVisitorTest, test_search_visitor) +TEST_F(SearchVisitorTest, basic_query_execution_in_search_visitor) { - vdslib::Parameters params; - params.set("searchcluster", "aaa"); - params.set("queryflags", "0x40000"); - params.set("summarycount", "3"); - params.set("summaryclass", "petra"); - params.set("rankprofile", "default"); - - QueryBuilder<SimpleQueryNodeTypes> builder; - builder.addStringTerm("maptest", "sddocname", 0, Weight(0)); - Node::UP node = builder.build(); - vespalib::string stackDump = StackDumpCreator::create(*node); - - params.set("query", stackDump); - testCreateSearchVisitor("dir:cfg", params); + auto res = execute_query(RequestBuilder(). + number_term("[5;10]", "id").build(), + {{3},{7},{4},{5},{9}}); + expect_hits({{9,19.0}, {7,17.0}, {5,15.0}}, *res); + expect_summary({{5}, {7}, {9}}, *res); } -TEST_F(SearchVisitorTest, test_only_require_weak_read_consistency) +TEST_F(SearchVisitorTest, visitor_only_require_weak_read_consistency) { - SearchVisitorFactory factory(::config::ConfigUri("dir:cfg")); - VisitorFactory& factoryBase(factory); vdslib::Parameters params; - std::unique_ptr<Visitor> sv(factoryBase.makeVisitor(*_component, _env, params)); - EXPECT_TRUE(sv->getRequiredReadConsistency() == spi::ReadConsistency::WEAK); + auto session = make_visitor_session(params); + EXPECT_TRUE(session->visitor.getRequiredReadConsistency() == spi::ReadConsistency::WEAK); } } |