summaryrefslogtreecommitdiffstats
path: root/slobrok/src/tests/local_rpc_monitor_map/local_rpc_monitor_map_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'slobrok/src/tests/local_rpc_monitor_map/local_rpc_monitor_map_test.cpp')
-rw-r--r--slobrok/src/tests/local_rpc_monitor_map/local_rpc_monitor_map_test.cpp331
1 files changed, 331 insertions, 0 deletions
diff --git a/slobrok/src/tests/local_rpc_monitor_map/local_rpc_monitor_map_test.cpp b/slobrok/src/tests/local_rpc_monitor_map/local_rpc_monitor_map_test.cpp
new file mode 100644
index 00000000000..9782f6ccbdc
--- /dev/null
+++ b/slobrok/src/tests/local_rpc_monitor_map/local_rpc_monitor_map_test.cpp
@@ -0,0 +1,331 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/gtest/gtest.h>
+#include <vespa/slobrok/server/local_rpc_monitor_map.h>
+#include <vespa/vespalib/util/stringfmt.h>
+#include <vespa/vespalib/util/time.h>
+#include <vespa/fnet/scheduler.h>
+#include <map>
+
+using namespace vespalib;
+using namespace slobrok;
+using vespalib::make_string_short::fmt;
+
+struct MapCall {
+ vespalib::string name;
+ ServiceMapping mapping;
+ ServiceMapping old;
+ static MapCall add(const ServiceMapping &m) { return {"add", m, {"",""}}; }
+ static MapCall remove(const ServiceMapping &m) { return {"remove", m, {"",""}}; }
+ static MapCall update(const ServiceMapping &o, const ServiceMapping &m) { return {"update", m, o}; }
+ void check(const MapCall &rhs) const {
+ EXPECT_EQ(name, rhs.name);
+ EXPECT_EQ(mapping, rhs.mapping);
+ EXPECT_EQ(old, rhs.old);
+ }
+ ~MapCall();
+};
+MapCall::~MapCall() = default;
+
+struct MonitorCall {
+ vespalib::string name;
+ ServiceMapping mapping;
+ bool hurry;
+ static MonitorCall start(const ServiceMapping &m, bool h) { return {"start", m, h}; }
+ static MonitorCall stop(const ServiceMapping &m) { return {"stop", m, false}; }
+ void check(const MonitorCall &rhs) const {
+ EXPECT_EQ(name, rhs.name);
+ EXPECT_EQ(mapping, rhs.mapping);
+ EXPECT_EQ(hurry, rhs.hurry);
+ }
+ ~MonitorCall();
+};
+MonitorCall::~MonitorCall() = default;
+
+template <typename Call>
+class CallLog {
+private:
+ std::vector<Call> _calls;
+ size_t _checked;
+public:
+ CallLog() noexcept : _calls(), _checked(0) {}
+ ~CallLog() { EXPECT_EQ(_calls.size(), _checked); }
+ void log(Call call) { _calls.push_back(call); }
+ void expect(std::initializer_list<Call> list) {
+ ASSERT_EQ(list.size(), (_calls.size() - _checked));
+ for (const auto &call: list) {
+ call.check(_calls[_checked++]);
+ }
+ }
+};
+
+struct MapLog : CallLog<MapCall>, MapListener {
+ void add(const ServiceMapping &mapping) override {
+ log(MapCall::add(mapping));
+ }
+ void remove(const ServiceMapping &mapping) override {
+ log(MapCall::remove(mapping));
+ }
+ void update(const ServiceMapping &old_mapping,
+ const ServiceMapping &new_mapping) override
+ {
+ log(MapCall::update(old_mapping, new_mapping));
+ }
+};
+
+struct MonitorLog : CallLog<MonitorCall>, MappingMonitor {
+ void start(const ServiceMapping& mapping, bool hurry) override {
+ log(MonitorCall::start(mapping, hurry));
+ }
+ void stop(const ServiceMapping& mapping) override {
+ log(MonitorCall::stop(mapping));
+ }
+};
+
+struct MyMappingMonitor : MappingMonitor {
+ MonitorLog &monitor;
+ MyMappingMonitor(MonitorLog &m) : monitor(m) {}
+ void start(const ServiceMapping& mapping, bool hurry) override {
+ monitor.start(mapping, hurry);
+ }
+ void stop(const ServiceMapping& mapping) override {
+ monitor.stop(mapping);
+ }
+};
+
+struct LocalRpcMonitorMapTest : public ::testing::Test {
+ steady_time time;
+ FNET_Scheduler scheduler;
+ MonitorLog monitor_log;
+ MapLog map_log;
+ LocalRpcMonitorMap map;
+ std::unique_ptr<MapSubscription> subscription;
+ ServiceMapping mapping;
+ ServiceMapping mapping_conflict;
+ LocalRpcMonitorMapTest()
+ : time(duration::zero()),
+ scheduler(&time, &time), monitor_log(), map_log(),
+ map(&scheduler, [this](auto &owner)
+ {
+ EXPECT_EQ(&owner, &map);
+ return std::make_unique<MyMappingMonitor>(monitor_log);
+ }),
+ subscription(MapSubscription::subscribe(map.dispatcher(), map_log)),
+ mapping("dummy_service", "dummy_spec"),
+ mapping_conflict("dummy_service", "conflicting_dummy_spec")
+ {}
+ void tick(duration elapsed = FNET_Scheduler::tick_ms) {
+ time += elapsed;
+ scheduler.CheckTasks();
+ }
+ void add_mapping(const ServiceMapping &m, bool is_up) {
+ map.add(m); // <- add from consensus map
+ monitor_log.expect({});
+ tick(0ms); // <- process delayed add event
+ monitor_log.expect({MonitorCall::start(m, false)});
+ map_log.expect({});
+ if (is_up) {
+ map.up(m); // <- up from monitor
+ map_log.expect({MapCall::add(m)});
+ } else {
+ map.down(m); // <- down from monitor
+ map_log.expect({});
+ }
+ }
+ void flip_up_state(const ServiceMapping &m, bool was_up, size_t cnt) {
+ for (size_t i = 0; i < cnt; ++i) {
+ if (was_up) {
+ map.up(m);
+ map_log.expect({});
+ map.down(m);
+ map_log.expect({MapCall::remove(m)});
+ } else {
+ map.down(m);
+ map_log.expect({});
+ map.up(m);
+ map_log.expect({MapCall::add(m)});
+ }
+ was_up = !was_up;
+ }
+ monitor_log.expect({});
+ }
+ void remove_mapping(const ServiceMapping &m, bool was_up) {
+ map.remove(m); // <- remove from consensus map
+ monitor_log.expect({});
+ tick(0ms); // <- process delayed remove event
+ monitor_log.expect({MonitorCall::stop(m)});
+ if (was_up) {
+ map_log.expect({MapCall::remove(m)});
+ } else {
+ map_log.expect({});
+ }
+ }
+ ~LocalRpcMonitorMapTest();
+};
+LocalRpcMonitorMapTest::~LocalRpcMonitorMapTest() = default;
+
+struct MyAddLocalHandler : LocalRpcMonitorMap::AddLocalCompletionHandler {
+ std::unique_ptr<OkState> &state;
+ bool &handler_deleted;
+ MyAddLocalHandler(std::unique_ptr<OkState> &s, bool &hd)
+ : state(s), handler_deleted(hd) {}
+ void doneHandler(OkState result) override {
+ state = std::make_unique<OkState>(result);
+ }
+ ~MyAddLocalHandler() override {
+ handler_deleted = true;
+ }
+};
+
+TEST_F(LocalRpcMonitorMapTest, external_add_remove_while_up) {
+ add_mapping(mapping, true);
+ remove_mapping(mapping, true);
+}
+
+TEST_F(LocalRpcMonitorMapTest, external_add_remove_while_down) {
+ add_mapping(mapping, false);
+ remove_mapping(mapping, false);
+}
+
+TEST_F(LocalRpcMonitorMapTest, server_up_down_up_down) {
+ add_mapping(mapping, true);
+ flip_up_state(mapping, true, 3);
+ remove_mapping(mapping, false);
+}
+
+TEST_F(LocalRpcMonitorMapTest, server_down_up_down_up) {
+ add_mapping(mapping, false);
+ flip_up_state(mapping, false, 3);
+ remove_mapping(mapping, true);
+}
+
+TEST_F(LocalRpcMonitorMapTest, multi_mapping) {
+ ServiceMapping m1("dummy_service1", "dummy_spec1");
+ ServiceMapping m2("dummy_service2", "dummy_spec2");
+ ServiceMapping m3("dummy_service3", "dummy_spec3");
+ add_mapping(m1, true);
+ add_mapping(m2, false);
+ add_mapping(m3, true);
+ flip_up_state(m1, true, 3);
+ flip_up_state(m2, false, 3);
+ flip_up_state(m3, true, 3);
+ remove_mapping(m1, false);
+ remove_mapping(m2, true);
+ remove_mapping(m3, false);
+}
+
+TEST_F(LocalRpcMonitorMapTest, local_add_ok) {
+ std::unique_ptr<OkState> state;
+ bool handler_deleted;
+ map.addLocal(mapping, std::make_unique<MyAddLocalHandler>(state, handler_deleted));
+ monitor_log.expect({MonitorCall::start(mapping, true)});
+ map_log.expect({});
+ map.up(mapping);
+ monitor_log.expect({});
+ map_log.expect({MapCall::add(mapping)});
+ ASSERT_TRUE(state);
+ EXPECT_TRUE(state->ok());
+ ASSERT_TRUE(handler_deleted);
+}
+
+TEST_F(LocalRpcMonitorMapTest, local_add_already_up) {
+ std::unique_ptr<OkState> state;
+ bool handler_deleted;
+ add_mapping(mapping, true);
+ map.addLocal(mapping, std::make_unique<MyAddLocalHandler>(state, handler_deleted));
+ monitor_log.expect({});
+ map_log.expect({});
+ ASSERT_TRUE(state);
+ EXPECT_TRUE(state->ok());
+ ASSERT_TRUE(handler_deleted);
+}
+
+TEST_F(LocalRpcMonitorMapTest, local_add_unknown_comes_up) {
+ std::unique_ptr<OkState> state;
+ bool handler_deleted;
+ add_mapping(mapping, false);
+ map.addLocal(mapping, std::make_unique<MyAddLocalHandler>(state, handler_deleted));
+ monitor_log.expect({MonitorCall::stop(mapping), MonitorCall::start(mapping, true)});
+ map_log.expect({});
+ EXPECT_FALSE(state);
+ map.up(mapping);
+ map_log.expect({MapCall::add(mapping)});
+ ASSERT_TRUE(state);
+ EXPECT_TRUE(state->ok());
+ ASSERT_TRUE(handler_deleted);
+}
+
+TEST_F(LocalRpcMonitorMapTest, local_add_unknown_goes_down) {
+ std::unique_ptr<OkState> state;
+ bool handler_deleted;
+ add_mapping(mapping, false);
+ map.addLocal(mapping, std::make_unique<MyAddLocalHandler>(state, handler_deleted));
+ monitor_log.expect({MonitorCall::stop(mapping), MonitorCall::start(mapping, true)});
+ map_log.expect({});
+ EXPECT_FALSE(state);
+ map.down(mapping);
+ map_log.expect({});
+ ASSERT_TRUE(state);
+ EXPECT_FALSE(state->ok());
+ ASSERT_TRUE(handler_deleted);
+}
+
+TEST_F(LocalRpcMonitorMapTest, local_add_conflict) {
+ std::unique_ptr<OkState> state;
+ bool handler_deleted;
+ add_mapping(mapping, true);
+ map.addLocal(mapping_conflict, std::make_unique<MyAddLocalHandler>(state, handler_deleted));
+ monitor_log.expect({});
+ map_log.expect({});
+ ASSERT_TRUE(state);
+ EXPECT_TRUE(state->failed());
+ ASSERT_TRUE(handler_deleted);
+}
+
+TEST_F(LocalRpcMonitorMapTest, local_multi_add) {
+ std::unique_ptr<OkState> state1;
+ bool handler_deleted1;
+ std::unique_ptr<OkState> state2;
+ bool handler_deleted2;
+ map.addLocal(mapping, std::make_unique<MyAddLocalHandler>(state1, handler_deleted1));
+ monitor_log.expect({MonitorCall::start(mapping, true)});
+ map.addLocal(mapping, std::make_unique<MyAddLocalHandler>(state2, handler_deleted2));
+ monitor_log.expect({});
+ map_log.expect({});
+ EXPECT_FALSE(state1);
+ EXPECT_FALSE(state2);
+ map.up(mapping);
+ monitor_log.expect({});
+ map_log.expect({MapCall::add(mapping)});
+ ASSERT_TRUE(state1);
+ ASSERT_TRUE(state2);
+ EXPECT_TRUE(state1->ok());
+ EXPECT_TRUE(state2->ok());
+ ASSERT_TRUE(handler_deleted1);
+ ASSERT_TRUE(handler_deleted2);
+}
+
+TEST_F(LocalRpcMonitorMapTest, local_remove) {
+ add_mapping(mapping, true);
+ map.removeLocal(mapping);
+ monitor_log.expect({MonitorCall::stop(mapping), MonitorCall::start(mapping, false)});
+ map_log.expect({MapCall::remove(mapping)});
+ map.up(mapping); // timeout case (should normally not happen)
+ map_log.expect({MapCall::add(mapping)});
+}
+
+TEST_F(LocalRpcMonitorMapTest, local_add_local_remove) {
+ std::unique_ptr<OkState> state;
+ bool handler_deleted;
+ map.addLocal(mapping, std::make_unique<MyAddLocalHandler>(state, handler_deleted));
+ monitor_log.expect({MonitorCall::start(mapping, true)});
+ map_log.expect({});
+ map.removeLocal(mapping);
+ monitor_log.expect({MonitorCall::stop(mapping)});
+ map_log.expect({});
+ ASSERT_TRUE(state);
+ EXPECT_TRUE(state->failed());
+ ASSERT_TRUE(handler_deleted);
+}
+
+GTEST_MAIN_RUN_ALL_TESTS()