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