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