rippled
Loading...
Searching...
No Matches
Logic_test.cpp
1#include <test/unit_test/SuiteJournal.h>
2
3#include <xrpl/basics/chrono.h>
4#include <xrpl/basics/random.h>
5#include <xrpl/beast/unit_test.h>
6#include <xrpl/resource/Consumer.h>
7#include <xrpl/resource/detail/Entry.h>
8#include <xrpl/resource/detail/Logic.h>
9
10#include <boost/utility/base_from_member.hpp>
11
12#include <functional>
13
14namespace xrpl {
15namespace Resource {
16
18{
19public:
20 class TestLogic : private boost::base_from_member<TestStopwatch>, public Logic
21
22 {
23 private:
24 using clock_type = boost::base_from_member<TestStopwatch>;
25
26 public:
27 explicit TestLogic(beast::Journal journal)
28 : Logic(beast::insight::NullCollector::New(), member, journal)
29 {
30 }
31
32 void
34 {
35 ++member;
36 }
37
40 {
41 return member;
42 }
43 };
44
45 //--------------------------------------------------------------------------
46
47 static void
49 {
50 std::uint8_t const v(10 + rand_int(9));
51 std::uint8_t const n(10 + rand_int(9));
52 gossip.items.reserve(n);
53 for (std::uint8_t i = 0; i < n; ++i)
54 {
55 Gossip::Item item;
56 item.balance = 100 + rand_int(499);
57 beast::IP::AddressV4::bytes_type const d = {
58 {192, 0, 2, static_cast<std::uint8_t>(v + i)}};
60 gossip.items.push_back(item);
61 }
62 }
63
64 //--------------------------------------------------------------------------
65
66 void
67 testDrop(beast::Journal j, bool limited)
68 {
69 if (limited)
70 {
71 testcase("Limited warn/drop");
72 }
73 else
74 {
75 testcase("Unlimited warn/drop");
76 }
77
78 TestLogic logic(j);
79
80 Charge const fee(dropThreshold + 1);
82
83 std::function<Consumer(beast::IP::Endpoint)> const ep = limited
84 ? std::bind(&TestLogic::newInboundEndpoint, &logic, std::placeholders::_1)
85 : std::bind(&TestLogic::newUnlimitedEndpoint, &logic, std::placeholders::_1);
86
87 {
88 Consumer c(ep(addr));
89
90 // Create load until we get a warning
91 int n = 10000;
92
93 while (--n >= 0)
94 {
95 if (n == 0)
96 {
97 if (limited)
98 {
99 fail("Loop count exceeded without warning");
100 }
101 else
102 {
103 pass();
104 }
105 return;
106 }
107
108 if (c.charge(fee) == warn)
109 {
110 if (limited)
111 {
112 pass();
113 }
114 else
115 {
116 fail("Should loop forever with no warning");
117 }
118 break;
119 }
120 ++logic.clock();
121 }
122
123 // Create load until we get dropped
124 while (--n >= 0)
125 {
126 if (n == 0)
127 {
128 if (limited)
129 {
130 fail("Loop count exceeded without dropping");
131 }
132 else
133 {
134 pass();
135 }
136 return;
137 }
138
139 if (c.charge(fee) == drop)
140 {
141 // Disconnect abusive Consumer
142 BEAST_EXPECT(c.disconnect(j) == limited);
143 break;
144 }
145 ++logic.clock();
146 }
147 }
148
149 // Make sure the consumer is on the blacklist for a while.
150 {
151 Consumer const c(logic.newInboundEndpoint(addr));
152 logic.periodicActivity();
153 if (c.disposition() != drop)
154 {
155 if (limited)
156 {
157 fail("Dropped consumer not put on blacklist");
158 }
159 else
160 {
161 pass();
162 }
163 return;
164 }
165 }
166
167 // Makes sure the Consumer is eventually removed from blacklist
168 bool readmitted = false;
169 {
170 using namespace std::chrono_literals;
171 // Give Consumer time to become readmitted. Should never
172 // exceed expiration time.
173 auto n = secondsUntilExpiration + 1s;
174 while (--n > 0s)
175 {
176 ++logic.clock();
177 logic.periodicActivity();
178 Consumer const c(logic.newInboundEndpoint(addr));
179 if (c.disposition() != drop)
180 {
181 readmitted = true;
182 break;
183 }
184 }
185 }
186 if (!readmitted)
187 {
188 fail("Dropped Consumer left on blacklist too long");
189 return;
190 }
191 pass();
192 }
193
194 void
196 {
197 testcase("Imports");
198
199 TestLogic logic(j);
200
201 Gossip g[5];
202
203 for (int i = 0; i < 5; ++i)
204 createGossip(g[i]);
205
206 for (int i = 0; i < 5; ++i)
207 logic.importConsumers(std::to_string(i), g[i]);
208
209 pass();
210 }
211
212 void
214 {
215 testcase("Import");
216
217 TestLogic logic(j);
218
219 Gossip g;
220 Gossip::Item item;
221 item.balance = 100;
222 beast::IP::AddressV4::bytes_type const d = {{192, 0, 2, 1}};
224 g.items.push_back(item);
225
226 logic.importConsumers("g", g);
227
228 pass();
229 }
230
231 void
233 {
234 testcase("Charge");
235
236 TestLogic logic(j);
237
238 {
239 beast::IP::Endpoint const address(beast::IP::Endpoint::from_string("192.0.2.1"));
240 Consumer c(logic.newInboundEndpoint(address));
241 Charge const fee(1000);
242 JLOG(j.info()) << "Charging " << c.to_string() << " " << fee << " per second";
243 c.charge(fee);
244 for (int i = 0; i < 128; ++i)
245 {
246 JLOG(j.info()) << "Time= " << logic.clock().now().time_since_epoch().count()
247 << ", Balance = " << c.balance();
248 logic.advance();
249 }
250 }
251
252 {
253 beast::IP::Endpoint const address(beast::IP::Endpoint::from_string("192.0.2.2"));
254 Consumer c(logic.newInboundEndpoint(address));
255 Charge const fee(1000);
256 JLOG(j.info()) << "Charging " << c.to_string() << " " << fee << " per second";
257 for (int i = 0; i < 128; ++i)
258 {
259 c.charge(fee);
260 JLOG(j.info()) << "Time= " << logic.clock().now().time_since_epoch().count()
261 << ", Balance = " << c.balance();
262 logic.advance();
263 }
264 }
265
266 pass();
267 }
268
269 void
270 run() override
271 {
272 using namespace beast::severities;
273 test::SuiteJournal journal("ResourceManager_test", *this);
274
275 testDrop(journal, true);
276 testDrop(journal, false);
277 testCharges(journal);
278 testImports(journal);
279 testImport(journal);
280 }
281};
282
283BEAST_DEFINE_TESTSUITE(ResourceManager, resource, xrpl);
284
285} // namespace Resource
286} // namespace xrpl
T bind(T... args)
A version-independent IP address and port combination.
Definition IPEndpoint.h:18
static Endpoint from_string(std::string const &s)
A generic endpoint for log messages.
Definition Journal.h:40
Stream info() const
Definition Journal.h:307
time_point now() const override
Returns the current time.
A testsuite class.
Definition suite.h:51
void pass()
Record a successful test condition.
Definition suite.h:497
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:150
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:519
A consumption charge.
Definition Charge.h:10
An endpoint that consumes resources.
Definition Consumer.h:16
bool disconnect(beast::Journal const &j)
Returns true if the consumer should be disconnected.
Definition Consumer.cpp:106
Disposition disposition() const
Returns the current disposition of this consumer.
Definition Consumer.cpp:78
std::string to_string() const
Return a human readable string uniquely identifying this consumer.
Definition Consumer.cpp:60
int balance()
Returns the credit balance representing consumption.
Definition Consumer.cpp:118
Disposition charge(Charge const &fee, std::string const &context={})
Apply a load charge to the consumer.
Definition Consumer.cpp:88
Consumer newInboundEndpoint(beast::IP::Endpoint const &address)
Consumer newUnlimitedEndpoint(beast::IP::Endpoint const &address)
Create endpoint that should not have resource limits applied.
void importConsumers(std::string const &origin, Gossip const &gossip)
boost::base_from_member< TestStopwatch > clock_type
void testImport(beast::Journal j)
void testCharges(beast::Journal j)
void run() override
Runs the suite.
static void createGossip(Gossip &gossip)
void testImports(beast::Journal j)
void testDrop(beast::Journal j, bool limited)
boost::asio::ip::address_v4 AddressV4
Definition IPAddressV4.h:10
A namespace for easy access to logging severity values.
Definition Journal.h:10
@ warn
Consumer should be disconnected for excess consumption.
Definition Disposition.h:13
std::chrono::seconds constexpr secondsUntilExpiration
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::enable_if_t< std::is_integral< Integral >::value, Integral > rand_int()
Describes a single consumer.
Definition Gossip.h:17
beast::IP::Endpoint address
Definition Gossip.h:21
Data format for exchanging consumption information across peers.
Definition Gossip.h:12
std::vector< Item > items
Definition Gossip.h:24
T to_string(T... args)