mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-21 01:01:43 +00:00
317 lines
10 KiB
C++
317 lines
10 KiB
C++
|
|
/*----------------------------------------------------------------------------*/
|
||
|
|
/* Copyright (c) FIRST 2017. All Rights Reserved. */
|
||
|
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||
|
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||
|
|
/* the project. */
|
||
|
|
/*----------------------------------------------------------------------------*/
|
||
|
|
|
||
|
|
#include "EntryNotifier.h"
|
||
|
|
|
||
|
|
#include "gtest/gtest.h"
|
||
|
|
|
||
|
|
#include "support/Logger.h"
|
||
|
|
|
||
|
|
#include "TestPrinters.h"
|
||
|
|
#include "ValueMatcher.h"
|
||
|
|
|
||
|
|
using ::testing::_;
|
||
|
|
using ::testing::AnyNumber;
|
||
|
|
using ::testing::IsNull;
|
||
|
|
using ::testing::Return;
|
||
|
|
|
||
|
|
namespace nt {
|
||
|
|
|
||
|
|
class EntryNotifierTest : public ::testing::Test {
|
||
|
|
public:
|
||
|
|
EntryNotifierTest() : notifier(1, logger) { notifier.Start(); }
|
||
|
|
|
||
|
|
void GenerateNotifications();
|
||
|
|
|
||
|
|
protected:
|
||
|
|
wpi::Logger logger;
|
||
|
|
EntryNotifier notifier;
|
||
|
|
};
|
||
|
|
|
||
|
|
void EntryNotifierTest::GenerateNotifications() {
|
||
|
|
// All flags combos that can be generated by Storage
|
||
|
|
static const unsigned int flags[] = {
|
||
|
|
// "normal" notifications
|
||
|
|
NT_NOTIFY_NEW, NT_NOTIFY_DELETE, NT_NOTIFY_UPDATE, NT_NOTIFY_FLAGS,
|
||
|
|
NT_NOTIFY_UPDATE | NT_NOTIFY_FLAGS,
|
||
|
|
// immediate notifications are always "new"
|
||
|
|
NT_NOTIFY_IMMEDIATE | NT_NOTIFY_NEW,
|
||
|
|
// local notifications can be of any flag combo
|
||
|
|
NT_NOTIFY_LOCAL | NT_NOTIFY_NEW, NT_NOTIFY_LOCAL | NT_NOTIFY_DELETE,
|
||
|
|
NT_NOTIFY_LOCAL | NT_NOTIFY_UPDATE, NT_NOTIFY_LOCAL | NT_NOTIFY_FLAGS,
|
||
|
|
NT_NOTIFY_LOCAL | NT_NOTIFY_UPDATE | NT_NOTIFY_FLAGS};
|
||
|
|
// Generate across keys
|
||
|
|
static const char* keys[] = {"/foo/bar", "/baz", "/boo"};
|
||
|
|
|
||
|
|
auto val = Value::MakeDouble(1);
|
||
|
|
|
||
|
|
// Provide unique key indexes for each key
|
||
|
|
unsigned int keyindex = 5;
|
||
|
|
for (auto key : keys) {
|
||
|
|
for (auto flag : flags) {
|
||
|
|
notifier.NotifyEntry(keyindex, key, val, flag);
|
||
|
|
}
|
||
|
|
++keyindex;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_F(EntryNotifierTest, PollEntryMultiple) {
|
||
|
|
auto poller1 = notifier.CreatePoller();
|
||
|
|
auto poller2 = notifier.CreatePoller();
|
||
|
|
auto poller3 = notifier.CreatePoller();
|
||
|
|
auto h1 = notifier.AddPolled(poller1, 6, NT_NOTIFY_NEW);
|
||
|
|
auto h2 = notifier.AddPolled(poller2, 6, NT_NOTIFY_NEW);
|
||
|
|
auto h3 = notifier.AddPolled(poller3, 6, NT_NOTIFY_UPDATE);
|
||
|
|
|
||
|
|
ASSERT_FALSE(notifier.local_notifiers());
|
||
|
|
|
||
|
|
GenerateNotifications();
|
||
|
|
|
||
|
|
ASSERT_TRUE(notifier.WaitForQueue(1.0));
|
||
|
|
bool timed_out = false;
|
||
|
|
auto results1 = notifier.Poll(poller1, 0, &timed_out);
|
||
|
|
ASSERT_FALSE(timed_out);
|
||
|
|
auto results2 = notifier.Poll(poller2, 0, &timed_out);
|
||
|
|
ASSERT_FALSE(timed_out);
|
||
|
|
auto results3 = notifier.Poll(poller3, 0, &timed_out);
|
||
|
|
ASSERT_FALSE(timed_out);
|
||
|
|
|
||
|
|
ASSERT_EQ(results1.size(), 2u);
|
||
|
|
for (const auto& result : results1) {
|
||
|
|
SCOPED_TRACE(::testing::PrintToString(result));
|
||
|
|
EXPECT_EQ(Handle{result.listener}.GetIndex(), (int)h1);
|
||
|
|
}
|
||
|
|
|
||
|
|
ASSERT_EQ(results2.size(), 2u);
|
||
|
|
for (const auto& result : results2) {
|
||
|
|
SCOPED_TRACE(::testing::PrintToString(result));
|
||
|
|
EXPECT_EQ(Handle{result.listener}.GetIndex(), (int)h2);
|
||
|
|
}
|
||
|
|
|
||
|
|
ASSERT_EQ(results3.size(), 2u);
|
||
|
|
for (const auto& result : results3) {
|
||
|
|
SCOPED_TRACE(::testing::PrintToString(result));
|
||
|
|
EXPECT_EQ(Handle{result.listener}.GetIndex(), (int)h3);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_F(EntryNotifierTest, PollEntryBasic) {
|
||
|
|
auto poller = notifier.CreatePoller();
|
||
|
|
auto g1 = notifier.AddPolled(poller, 6, NT_NOTIFY_NEW);
|
||
|
|
auto g2 = notifier.AddPolled(poller, 6, NT_NOTIFY_DELETE);
|
||
|
|
auto g3 = notifier.AddPolled(poller, 6, NT_NOTIFY_UPDATE);
|
||
|
|
auto g4 = notifier.AddPolled(poller, 6, NT_NOTIFY_FLAGS);
|
||
|
|
|
||
|
|
ASSERT_FALSE(notifier.local_notifiers());
|
||
|
|
|
||
|
|
GenerateNotifications();
|
||
|
|
|
||
|
|
ASSERT_TRUE(notifier.WaitForQueue(1.0));
|
||
|
|
bool timed_out = false;
|
||
|
|
auto results = notifier.Poll(poller, 0, &timed_out);
|
||
|
|
ASSERT_FALSE(timed_out);
|
||
|
|
|
||
|
|
int g1count = 0;
|
||
|
|
int g2count = 0;
|
||
|
|
int g3count = 0;
|
||
|
|
int g4count = 0;
|
||
|
|
for (const auto& result : results) {
|
||
|
|
SCOPED_TRACE(::testing::PrintToString(result));
|
||
|
|
EXPECT_EQ(result.name, "/baz");
|
||
|
|
EXPECT_THAT(result.value, ValueEq(Value::MakeDouble(1)));
|
||
|
|
EXPECT_EQ(Handle{result.entry}.GetType(), Handle::kEntry);
|
||
|
|
EXPECT_EQ(Handle{result.entry}.GetInst(), 1);
|
||
|
|
EXPECT_EQ(Handle{result.entry}.GetIndex(), 6);
|
||
|
|
EXPECT_EQ(Handle{result.listener}.GetType(), Handle::kEntryListener);
|
||
|
|
EXPECT_EQ(Handle{result.listener}.GetInst(), 1);
|
||
|
|
if (Handle{result.listener}.GetIndex() == (int)g1) {
|
||
|
|
++g1count;
|
||
|
|
EXPECT_TRUE((result.flags & NT_NOTIFY_NEW) != 0);
|
||
|
|
} else if (Handle{result.listener}.GetIndex() == (int)g2) {
|
||
|
|
++g2count;
|
||
|
|
EXPECT_TRUE((result.flags & NT_NOTIFY_DELETE) != 0);
|
||
|
|
} else if (Handle{result.listener}.GetIndex() == (int)g3) {
|
||
|
|
++g3count;
|
||
|
|
EXPECT_TRUE((result.flags & NT_NOTIFY_UPDATE) != 0);
|
||
|
|
} else if (Handle{result.listener}.GetIndex() == (int)g4) {
|
||
|
|
++g4count;
|
||
|
|
EXPECT_TRUE((result.flags & NT_NOTIFY_FLAGS) != 0);
|
||
|
|
} else {
|
||
|
|
ADD_FAILURE() << "unknown listener index";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
EXPECT_EQ(g1count, 2);
|
||
|
|
EXPECT_EQ(g2count, 1); // NT_NOTIFY_DELETE
|
||
|
|
EXPECT_EQ(g3count, 2);
|
||
|
|
EXPECT_EQ(g4count, 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_F(EntryNotifierTest, PollEntryImmediate) {
|
||
|
|
auto poller = notifier.CreatePoller();
|
||
|
|
notifier.AddPolled(poller, 6, NT_NOTIFY_NEW | NT_NOTIFY_IMMEDIATE);
|
||
|
|
notifier.AddPolled(poller, 6, NT_NOTIFY_NEW);
|
||
|
|
|
||
|
|
ASSERT_FALSE(notifier.local_notifiers());
|
||
|
|
|
||
|
|
GenerateNotifications();
|
||
|
|
|
||
|
|
ASSERT_TRUE(notifier.WaitForQueue(1.0));
|
||
|
|
bool timed_out = false;
|
||
|
|
auto results = notifier.Poll(poller, 0, &timed_out);
|
||
|
|
ASSERT_FALSE(timed_out);
|
||
|
|
SCOPED_TRACE(::testing::PrintToString(results));
|
||
|
|
ASSERT_EQ(results.size(), 4u);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_F(EntryNotifierTest, PollEntryLocal) {
|
||
|
|
auto poller = notifier.CreatePoller();
|
||
|
|
notifier.AddPolled(poller, 6, NT_NOTIFY_NEW | NT_NOTIFY_LOCAL);
|
||
|
|
notifier.AddPolled(poller, 6, NT_NOTIFY_NEW);
|
||
|
|
|
||
|
|
ASSERT_TRUE(notifier.local_notifiers());
|
||
|
|
|
||
|
|
GenerateNotifications();
|
||
|
|
|
||
|
|
ASSERT_TRUE(notifier.WaitForQueue(1.0));
|
||
|
|
bool timed_out = false;
|
||
|
|
auto results = notifier.Poll(poller, 0, &timed_out);
|
||
|
|
ASSERT_FALSE(timed_out);
|
||
|
|
SCOPED_TRACE(::testing::PrintToString(results));
|
||
|
|
ASSERT_EQ(results.size(), 6u);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_F(EntryNotifierTest, PollPrefixMultiple) {
|
||
|
|
auto poller1 = notifier.CreatePoller();
|
||
|
|
auto poller2 = notifier.CreatePoller();
|
||
|
|
auto poller3 = notifier.CreatePoller();
|
||
|
|
auto h1 = notifier.AddPolled(poller1, "/foo", NT_NOTIFY_NEW);
|
||
|
|
auto h2 = notifier.AddPolled(poller2, "/foo", NT_NOTIFY_NEW);
|
||
|
|
auto h3 = notifier.AddPolled(poller3, "/foo", NT_NOTIFY_UPDATE);
|
||
|
|
|
||
|
|
ASSERT_FALSE(notifier.local_notifiers());
|
||
|
|
|
||
|
|
GenerateNotifications();
|
||
|
|
|
||
|
|
ASSERT_TRUE(notifier.WaitForQueue(1.0));
|
||
|
|
bool timed_out = false;
|
||
|
|
auto results1 = notifier.Poll(poller1, 0, &timed_out);
|
||
|
|
ASSERT_FALSE(timed_out);
|
||
|
|
auto results2 = notifier.Poll(poller2, 0, &timed_out);
|
||
|
|
ASSERT_FALSE(timed_out);
|
||
|
|
auto results3 = notifier.Poll(poller3, 0, &timed_out);
|
||
|
|
ASSERT_FALSE(timed_out);
|
||
|
|
|
||
|
|
ASSERT_EQ(results1.size(), 2u);
|
||
|
|
for (const auto& result : results1) {
|
||
|
|
SCOPED_TRACE(::testing::PrintToString(result));
|
||
|
|
EXPECT_EQ(Handle{result.listener}.GetIndex(), (int)h1);
|
||
|
|
}
|
||
|
|
|
||
|
|
ASSERT_EQ(results2.size(), 2u);
|
||
|
|
for (const auto& result : results2) {
|
||
|
|
SCOPED_TRACE(::testing::PrintToString(result));
|
||
|
|
EXPECT_EQ(Handle{result.listener}.GetIndex(), (int)h2);
|
||
|
|
}
|
||
|
|
|
||
|
|
ASSERT_EQ(results3.size(), 2u);
|
||
|
|
for (const auto& result : results3) {
|
||
|
|
SCOPED_TRACE(::testing::PrintToString(result));
|
||
|
|
EXPECT_EQ(Handle{result.listener}.GetIndex(), (int)h3);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_F(EntryNotifierTest, PollPrefixBasic) {
|
||
|
|
auto poller = notifier.CreatePoller();
|
||
|
|
auto g1 = notifier.AddPolled(poller, "/foo", NT_NOTIFY_NEW);
|
||
|
|
auto g2 = notifier.AddPolled(poller, "/foo", NT_NOTIFY_DELETE);
|
||
|
|
auto g3 = notifier.AddPolled(poller, "/foo", NT_NOTIFY_UPDATE);
|
||
|
|
auto g4 = notifier.AddPolled(poller, "/foo", NT_NOTIFY_FLAGS);
|
||
|
|
notifier.AddPolled(poller, "/bar", NT_NOTIFY_NEW);
|
||
|
|
notifier.AddPolled(poller, "/bar", NT_NOTIFY_DELETE);
|
||
|
|
notifier.AddPolled(poller, "/bar", NT_NOTIFY_UPDATE);
|
||
|
|
notifier.AddPolled(poller, "/bar", NT_NOTIFY_FLAGS);
|
||
|
|
|
||
|
|
ASSERT_FALSE(notifier.local_notifiers());
|
||
|
|
|
||
|
|
GenerateNotifications();
|
||
|
|
|
||
|
|
ASSERT_TRUE(notifier.WaitForQueue(1.0));
|
||
|
|
bool timed_out = false;
|
||
|
|
auto results = notifier.Poll(poller, 0, &timed_out);
|
||
|
|
ASSERT_FALSE(timed_out);
|
||
|
|
|
||
|
|
int g1count = 0;
|
||
|
|
int g2count = 0;
|
||
|
|
int g3count = 0;
|
||
|
|
int g4count = 0;
|
||
|
|
for (const auto& result : results) {
|
||
|
|
SCOPED_TRACE(::testing::PrintToString(result));
|
||
|
|
EXPECT_TRUE(StringRef(result.name).startswith("/foo"));
|
||
|
|
EXPECT_THAT(result.value, ValueEq(Value::MakeDouble(1)));
|
||
|
|
EXPECT_EQ(Handle{result.entry}.GetType(), Handle::kEntry);
|
||
|
|
EXPECT_EQ(Handle{result.entry}.GetInst(), 1);
|
||
|
|
EXPECT_EQ(Handle{result.entry}.GetIndex(), 5);
|
||
|
|
EXPECT_EQ(Handle{result.listener}.GetType(), Handle::kEntryListener);
|
||
|
|
EXPECT_EQ(Handle{result.listener}.GetInst(), 1);
|
||
|
|
if (Handle{result.listener}.GetIndex() == (int)g1) {
|
||
|
|
++g1count;
|
||
|
|
EXPECT_TRUE((result.flags & NT_NOTIFY_NEW) != 0);
|
||
|
|
} else if (Handle{result.listener}.GetIndex() == (int)g2) {
|
||
|
|
++g2count;
|
||
|
|
EXPECT_TRUE((result.flags & NT_NOTIFY_DELETE) != 0);
|
||
|
|
} else if (Handle{result.listener}.GetIndex() == (int)g3) {
|
||
|
|
++g3count;
|
||
|
|
EXPECT_TRUE((result.flags & NT_NOTIFY_UPDATE) != 0);
|
||
|
|
} else if (Handle{result.listener}.GetIndex() == (int)g4) {
|
||
|
|
++g4count;
|
||
|
|
EXPECT_TRUE((result.flags & NT_NOTIFY_FLAGS) != 0);
|
||
|
|
} else {
|
||
|
|
ADD_FAILURE() << "unknown listener index";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
EXPECT_EQ(g1count, 2);
|
||
|
|
EXPECT_EQ(g2count, 1); // NT_NOTIFY_DELETE
|
||
|
|
EXPECT_EQ(g3count, 2);
|
||
|
|
EXPECT_EQ(g4count, 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_F(EntryNotifierTest, PollPrefixImmediate) {
|
||
|
|
auto poller = notifier.CreatePoller();
|
||
|
|
notifier.AddPolled(poller, "/foo", NT_NOTIFY_NEW | NT_NOTIFY_IMMEDIATE);
|
||
|
|
notifier.AddPolled(poller, "/foo", NT_NOTIFY_NEW);
|
||
|
|
|
||
|
|
ASSERT_FALSE(notifier.local_notifiers());
|
||
|
|
|
||
|
|
GenerateNotifications();
|
||
|
|
|
||
|
|
ASSERT_TRUE(notifier.WaitForQueue(1.0));
|
||
|
|
bool timed_out = false;
|
||
|
|
auto results = notifier.Poll(poller, 0, &timed_out);
|
||
|
|
ASSERT_FALSE(timed_out);
|
||
|
|
SCOPED_TRACE(::testing::PrintToString(results));
|
||
|
|
ASSERT_EQ(results.size(), 4u);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_F(EntryNotifierTest, PollPrefixLocal) {
|
||
|
|
auto poller = notifier.CreatePoller();
|
||
|
|
notifier.AddPolled(poller, "/foo", NT_NOTIFY_NEW | NT_NOTIFY_LOCAL);
|
||
|
|
notifier.AddPolled(poller, "/foo", NT_NOTIFY_NEW);
|
||
|
|
|
||
|
|
ASSERT_TRUE(notifier.local_notifiers());
|
||
|
|
|
||
|
|
GenerateNotifications();
|
||
|
|
|
||
|
|
ASSERT_TRUE(notifier.WaitForQueue(1.0));
|
||
|
|
bool timed_out = false;
|
||
|
|
auto results = notifier.Poll(poller, 0, &timed_out);
|
||
|
|
ASSERT_FALSE(timed_out);
|
||
|
|
SCOPED_TRACE(::testing::PrintToString(results));
|
||
|
|
ASSERT_EQ(results.size(), 6u);
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace nt
|