xrpld
Loading...
Searching...
No Matches
Livecache_test.cpp
1#include <test/beast/IPEndpointCommon.h>
2#include <test/unit_test/SuiteJournal.h>
3
4#include <xrpld/peerfinder/PeerfinderManager.h>
5#include <xrpld/peerfinder/detail/Livecache.h>
6#include <xrpld/peerfinder/detail/Tuning.h>
7
8#include <xrpl/basics/chrono.h>
9#include <xrpl/basics/random.h>
10#include <xrpl/beast/net/IPEndpoint.h>
11#include <xrpl/beast/unit_test/suite.h>
12
13#include <boost/algorithm/string/classification.hpp>
14#include <boost/algorithm/string/split.hpp>
15#include <boost/algorithm/string/trim.hpp>
16#include <boost/lexical_cast.hpp>
17
18#include <algorithm>
19#include <array>
20#include <cstdint>
21#include <iterator>
22#include <utility>
23#include <vector>
24
26
27bool
28operator==(Endpoint const& a, Endpoint const& b)
29{
30 return (a.hops == b.hops && a.address == b.address);
31}
32
34{
37
38public:
39 Livecache_test() : journal_("Livecache_test", *this)
40 {
41 }
42
43 // Add the address as an endpoint
44 template <class C>
45 void
47 {
48 Endpoint const cep{ep, hops};
49 c.insert(cep);
50 }
51
52 void
54 {
55 testcase("Basic Insert");
57 BEAST_EXPECT(c.empty());
58
59 for (auto i = 0; i < 10; ++i)
60 add(beast::IP::randomEP(true), c);
61
62 BEAST_EXPECT(!c.empty());
63 BEAST_EXPECT(c.size() == 10);
64
65 for (auto i = 0; i < 10; ++i)
66 add(beast::IP::randomEP(false), c);
67
68 BEAST_EXPECT(!c.empty());
69 BEAST_EXPECT(c.size() == 20);
70 }
71
72 void
74 {
75 testcase("Insert/Update");
77
78 auto ep1 = Endpoint{beast::IP::randomEP(), 2};
79 c.insert(ep1);
80 BEAST_EXPECT(c.size() == 1);
81 // third position list will contain the entry
82 BEAST_EXPECT((c.hops.begin() + 2)->begin()->hops == 2);
83
84 auto ep2 = Endpoint{ep1.address, 4};
85 // this will not change the entry has higher hops
86 c.insert(ep2);
87 BEAST_EXPECT(c.size() == 1);
88 // still in third position list
89 BEAST_EXPECT((c.hops.begin() + 2)->begin()->hops == 2);
90
91 auto ep3 = Endpoint{ep1.address, 2};
92 // this will not change the entry has the same hops as existing
93 c.insert(ep3);
94 BEAST_EXPECT(c.size() == 1);
95 // still in third position list
96 BEAST_EXPECT((c.hops.begin() + 2)->begin()->hops == 2);
97
98 auto ep4 = Endpoint{ep1.address, 1};
99 c.insert(ep4);
100 BEAST_EXPECT(c.size() == 1);
101 // now at second position list
102 BEAST_EXPECT((c.hops.begin() + 1)->begin()->hops == 1);
103 }
104
105 void
107 {
108 testcase("Expire");
109 using namespace std::chrono_literals;
111
112 auto ep1 = Endpoint{beast::IP::randomEP(), 1};
113 c.insert(ep1);
114 BEAST_EXPECT(c.size() == 1);
115 c.expire();
116 BEAST_EXPECT(c.size() == 1);
117 // verify that advancing to 1 sec before expiration
118 // leaves our entry intact
120 c.expire();
121 BEAST_EXPECT(c.size() == 1);
122 // now advance to the point of expiration
123 clock_.advance(1s);
124 c.expire();
125 BEAST_EXPECT(c.empty());
126 }
127
128 void
130 {
131 testcase("Histogram");
132 static constexpr auto kNumEps = 40;
134 for (auto i = 0; i < kNumEps; ++i)
136 auto h = c.hops.histogram();
137 if (!BEAST_EXPECT(!h.empty()))
138 return;
140 boost::split(v, h, boost::algorithm::is_any_of(","));
141 auto sum = 0;
142 for (auto const& n : v)
143 {
144 auto val = boost::lexical_cast<int>(boost::trim_copy(n));
145 sum += val;
146 BEAST_EXPECT(val >= 0);
147 }
148 BEAST_EXPECT(sum == kNumEps);
149 }
150
151 void
153 {
154 testcase("Shuffle");
156 for (auto i = 0; i < 100; ++i)
158
161
162 auto cmpEp = [](Endpoint const& a, Endpoint const& b) {
163 return (b.hops < a.hops || (b.hops == a.hops && b.address < a.address));
164 };
165 all_hops before;
166 all_hops beforeSorted;
167 for (auto i = std::make_pair(0, c.hops.begin()); i.second != c.hops.end();
168 ++i.first, ++i.second)
169 {
170 std::ranges::copy(*i.second, std::back_inserter(before[i.first]));
171 std::ranges::copy(*i.second, std::back_inserter(beforeSorted[i.first]));
172 std::ranges::sort(beforeSorted[i.first], cmpEp);
173 }
174
175 c.hops.shuffle();
176
177 all_hops after;
178 all_hops afterSorted;
179 for (auto i = std::make_pair(0, c.hops.begin()); i.second != c.hops.end();
180 ++i.first, ++i.second)
181 {
182 std::ranges::copy(*i.second, std::back_inserter(after[i.first]));
183 std::ranges::copy(*i.second, std::back_inserter(afterSorted[i.first]));
184 std::ranges::sort(afterSorted[i.first], cmpEp);
185 }
186
187 // each hop bucket should contain the same items
188 // before and after sort, albeit in different order
189 bool allMatch = true;
190 for (auto i = 0; i < before.size(); ++i)
191 {
192 BEAST_EXPECT(before[i].size() == after[i].size());
193 allMatch = allMatch && (before[i] == after[i]);
194 BEAST_EXPECT(beforeSorted[i] == afterSorted[i]);
195 }
196 BEAST_EXPECT(!allMatch);
197 }
198
199 void
200 run() override
201 {
204 testExpire();
206 testShuffle();
207 }
208};
209
211
212} // namespace xrpl::PeerFinder
T back_inserter(T... args)
A version-independent IP address and port combination.
Definition IPEndpoint.h:17
A testsuite class.
Definition suite.h:50
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:149
void shuffle()
Shuffle each hop list.
Definition Livecache.h:461
std::string histogram() const
Definition Livecache.h:477
void add(beast::IP::Endpoint ep, C &c, std::uint32_t hops=0)
void run() override
Runs the suite.
The Livecache holds the short-lived relayed Endpoint messages.
Definition Livecache.h:172
cache_type::size_type size() const
Returns the number of entries in the cache.
Definition Livecache.h:341
class xrpl::PeerFinder::Livecache::HopsT hops
void expire()
Erase entries whose time has expired.
Definition Livecache.h:369
void insert(Endpoint const &ep)
Creates or updates an existing Element based on a new message.
Definition Livecache.h:391
bool empty() const
Returns true if the cache is empty.
Definition Livecache.h:334
T copy(T... args)
T make_pair(T... args)
Endpoint randomEP(bool v4=true)
constexpr std::chrono::seconds kLiveCacheSecondsToLive(30)
BEAST_DEFINE_TESTSUITE(Livecache, peerfinder, xrpl)
bool operator==(Endpoint const &a, Endpoint const &b)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
static auto sum(TCollection const &col)
Definition BookStep.cpp:993
std::enable_if_t< std::is_integral_v< Integral > &&detail::is_engine< Engine >::value, Integral > randInt(Engine &engine, Integral min, Integral max)
Return a uniformly distributed random integer.
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:554
beast::ManualClock< std::chrono::steady_clock > TestStopwatch
A manual Stopwatch for unit tests.
Definition chrono.h:90
T sort(T... args)
Describes a connectable peer address along with some metadata.