diff options
author | Håvard Pettersen <havardpe@oath.com> | 2019-03-07 09:42:31 +0000 |
---|---|---|
committer | Håvard Pettersen <havardpe@oath.com> | 2019-03-25 13:35:53 +0000 |
commit | 287b425e61cb40584991729bf2f4234d27d85cc8 (patch) | |
tree | 8ba4e95cfe3b5a212b4d422f956f88a7aee43700 /searchlib/src/tests/engine | |
parent | e957b28c666a6b0d45fc325efc11e894f7d63d94 (diff) |
initial searchprotocol implementation in cpp
Diffstat (limited to 'searchlib/src/tests/engine')
5 files changed, 707 insertions, 0 deletions
diff --git a/searchlib/src/tests/engine/proto_converter/CMakeLists.txt b/searchlib/src/tests/engine/proto_converter/CMakeLists.txt new file mode 100644 index 00000000000..718e8120c2c --- /dev/null +++ b/searchlib/src/tests/engine/proto_converter/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(searchlib_engine_proto_converter_test_app TEST + SOURCES + proto_converter_test.cpp + DEPENDS + searchlib + gtest +) +vespa_add_test(NAME searchlib_engine_proto_converter_test_app COMMAND searchlib_engine_proto_converter_test_app) diff --git a/searchlib/src/tests/engine/proto_converter/proto_converter_test.cpp b/searchlib/src/tests/engine/proto_converter/proto_converter_test.cpp new file mode 100644 index 00000000000..e38820b6e8b --- /dev/null +++ b/searchlib/src/tests/engine/proto_converter/proto_converter_test.cpp @@ -0,0 +1,543 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/vespalib/gtest/gtest.h> +#include <vespa/searchlib/engine/proto_converter.h> +#include <vespa/searchlib/common/transport.h> +#include <vespa/vespalib/data/slime/slime.h> +#include <vespa/vespalib/data/slime/binary_format.h> + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Winline" + +using Converter = ::search::engine::ProtoConverter; + +using SearchRequest = ::search::engine::SearchRequest; +using SearchReply = ::search::engine::SearchReply; + +using DocsumRequest = ::search::engine::DocsumRequest; +using DocsumReply = ::search::engine::DocsumReply; + +using MonitorRequest = ::search::engine::MonitorRequest; +using MonitorReply = ::search::engine::MonitorReply; + +using vespalib::Slime; +using vespalib::Memory; +using vespalib::slime::BinaryFormat; + +//----------------------------------------------------------------------------- + +struct SearchRequestTest : ::testing::Test { + Converter::ProtoSearchRequest proto; + SearchRequest request; + void convert() { Converter::search_request_from_proto(proto, request); } +}; + +TEST_F(SearchRequestTest, require_that_offset_is_converted) { + proto.set_offset(123); + convert(); + EXPECT_EQ(request.offset, 123); +} + +TEST_F(SearchRequestTest, require_that_hits_is_converted) { + proto.set_hits(17); + convert(); + EXPECT_EQ(request.maxhits, 17); +} + +TEST_F(SearchRequestTest, require_that_timeout_is_converted) { + proto.set_timeout(500); + convert(); + EXPECT_EQ(request.getTimeout().ms(), 500); +} + +TEST_F(SearchRequestTest, require_that_trace_level_is_converted) { + proto.set_trace_level(9); + convert(); + EXPECT_EQ(request.getTraceLevel(), 9); +} + +TEST_F(SearchRequestTest, require_that_sorting_is_converted) { + auto *sort_field = proto.add_sorting(); + sort_field->set_ascending(true); + sort_field->set_field("foo"); + sort_field = proto.add_sorting(); + sort_field->set_ascending(false); + sort_field->set_field("bar"); + convert(); + EXPECT_EQ(request.sortSpec, "+foo -bar"); +} + +TEST_F(SearchRequestTest, require_that_session_key_is_converted) { + proto.set_session_key("my-session"); + convert(); + EXPECT_EQ(std::string(&request.sessionId[0], request.sessionId.size()), "my-session"); +} + +TEST_F(SearchRequestTest, require_that_document_type_is_converted) { + proto.set_document_type("music"); + convert(); + EXPECT_EQ(request.propertiesMap.matchProperties().lookup("documentdb", "searchdoctype").get(""), "music"); +} + +TEST_F(SearchRequestTest, require_that_cache_grouping_is_converted) { + proto.set_cache_grouping(true); + convert(); + EXPECT_TRUE(request.propertiesMap.cacheProperties().lookup("grouping").found()); + EXPECT_FALSE(request.propertiesMap.cacheProperties().lookup("query").found()); +} + +TEST_F(SearchRequestTest, require_that_cache_query_is_converted) { + proto.set_cache_query(true); + convert(); + EXPECT_FALSE(request.propertiesMap.cacheProperties().lookup("grouping").found()); + EXPECT_TRUE(request.propertiesMap.cacheProperties().lookup("query").found()); +} + +TEST_F(SearchRequestTest, require_that_rank_profile_is_converted) { + proto.set_rank_profile("mlr"); + convert(); + EXPECT_EQ(request.ranking, "mlr"); +} + +TEST_F(SearchRequestTest, require_that_feature_overrides_are_converted) { + auto *prop = proto.add_feature_overrides(); + prop->set_name("foo"); + prop->add_values("a"); + prop = proto.add_feature_overrides(); + prop->set_name("bar"); + prop->add_values("b"); + prop->add_values("c"); + auto *tprop = proto.add_tensor_feature_overrides(); + tprop->set_name("x1"); + tprop->set_value("[1,2,3]"); + tprop = proto.add_tensor_feature_overrides(); + tprop->set_name("y1"); + tprop->set_value("[4,5]"); + convert(); + auto foo = request.propertiesMap.featureOverrides().lookup("foo"); + EXPECT_EQ(foo.size(), 1u); + EXPECT_EQ(foo.get(), "a"); + auto bar = request.propertiesMap.featureOverrides().lookup("bar"); + EXPECT_EQ(bar.size(), 2u); + EXPECT_EQ(bar.get(), "b"); + EXPECT_EQ(bar.getAt(1), "c"); + auto x1 = request.propertiesMap.featureOverrides().lookup("x1"); + EXPECT_EQ(x1.size(), 1u); + EXPECT_EQ(x1.get(), "[1,2,3]"); + auto y1 = request.propertiesMap.featureOverrides().lookup("y1"); + EXPECT_EQ(y1.size(), 1u); + EXPECT_EQ(y1.get(), "[4,5]"); +} + +TEST_F(SearchRequestTest, require_that_rank_properties_are_converted) { + auto *prop = proto.add_rank_properties(); + prop->set_name("foo"); + prop->add_values("a"); + prop = proto.add_rank_properties(); + prop->set_name("bar"); + prop->add_values("b"); + prop->add_values("c"); + auto *tprop = proto.add_tensor_rank_properties(); + tprop->set_name("x1"); + tprop->set_value("[1,2,3]"); + tprop = proto.add_tensor_rank_properties(); + tprop->set_name("y1"); + tprop->set_value("[4,5]"); + convert(); + auto foo = request.propertiesMap.rankProperties().lookup("foo"); + EXPECT_EQ(foo.size(), 1u); + EXPECT_EQ(foo.get(), "a"); + auto bar = request.propertiesMap.rankProperties().lookup("bar"); + EXPECT_EQ(bar.size(), 2u); + EXPECT_EQ(bar.get(), "b"); + EXPECT_EQ(bar.getAt(1), "c"); + auto x1 = request.propertiesMap.rankProperties().lookup("x1"); + EXPECT_EQ(x1.size(), 1u); + EXPECT_EQ(x1.get(), "[1,2,3]"); + auto y1 = request.propertiesMap.rankProperties().lookup("y1"); + EXPECT_EQ(y1.size(), 1u); + EXPECT_EQ(y1.get(), "[4,5]"); +} + +TEST_F(SearchRequestTest, require_that_grouping_blob_is_converted) { + proto.set_grouping_blob("grouping-blob"); + convert(); + EXPECT_EQ(std::string(&request.groupSpec[0], request.groupSpec.size()), "grouping-blob"); +} + +TEST_F(SearchRequestTest, require_that_geo_location_is_converted) { + proto.set_geo_location("x,y"); + convert(); + EXPECT_EQ(request.location, "x,y"); +} + +TEST_F(SearchRequestTest, require_that_query_tree_blob_is_converted) { + proto.set_query_tree_blob("query-tree-blob"); + convert(); + EXPECT_EQ(std::string(&request.stackDump[0], request.stackDump.size()), "query-tree-blob"); +} + +//----------------------------------------------------------------------------- + +struct SearchReplyTest : ::testing::Test { + SearchReply reply; + Converter::ProtoSearchReply proto; + void convert() { Converter::search_reply_to_proto(reply, proto); } +}; + +TEST_F(SearchReplyTest, require_that_total_hit_count_is_converted) { + reply.totalHitCount = 9001; + convert(); + EXPECT_EQ(proto.total_hit_count(), 9001); +} + +TEST_F(SearchReplyTest, require_that_coverage_docs_is_converted) { + reply.coverage.setCovered(150000); + convert(); + EXPECT_EQ(proto.coverage_docs(), 150000); +} + +TEST_F(SearchReplyTest, require_that_active_docs_is_converted) { + reply.coverage.setActive(200000); + convert(); + EXPECT_EQ(proto.active_docs(), 200000); +} + +TEST_F(SearchReplyTest, require_that_soon_active_docs_is_converted) { + reply.coverage.setSoonActive(250000); + convert(); + EXPECT_EQ(proto.soon_active_docs(), 250000); +} + +TEST_F(SearchReplyTest, require_that_degraded_by_match_phase_is_converted) { + reply.coverage.degradeMatchPhase(); + convert(); + EXPECT_TRUE(proto.degraded_by_match_phase()); + EXPECT_FALSE(proto.degraded_by_soft_timeout()); +} + +TEST_F(SearchReplyTest, require_that_degraded_by_soft_timeout_is_converted) { + reply.coverage.degradeTimeout(); + convert(); + EXPECT_FALSE(proto.degraded_by_match_phase()); + EXPECT_TRUE(proto.degraded_by_soft_timeout()); +} + +TEST_F(SearchReplyTest, require_that_multiple_degraded_reasons_are_converted) { + reply.coverage.degradeMatchPhase(); + reply.coverage.degradeTimeout(); + convert(); + EXPECT_TRUE(proto.degraded_by_match_phase()); + EXPECT_TRUE(proto.degraded_by_soft_timeout()); +} + +TEST_F(SearchReplyTest, require_that_hits_are_converted) { + constexpr size_t len = document::GlobalId::LENGTH; + ASSERT_EQ(len, 12); + char id0[len] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12}; + char id1[len] = {11,12,13,14,15,16,17,18,19,20,21,22}; + char id2[len] = {21,22,23,24,25,26,27,28,29,30,31,32}; + reply.hits.resize(3); + reply.hits[0].gid = document::GlobalId(id0); + reply.hits[0].metric = 100.0; + reply.hits[1].gid = document::GlobalId(id1); + reply.hits[1].metric = 50.0; + reply.hits[2].gid = document::GlobalId(id2); + reply.hits[2].metric = 10.0; + convert(); + ASSERT_EQ(proto.hits_size(), 3); + EXPECT_EQ(proto.hits(0).global_id(), std::string(id0, len)); + EXPECT_EQ(proto.hits(0).relevance(), 100.0); + EXPECT_TRUE(proto.hits(0).sort_data().empty()); + EXPECT_EQ(proto.hits(1).global_id(), std::string(id1, len)); + EXPECT_EQ(proto.hits(1).relevance(), 50.0); + EXPECT_TRUE(proto.hits(1).sort_data().empty()); + EXPECT_EQ(proto.hits(2).global_id(), std::string(id2, len)); + EXPECT_EQ(proto.hits(2).relevance(), 10.0); + EXPECT_TRUE(proto.hits(2).sort_data().empty()); +} + +TEST_F(SearchReplyTest, require_that_hits_with_sort_data_are_converted) { + constexpr size_t len = document::GlobalId::LENGTH; + ASSERT_EQ(len, 12); + char id0[len] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12}; + char id1[len] = {11,12,13,14,15,16,17,18,19,20,21,22}; + char id2[len] = {21,22,23,24,25,26,27,28,29,30,31,32}; + reply.hits.resize(3); + reply.hits[0].gid = document::GlobalId(id0); + reply.hits[0].metric = 100.0; + reply.hits[1].gid = document::GlobalId(id1); + reply.hits[1].metric = 50.0; + reply.hits[2].gid = document::GlobalId(id2); + reply.hits[2].metric = 10.0; + vespalib::string sort_data("fooxybar"); + reply.sortData.assign(sort_data.begin(), sort_data.end()); + reply.sortIndex.push_back(0); + reply.sortIndex.push_back(3); // hit1: 'foo' + reply.sortIndex.push_back(5); // hit2: 'xy' + reply.sortIndex.push_back(8); // hit3: 'bar' + convert(); + ASSERT_EQ(proto.hits_size(), 3); + EXPECT_EQ(proto.hits(0).global_id(), std::string(id0, len)); + EXPECT_EQ(proto.hits(0).relevance(), 100.0); + EXPECT_EQ(proto.hits(0).sort_data(), "foo"); + EXPECT_EQ(proto.hits(1).global_id(), std::string(id1, len)); + EXPECT_EQ(proto.hits(1).relevance(), 50.0); + EXPECT_EQ(proto.hits(1).sort_data(), "xy"); + EXPECT_EQ(proto.hits(2).global_id(), std::string(id2, len)); + EXPECT_EQ(proto.hits(2).relevance(), 10.0); + EXPECT_EQ(proto.hits(2).sort_data(), "bar"); +} + +TEST_F(SearchReplyTest, require_that_grouping_blob_is_converted) { + vespalib::string tmp("grouping-result"); + reply.groupResult.assign(tmp.begin(), tmp.end()); + convert(); + EXPECT_EQ(proto.grouping_blob(), "grouping-result"); +} + +TEST_F(SearchReplyTest, require_that_slime_trace_is_converted) { + reply.propertiesMap.lookupCreate("trace").add("slime", "slime-trace"); + convert(); + EXPECT_EQ(proto.slime_trace(), "slime-trace"); +} + +//----------------------------------------------------------------------------- + +struct DocsumRequestTest : ::testing::Test { + Converter::ProtoDocsumRequest proto; + DocsumRequest request; + DocsumRequestTest() : proto(), request(true) {} // <- use root slime + void convert() { Converter::docsum_request_from_proto(proto, request); } +}; + +TEST_F(DocsumRequestTest, require_that_root_slime_is_used) { + EXPECT_TRUE(request.useRootSlime()); +} + +TEST_F(DocsumRequestTest, require_that_timeout_is_converted) { + proto.set_timeout(500); + convert(); + EXPECT_EQ(request.getTimeout().ms(), 500); +} + +TEST_F(DocsumRequestTest, require_that_session_key_is_converted) { + proto.set_session_key("my-session"); + convert(); + EXPECT_EQ(std::string(&request.sessionId[0], request.sessionId.size()), "my-session"); +} + +TEST_F(DocsumRequestTest, require_that_document_type_is_converted) { + proto.set_document_type("music"); + convert(); + EXPECT_EQ(request.propertiesMap.matchProperties().lookup("documentdb", "searchdoctype").get(""), "music"); +} + +TEST_F(DocsumRequestTest, require_that_summary_class_is_converted) { + proto.set_summary_class("prefetch"); + convert(); + EXPECT_EQ(request.resultClassName, "prefetch"); +} + +TEST_F(DocsumRequestTest, require_that_cache_query_is_converted) { + proto.set_cache_query(true); + convert(); + EXPECT_TRUE(request.propertiesMap.cacheProperties().lookup("query").found()); + EXPECT_FALSE((request.queryFlags & search::fs4transport::QFLAG_DUMP_FEATURES) != 0); +} + +TEST_F(DocsumRequestTest, require_that_dump_features_is_converted) { + proto.set_dump_features(true); + convert(); + EXPECT_FALSE(request.propertiesMap.cacheProperties().lookup("query").found()); + EXPECT_TRUE((request.queryFlags & search::fs4transport::QFLAG_DUMP_FEATURES) != 0); +} + +TEST_F(DocsumRequestTest, require_that_rank_profile_is_converted) { + proto.set_rank_profile("mlr"); + convert(); + EXPECT_EQ(request.ranking, "mlr"); +} + +TEST_F(DocsumRequestTest, require_that_feature_overrides_are_converted) { + auto *prop = proto.add_feature_overrides(); + prop->set_name("foo"); + prop->add_values("a"); + prop = proto.add_feature_overrides(); + prop->set_name("bar"); + prop->add_values("b"); + prop->add_values("c"); + auto *tprop = proto.add_tensor_feature_overrides(); + tprop->set_name("x1"); + tprop->set_value("[1,2,3]"); + tprop = proto.add_tensor_feature_overrides(); + tprop->set_name("y1"); + tprop->set_value("[4,5]"); + convert(); + auto foo = request.propertiesMap.featureOverrides().lookup("foo"); + EXPECT_EQ(foo.size(), 1u); + EXPECT_EQ(foo.get(), "a"); + auto bar = request.propertiesMap.featureOverrides().lookup("bar"); + EXPECT_EQ(bar.size(), 2u); + EXPECT_EQ(bar.get(), "b"); + EXPECT_EQ(bar.getAt(1), "c"); + auto x1 = request.propertiesMap.featureOverrides().lookup("x1"); + EXPECT_EQ(x1.size(), 1u); + EXPECT_EQ(x1.get(), "[1,2,3]"); + auto y1 = request.propertiesMap.featureOverrides().lookup("y1"); + EXPECT_EQ(y1.size(), 1u); + EXPECT_EQ(y1.get(), "[4,5]"); +} + +TEST_F(DocsumRequestTest, require_that_rank_properties_are_converted) { + auto *prop = proto.add_rank_properties(); + prop->set_name("foo"); + prop->add_values("a"); + prop = proto.add_rank_properties(); + prop->set_name("bar"); + prop->add_values("b"); + prop->add_values("c"); + auto *tprop = proto.add_tensor_rank_properties(); + tprop->set_name("x1"); + tprop->set_value("[1,2,3]"); + tprop = proto.add_tensor_rank_properties(); + tprop->set_name("y1"); + tprop->set_value("[4,5]"); + convert(); + auto foo = request.propertiesMap.rankProperties().lookup("foo"); + EXPECT_EQ(foo.size(), 1u); + EXPECT_EQ(foo.get(), "a"); + auto bar = request.propertiesMap.rankProperties().lookup("bar"); + EXPECT_EQ(bar.size(), 2u); + EXPECT_EQ(bar.get(), "b"); + EXPECT_EQ(bar.getAt(1), "c"); + auto x1 = request.propertiesMap.rankProperties().lookup("x1"); + EXPECT_EQ(x1.size(), 1u); + EXPECT_EQ(x1.get(), "[1,2,3]"); + auto y1 = request.propertiesMap.rankProperties().lookup("y1"); + EXPECT_EQ(y1.size(), 1u); + EXPECT_EQ(y1.get(), "[4,5]"); +} + +TEST_F(DocsumRequestTest, require_that_highlight_terms_are_converted) { + auto *prop = proto.add_highlight_terms(); + prop->set_name("foo"); + prop->add_values("a"); + prop = proto.add_highlight_terms(); + prop->set_name("bar"); + prop->add_values("b"); + prop->add_values("c"); + convert(); + auto foo = request.propertiesMap.highlightTerms().lookup("foo"); + EXPECT_EQ(foo.size(), 1u); + EXPECT_EQ(foo.get(), "a"); + auto bar = request.propertiesMap.highlightTerms().lookup("bar"); + EXPECT_EQ(bar.size(), 2u); + EXPECT_EQ(bar.get(), "b"); + EXPECT_EQ(bar.getAt(1), "c"); +} + +TEST_F(DocsumRequestTest, require_that_geo_location_is_converted) { + proto.set_geo_location("x,y"); + convert(); + EXPECT_EQ(request.location, "x,y"); +} + +TEST_F(DocsumRequestTest, require_that_query_tree_blob_is_converted) { + proto.set_query_tree_blob("query-tree-blob"); + convert(); + EXPECT_EQ(std::string(&request.stackDump[0], request.stackDump.size()), "query-tree-blob"); +} + +TEST_F(DocsumRequestTest, require_that_global_ids_are_converted) { + constexpr size_t len = document::GlobalId::LENGTH; + ASSERT_EQ(len, 12); + char id0[len] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12}; + char id1[len] = {11,12,13,14,15,16,17,18,19,20,21,22}; + char id2[len] = {21,22,23,24,25,26,27,28,29,30,31,32}; + proto.add_global_ids(id0, len); + proto.add_global_ids(id1, len); + proto.add_global_ids(id2, len); + convert(); + ASSERT_EQ(request.hits.size(), 3); + EXPECT_EQ(request.hits[0].gid, document::GlobalId(id0)); + EXPECT_EQ(request.hits[1].gid, document::GlobalId(id1)); + EXPECT_EQ(request.hits[2].gid, document::GlobalId(id2)); +} + +//----------------------------------------------------------------------------- + +struct DocsumReplyTest : ::testing::Test { + DocsumReply reply; + Converter::ProtoDocsumReply proto; + void convert() { Converter::docsum_reply_to_proto(reply, proto); } +}; + +TEST_F(DocsumReplyTest, require_that_slime_summaries_are_converted) { + reply._root = std::make_unique<Slime>(); + auto &list = reply._root->setArray(); + auto &doc0 = list.addObject(); + doc0.setLong("my_field", 42); + convert(); + const auto &mem = proto.slime_summaries(); + Slime slime; + EXPECT_EQ(BinaryFormat::decode(Memory(mem.data(), mem.size()), slime), mem.size()); + EXPECT_EQ(slime.get()[0]["my_field"].asLong(), 42); +} + +TEST_F(DocsumReplyTest, require_that_missing_root_slime_gives_empty_payload) { + reply._root.reset(); + convert(); + EXPECT_EQ(proto.slime_summaries().size(), 0); +} + +//----------------------------------------------------------------------------- + +struct MonitorRequestTest : ::testing::Test { + Converter::ProtoMonitorRequest proto; + MonitorRequest request; + void convert() { Converter::monitor_request_from_proto(proto, request); } +}; + +TEST_F(MonitorRequestTest, require_that_active_docs_are_always_requested) { + convert(); + EXPECT_TRUE(request.reportActiveDocs); +} + +//----------------------------------------------------------------------------- + +struct MonitorReplyTest : ::testing::Test { + MonitorReply reply; + Converter::ProtoMonitorReply proto; + void convert() { Converter::monitor_reply_to_proto(reply, proto); } +}; + +TEST_F(MonitorReplyTest, require_that_zero_timestamp_is_converted_to_online_false) { + reply.timestamp = 0; + convert(); + EXPECT_FALSE(proto.online()); +} + +TEST_F(MonitorReplyTest, require_that_nonzero_timestamp_is_converted_to_online_true) { + reply.timestamp = 42; + convert(); + EXPECT_TRUE(proto.online()); +} + +TEST_F(MonitorReplyTest, require_that_active_docs_is_converted) { + reply.activeDocs = 12345; + convert(); + EXPECT_EQ(proto.active_docs(), 12345); +} + +TEST_F(MonitorReplyTest, require_that_distribution_key_is_converted) { + reply.distribution_key = 7; + convert(); + EXPECT_EQ(proto.distribution_key(), 7); +} + +//----------------------------------------------------------------------------- + +GTEST_MAIN_RUN_ALL_TESTS() + +#pragma GCC diagnostic pop diff --git a/searchlib/src/tests/engine/proto_rpc_adapter/CMakeLists.txt b/searchlib/src/tests/engine/proto_rpc_adapter/CMakeLists.txt new file mode 100644 index 00000000000..3fa638f16e5 --- /dev/null +++ b/searchlib/src/tests/engine/proto_rpc_adapter/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(searchlib_engine_proto_rpc_adapter_test_app TEST + SOURCES + proto_rpc_adapter_test.cpp + DEPENDS + searchlib + gtest +) +vespa_add_test(NAME searchlib_engine_proto_rpc_adapter_test_app COMMAND searchlib_engine_proto_rpc_adapter_test_app) diff --git a/searchlib/src/tests/engine/proto_rpc_adapter/proto_rpc_adapter_test.cpp b/searchlib/src/tests/engine/proto_rpc_adapter/proto_rpc_adapter_test.cpp new file mode 100644 index 00000000000..60cf1af13a0 --- /dev/null +++ b/searchlib/src/tests/engine/proto_rpc_adapter/proto_rpc_adapter_test.cpp @@ -0,0 +1,145 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/vespalib/gtest/gtest.h> +#include <vespa/searchlib/engine/search_protocol_proto.h> +#include <vespa/searchlib/engine/proto_rpc_adapter.h> +#include <vespa/searchlib/engine/searchapi.h> +#include <vespa/searchlib/engine/docsumapi.h> +#include <vespa/searchlib/engine/monitorapi.h> +#include <vespa/fnet/frt/frt.h> +#include <vespa/vespalib/data/slime/slime.h> +#include <vespa/vespalib/data/slime/binary_format.h> + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Winline" + +using namespace search::engine; + +using vespalib::Slime; +using vespalib::Memory; +using vespalib::slime::BinaryFormat; + +using ProtoSearchRequest = ProtoRpcAdapter::ProtoSearchRequest; +using ProtoSearchReply = ProtoRpcAdapter::ProtoSearchReply; +using ProtoDocsumRequest = ProtoRpcAdapter::ProtoDocsumRequest; +using ProtoDocsumReply = ProtoRpcAdapter::ProtoDocsumReply; +using ProtoMonitorRequest = ProtoRpcAdapter::ProtoMonitorRequest; +using ProtoMonitorReply = ProtoRpcAdapter::ProtoMonitorReply; + +struct MySearchServer : SearchServer { + SearchReply::UP search(SearchRequest::Source src, SearchClient &client) override { + auto req = src.release(); + assert(req); + auto reply = std::make_unique<SearchReply>(); + reply->totalHitCount = req->offset; // simplified search implementation + client.searchDone(std::move(reply)); // simplified async response + return std::unique_ptr<SearchReply>(); + } +}; + +struct MyDocsumServer : DocsumServer { + DocsumReply::UP getDocsums(DocsumRequest::Source src, DocsumClient &client) override { + auto req = src.release(); + assert(req); + auto reply = std::make_unique<DocsumReply>(); + reply->_root = std::make_unique<Slime>(); + auto &list = reply->_root->setArray(); + list.addObject().setBool("use_root_slime", req->useRootSlime()); + list.addObject().setString("ranking", req->ranking); + client.getDocsumsDone(std::move(reply)); // simplified async response + return std::unique_ptr<DocsumReply>(); + } +}; + +struct MyMonitorServer : MonitorServer { + MonitorReply::UP ping(MonitorRequest::UP req, MonitorClient &) override { + (void) req; + assert(req); + auto reply = std::make_unique<MonitorReply>(); + reply->activeDocs = 53; + return reply; // proton does sync response here + } +}; + +struct ProtoRpcAdapterTest : ::testing::Test { + FRT_Supervisor orb; + MySearchServer search; + MyDocsumServer docsum; + MyMonitorServer monitor; + ProtoRpcAdapter adapter; + ProtoRpcAdapterTest() + : orb(), adapter(search, docsum, monitor, orb) + { + orb.Listen(0); + orb.Start(); + } + FRT_Target *connect() { + return orb.GetTarget(orb.GetListenPort()); + } + ~ProtoRpcAdapterTest() { + orb.ShutDown(true); + } +}; + +//----------------------------------------------------------------------------- + +TEST_F(ProtoRpcAdapterTest, require_that_plain_rpc_ping_works) { + auto target = connect(); + auto *req = new FRT_RPCRequest(); + req->SetMethodName("frt.rpc.ping"); + target->InvokeSync(req, 60.0); + EXPECT_TRUE(req->CheckReturnTypes("")); + req->SubRef(); + target->SubRef(); +} + +TEST_F(ProtoRpcAdapterTest, require_that_proto_rpc_search_works) { + auto target = connect(); + auto *rpc = new FRT_RPCRequest(); + ProtoSearchRequest req; + req.set_offset(42); + ProtoRpcAdapter::encode_search_request(req, *rpc); + target->InvokeSync(rpc, 60.0); + ProtoSearchReply reply; + EXPECT_TRUE(ProtoRpcAdapter::decode_search_reply(*rpc, reply)); + EXPECT_EQ(reply.total_hit_count(), 42); + rpc->SubRef(); + target->SubRef(); +} + +TEST_F(ProtoRpcAdapterTest, require_that_proto_rpc_getDocsums_works) { + auto target = connect(); + auto *rpc = new FRT_RPCRequest(); + ProtoDocsumRequest req; + req.set_rank_profile("mlr"); + ProtoRpcAdapter::encode_docsum_request(req, *rpc); + target->InvokeSync(rpc, 60.0); + ProtoDocsumReply reply; + EXPECT_TRUE(ProtoRpcAdapter::decode_docsum_reply(*rpc, reply)); + const auto &mem = reply.slime_summaries(); + Slime slime; + EXPECT_EQ(BinaryFormat::decode(Memory(mem.data(), mem.size()), slime), mem.size()); + EXPECT_EQ(slime.get()[0]["use_root_slime"].asBool(), true); + EXPECT_EQ(slime.get()[1]["ranking"].asString().make_string(), "mlr"); + rpc->SubRef(); + target->SubRef(); +} + +TEST_F(ProtoRpcAdapterTest, require_that_proto_rpc_ping_works) { + auto target = connect(); + auto *rpc = new FRT_RPCRequest(); + ProtoMonitorRequest req; + ProtoRpcAdapter::encode_monitor_request(req, *rpc); + target->InvokeSync(rpc, 60.0); + ProtoMonitorReply reply; + EXPECT_TRUE(ProtoRpcAdapter::decode_monitor_reply(*rpc, reply)); + EXPECT_EQ(reply.active_docs(), 53); + rpc->SubRef(); + target->SubRef(); +} + +//----------------------------------------------------------------------------- + +GTEST_MAIN_RUN_ALL_TESTS() + +#pragma GCC diagnostic pop diff --git a/searchlib/src/tests/engine/searchapi/searchapi_test.cpp b/searchlib/src/tests/engine/searchapi/searchapi_test.cpp index ed103bf501c..99d1967b0df 100644 --- a/searchlib/src/tests/engine/searchapi/searchapi_test.cpp +++ b/searchlib/src/tests/engine/searchapi/searchapi_test.cpp @@ -37,6 +37,7 @@ TEST("propertyNames") { EXPECT_EQUAL(search::MapNames::HIGHLIGHTTERMS, "highlightterms"); EXPECT_EQUAL(search::MapNames::MATCH, "match"); EXPECT_EQUAL(search::MapNames::CACHES, "caches"); + EXPECT_EQUAL(search::MapNames::TRACE, "trace"); } TEST("convertToReques") { |