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) : Logic(beast::insight::NullCollector::New(), member, journal)
28 {
29 }
30
31 void
33 {
34 ++member;
35 }
36
39 {
40 return member;
41 }
42 };
43
44 //--------------------------------------------------------------------------
45
46 void
48 {
49 std::uint8_t const v(10 + rand_int(9));
50 std::uint8_t const n(10 + rand_int(9));
51 gossip.items.reserve(n);
52 for (std::uint8_t i = 0; i < n; ++i)
53 {
54 Gossip::Item item;
55 item.balance = 100 + rand_int(499);
56 beast::IP::AddressV4::bytes_type d = {{192, 0, 2, static_cast<std::uint8_t>(v + i)}};
58 gossip.items.push_back(item);
59 }
60 }
61
62 //--------------------------------------------------------------------------
63
64 void
65 testDrop(beast::Journal j, bool limited)
66 {
67 if (limited)
68 testcase("Limited warn/drop");
69 else
70 testcase("Unlimited warn/drop");
71
72 TestLogic logic(j);
73
74 Charge const fee(dropThreshold + 1);
76
78 ? std::bind(&TestLogic::newInboundEndpoint, &logic, std::placeholders::_1)
79 : std::bind(&TestLogic::newUnlimitedEndpoint, &logic, std::placeholders::_1);
80
81 {
82 Consumer c(ep(addr));
83
84 // Create load until we get a warning
85 int n = 10000;
86
87 while (--n >= 0)
88 {
89 if (n == 0)
90 {
91 if (limited)
92 fail("Loop count exceeded without warning");
93 else
94 pass();
95 return;
96 }
97
98 if (c.charge(fee) == warn)
99 {
100 if (limited)
101 pass();
102 else
103 fail("Should loop forever with no warning");
104 break;
105 }
106 ++logic.clock();
107 }
108
109 // Create load until we get dropped
110 while (--n >= 0)
111 {
112 if (n == 0)
113 {
114 if (limited)
115 fail("Loop count exceeded without dropping");
116 else
117 pass();
118 return;
119 }
120
121 if (c.charge(fee) == drop)
122 {
123 // Disconnect abusive Consumer
124 BEAST_EXPECT(c.disconnect(j) == limited);
125 break;
126 }
127 ++logic.clock();
128 }
129 }
130
131 // Make sure the consumer is on the blacklist for a while.
132 {
133 Consumer c(logic.newInboundEndpoint(addr));
134 logic.periodicActivity();
135 if (c.disposition() != drop)
136 {
137 if (limited)
138 fail("Dropped consumer not put on blacklist");
139 else
140 pass();
141 return;
142 }
143 }
144
145 // Makes sure the Consumer is eventually removed from blacklist
146 bool readmitted = false;
147 {
148 using namespace std::chrono_literals;
149 // Give Consumer time to become readmitted. Should never
150 // exceed expiration time.
151 auto n = secondsUntilExpiration + 1s;
152 while (--n > 0s)
153 {
154 ++logic.clock();
155 logic.periodicActivity();
156 Consumer c(logic.newInboundEndpoint(addr));
157 if (c.disposition() != drop)
158 {
159 readmitted = true;
160 break;
161 }
162 }
163 }
164 if (readmitted == false)
165 {
166 fail("Dropped Consumer left on blacklist too long");
167 return;
168 }
169 pass();
170 }
171
172 void
174 {
175 testcase("Imports");
176
177 TestLogic logic(j);
178
179 Gossip g[5];
180
181 for (int i = 0; i < 5; ++i)
182 createGossip(g[i]);
183
184 for (int i = 0; i < 5; ++i)
185 logic.importConsumers(std::to_string(i), g[i]);
186
187 pass();
188 }
189
190 void
192 {
193 testcase("Import");
194
195 TestLogic logic(j);
196
197 Gossip g;
198 Gossip::Item item;
199 item.balance = 100;
200 beast::IP::AddressV4::bytes_type d = {{192, 0, 2, 1}};
202 g.items.push_back(item);
203
204 logic.importConsumers("g", g);
205
206 pass();
207 }
208
209 void
211 {
212 testcase("Charge");
213
214 TestLogic logic(j);
215
216 {
218 Consumer c(logic.newInboundEndpoint(address));
219 Charge fee(1000);
220 JLOG(j.info()) << "Charging " << c.to_string() << " " << fee << " per second";
221 c.charge(fee);
222 for (int i = 0; i < 128; ++i)
223 {
224 JLOG(j.info()) << "Time= " << logic.clock().now().time_since_epoch().count()
225 << ", Balance = " << c.balance();
226 logic.advance();
227 }
228 }
229
230 {
232 Consumer c(logic.newInboundEndpoint(address));
233 Charge fee(1000);
234 JLOG(j.info()) << "Charging " << c.to_string() << " " << fee << " per second";
235 for (int i = 0; i < 128; ++i)
236 {
237 c.charge(fee);
238 JLOG(j.info()) << "Time= " << logic.clock().now().time_since_epoch().count()
239 << ", Balance = " << c.balance();
240 logic.advance();
241 }
242 }
243
244 pass();
245 }
246
247 void
248 run() override
249 {
250 using namespace beast::severities;
251 test::SuiteJournal journal("ResourceManager_test", *this);
252
253 testDrop(journal, true);
254 testDrop(journal, false);
255 testCharges(journal);
256 testImports(journal);
257 testImport(journal);
258 }
259};
260
261BEAST_DEFINE_TESTSUITE(ResourceManager, resource, xrpl);
262
263} // namespace Resource
264} // 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:306
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:494
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:147
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:516
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:103
Disposition disposition() const
Returns the current disposition of this consumer.
Definition Consumer.cpp:75
std::string to_string() const
Return a human readable string uniquely identifying this consumer.
Definition Consumer.cpp:57
int balance()
Returns the credit balance representing consumption.
Definition Consumer.cpp:115
Disposition charge(Charge const &fee, std::string const &context={})
Apply a load charge to the consumer.
Definition Consumer.cpp:85
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.
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)