rippled
Loading...
Searching...
No Matches
Livecache_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <test/beast/IPEndpointCommon.h>
21#include <test/unit_test/SuiteJournal.h>
22#include <xrpld/peerfinder/detail/Livecache.h>
23#include <xrpl/basics/chrono.h>
24#include <xrpl/basics/safe_cast.h>
25#include <xrpl/beast/clock/manual_clock.h>
26#include <xrpl/beast/unit_test.h>
27#include <boost/algorithm/string.hpp>
28
29namespace ripple {
30namespace PeerFinder {
31
32bool
33operator==(Endpoint const& a, Endpoint const& b)
34{
35 return (a.hops == b.hops && a.address == b.address);
36}
37
39{
42
43public:
44 Livecache_test() : journal_("Livecache_test", *this)
45 {
46 }
47
48 // Add the address as an endpoint
49 template <class C>
50 inline void
52 {
53 Endpoint cep{ep, hops};
54 c.insert(cep);
55 }
56
57 void
59 {
60 testcase("Basic Insert");
62 BEAST_EXPECT(c.empty());
63
64 for (auto i = 0; i < 10; ++i)
65 add(beast::IP::randomEP(true), c);
66
67 BEAST_EXPECT(!c.empty());
68 BEAST_EXPECT(c.size() == 10);
69
70 for (auto i = 0; i < 10; ++i)
71 add(beast::IP::randomEP(false), c);
72
73 BEAST_EXPECT(!c.empty());
74 BEAST_EXPECT(c.size() == 20);
75 }
76
77 void
79 {
80 testcase("Insert/Update");
82
83 auto ep1 = Endpoint{beast::IP::randomEP(), 2};
84 c.insert(ep1);
85 BEAST_EXPECT(c.size() == 1);
86 // third position list will contain the entry
87 BEAST_EXPECT((c.hops.begin() + 2)->begin()->hops == 2);
88
89 auto ep2 = Endpoint{ep1.address, 4};
90 // this will not change the entry has higher hops
91 c.insert(ep2);
92 BEAST_EXPECT(c.size() == 1);
93 // still in third position list
94 BEAST_EXPECT((c.hops.begin() + 2)->begin()->hops == 2);
95
96 auto ep3 = Endpoint{ep1.address, 2};
97 // this will not change the entry has the same hops as existing
98 c.insert(ep3);
99 BEAST_EXPECT(c.size() == 1);
100 // still in third position list
101 BEAST_EXPECT((c.hops.begin() + 2)->begin()->hops == 2);
102
103 auto ep4 = Endpoint{ep1.address, 1};
104 c.insert(ep4);
105 BEAST_EXPECT(c.size() == 1);
106 // now at second position list
107 BEAST_EXPECT((c.hops.begin() + 1)->begin()->hops == 1);
108 }
109
110 void
112 {
113 testcase("Expire");
114 using namespace std::chrono_literals;
116
117 auto ep1 = Endpoint{beast::IP::randomEP(), 1};
118 c.insert(ep1);
119 BEAST_EXPECT(c.size() == 1);
120 c.expire();
121 BEAST_EXPECT(c.size() == 1);
122 // verify that advancing to 1 sec before expiration
123 // leaves our entry intact
125 c.expire();
126 BEAST_EXPECT(c.size() == 1);
127 // now advance to the point of expiration
128 clock_.advance(1s);
129 c.expire();
130 BEAST_EXPECT(c.empty());
131 }
132
133 void
135 {
136 testcase("Histogram");
137 constexpr auto num_eps = 40;
139 for (auto i = 0; i < num_eps; ++i)
141 c,
142 ripple::rand_int<std::uint32_t>());
143 auto h = c.hops.histogram();
144 if (!BEAST_EXPECT(!h.empty()))
145 return;
147 boost::split(v, h, boost::algorithm::is_any_of(","));
148 auto sum = 0;
149 for (auto const& n : v)
150 {
151 auto val = boost::lexical_cast<int>(boost::trim_copy(n));
152 sum += val;
153 BEAST_EXPECT(val >= 0);
154 }
155 BEAST_EXPECT(sum == num_eps);
156 }
157
158 void
160 {
161 testcase("Shuffle");
163 for (auto i = 0; i < 100; ++i)
165 c,
167
170
171 auto cmp_EP = [](Endpoint const& a, Endpoint const& b) {
172 return (
173 b.hops < a.hops || (b.hops == a.hops && b.address < a.address));
174 };
175 all_hops before;
176 all_hops before_sorted;
177 for (auto i = std::make_pair(0, c.hops.begin());
178 i.second != c.hops.end();
179 ++i.first, ++i.second)
180 {
181 std::copy(
182 (*i.second).begin(),
183 (*i.second).end(),
184 std::back_inserter(before[i.first]));
185 std::copy(
186 (*i.second).begin(),
187 (*i.second).end(),
188 std::back_inserter(before_sorted[i.first]));
189 std::sort(
190 before_sorted[i.first].begin(),
191 before_sorted[i.first].end(),
192 cmp_EP);
193 }
194
195 c.hops.shuffle();
196
197 all_hops after;
198 all_hops after_sorted;
199 for (auto i = std::make_pair(0, c.hops.begin());
200 i.second != c.hops.end();
201 ++i.first, ++i.second)
202 {
203 std::copy(
204 (*i.second).begin(),
205 (*i.second).end(),
206 std::back_inserter(after[i.first]));
207 std::copy(
208 (*i.second).begin(),
209 (*i.second).end(),
210 std::back_inserter(after_sorted[i.first]));
211 std::sort(
212 after_sorted[i.first].begin(),
213 after_sorted[i.first].end(),
214 cmp_EP);
215 }
216
217 // each hop bucket should contain the same items
218 // before and after sort, albeit in different order
219 bool all_match = true;
220 for (auto i = 0; i < before.size(); ++i)
221 {
222 BEAST_EXPECT(before[i].size() == after[i].size());
223 all_match = all_match && (before[i] == after[i]);
224 BEAST_EXPECT(before_sorted[i] == after_sorted[i]);
225 }
226 BEAST_EXPECT(!all_match);
227 }
228
229 void
230 run() override
231 {
234 testExpire();
236 testShuffle();
237 }
238};
239
240BEAST_DEFINE_TESTSUITE(Livecache, peerfinder, ripple);
241
242} // namespace PeerFinder
243} // namespace ripple
T back_inserter(T... args)
A version-independent IP address and port combination.
Definition: IPEndpoint.h:39
void advance(std::chrono::duration< Rep, Period > const &elapsed)
Advance the clock by a duration.
Definition: manual_clock.h:81
A testsuite class.
Definition: suite.h:53
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:153
void shuffle()
Shuffle each hop list.
Definition: Livecache.h:497
void run() override
Runs the suite.
void add(beast::IP::Endpoint ep, C &c, std::uint32_t hops=0)
The Livecache holds the short-lived relayed Endpoint messages.
Definition: Livecache.h:196
cache_type::size_type size() const
Returns the number of entries in the cache.
Definition: Livecache.h:374
void expire()
Erase entries whose time has expired.
Definition: Livecache.h:405
void insert(Endpoint const &ep)
Creates or updates an existing Element based on a new message.
Definition: Livecache.h:427
class ripple::PeerFinder::Livecache::hops_t hops
bool empty() const
Returns true if the cache is empty.
Definition: Livecache.h:367
T copy(T... args)
T make_pair(T... args)
Endpoint randomEP(bool v4=true)
std::chrono::seconds constexpr liveCacheSecondsToLive(30)
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:26
static auto sum(TCollection const &col)
Definition: BookStep.cpp:999
std::enable_if_t< std::is_integral< Integral >::value, Integral > rand_int()
static bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition: Escrow.cpp:89
T sort(T... args)
Describes a connectible peer address along with some metadata.