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 
32 namespace ripple {
33 namespace Resource {
34 
35 class ResourceManager_test : public beast::unit_test::suite
36 {
37 public:
38  class TestLogic
39  : private boost::base_from_member<TestStopwatch>
40  , public Logic
41 
42  {
43  private:
44  using clock_type =
45  boost::base_from_member<TestStopwatch>;
46 
47  public:
48  explicit TestLogic (beast::Journal journal)
49  : Logic (beast::insight::NullCollector::New(), member, journal)
50  {
51  }
52 
53  void advance ()
54  {
55  ++member;
56  }
57 
59  {
60  return member;
61  }
62  };
63 
64  //--------------------------------------------------------------------------
65 
66  void createGossip (Gossip& gossip)
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 testDrop (beast::Journal j, bool limited)
85  {
86  if (limited)
87  testcase("Limited warn/drop");
88  else
89  testcase("Unlimited warn/drop");
90 
91  TestLogic logic (j);
92 
93  Charge const fee (dropThreshold + 1);
94  beast::IP::Endpoint const addr (
95  beast::IP::Endpoint::from_string ("192.0.2.2"));
96 
98  std::bind(
99  &TestLogic::newInboundEndpoint, &logic, std::placeholders::_1) :
100  std::bind(
101  &TestLogic::newUnlimitedEndpoint, &logic, std::placeholders::_1);
102 
103  {
104  Consumer c (ep(addr));
105 
106  // Create load until we get a warning
107  int n = 10000;
108 
109  while (--n >= 0)
110  {
111  if (n == 0)
112  {
113  if (limited)
114  fail ("Loop count exceeded without warning");
115  else
116  pass();
117  return;
118  }
119 
120  if (c.charge (fee) == warn)
121  {
122  if (limited)
123  pass();
124  else
125  fail ("Should loop forever with no warning");
126  break;
127  }
128  ++logic.clock ();
129  }
130 
131  // Create load until we get dropped
132  while (--n >= 0)
133  {
134  if (n == 0)
135  {
136  if (limited)
137  fail ("Loop count exceeded without dropping");
138  else
139  pass();
140  return;
141  }
142 
143  if (c.charge (fee) == drop)
144  {
145  // Disconnect abusive Consumer
146  BEAST_EXPECT(c.disconnect () == limited);
147  break;
148  }
149  ++logic.clock ();
150  }
151  }
152 
153  // Make sure the consumer is on the blacklist for a while.
154  {
155  Consumer c (logic.newInboundEndpoint (addr));
156  logic.periodicActivity();
157  if (c.disposition () != drop)
158  {
159  if (limited)
160  fail ("Dropped consumer not put on blacklist");
161  else
162  pass();
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 c (logic.newInboundEndpoint (addr));
179  if (c.disposition () != drop)
180  {
181  readmitted = true;
182  break;
183  }
184  }
185  }
186  if (readmitted == false)
187  {
188  fail ("Dropped Consumer left on blacklist too long");
189  return;
190  }
191  pass();
192  }
193 
195  {
196  testcase ("Imports");
197 
198  TestLogic logic (j);
199 
200  Gossip g[5];
201 
202  for (int i = 0; i < 5; ++i)
203  createGossip (g[i]);
204 
205  for (int i = 0; i < 5; ++i)
206  logic.importConsumers (std::to_string (i), g[i]);
207 
208  pass();
209  }
210 
212  {
213  testcase ("Import");
214 
215  TestLogic logic (j);
216 
217  Gossip g;
218  Gossip::Item item;
219  item.balance = 100;
220  beast::IP::AddressV4::bytes_type d = {{192, 0, 2, 1}};
222  g.items.push_back (item);
223 
224  logic.importConsumers ("g", g);
225 
226  pass();
227  }
228 
230  {
231  testcase ("Charge");
232 
233  TestLogic logic (j);
234 
235  {
237  Consumer c (logic.newInboundEndpoint (address));
238  Charge fee (1000);
239  JLOG(j.info()) <<
240  "Charging " << c.to_string() << " " << fee << " per second";
241  c.charge (fee);
242  for (int i = 0; i < 128; ++i)
243  {
244  JLOG(j.info()) <<
245  "Time= " << logic.clock().now().time_since_epoch().count() <<
246  ", Balance = " << c.balance();
247  logic.advance();
248  }
249  }
250 
251  {
253  Consumer c (logic.newInboundEndpoint (address));
254  Charge fee (1000);
255  JLOG(j.info()) <<
256  "Charging " << c.to_string() << " " << fee << " per second";
257  for (int i = 0; i < 128; ++i)
258  {
259  c.charge (fee);
260  JLOG(j.info()) <<
261  "Time= " << logic.clock().now().time_since_epoch().count() <<
262  ", Balance = " << c.balance();
263  logic.advance();
264  }
265  }
266 
267  pass();
268  }
269 
270  void 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 
283 BEAST_DEFINE_TESTSUITE(ResourceManager,resource,ripple);
284 
285 }
286 }
std::bind
T bind(T... args)
ripple::Resource::ResourceManager_test::TestLogic::TestLogic
TestLogic(beast::Journal journal)
Definition: Logic_test.cpp:48
ripple::Resource::ResourceManager_test::TestLogic
Definition: Logic_test.cpp:38
ripple::Resource::ResourceManager_test::testCharges
void testCharges(beast::Journal j)
Definition: Logic_test.cpp:229
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:270
ripple::Resource::Logic::newInboundEndpoint
Consumer newInboundEndpoint(beast::IP::Endpoint const &address)
Definition: resource/impl/Logic.h:110
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:121
ripple::Resource::ResourceManager_test::testImport
void testImport(beast::Journal j)
Definition: Logic_test.cpp:211
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:46
std::function
ripple::Resource::ResourceManager_test::TestLogic::clock
TestStopwatch & clock()
Definition: Logic_test.cpp:58
ripple::Resource::ResourceManager_test
Definition: Logic_test.cpp:35
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:73
ripple::Resource::ResourceManager_test::testDrop
void testDrop(beast::Journal j, bool limited)
Definition: Logic_test.cpp:84
ripple::Resource::dropThreshold
@ dropThreshold
Definition: resource/impl/Tuning.h:35
ripple::Resource::drop
@ drop
Definition: Disposition.h:36
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:297
ripple::Resource::Consumer::balance
int balance()
Returns the credit balance representing consumption.
Definition: Consumer.cpp:120
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:60
std::uint8_t
beast::abstract_clock< std::chrono::steady_clock >
ripple::test::SuiteJournal
Definition: SuiteJournal.h:81
beast::manual_clock::now
time_point now() const override
Returns the current time.
Definition: manual_clock.h:57
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:194
ripple::Resource::Consumer::disconnect
bool disconnect()
Returns true if the consumer should be disconnected.
Definition: Consumer.cpp:114
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:175
beast::IP::Endpoint::from_string
static Endpoint from_string(std::string const &s)
Definition: IPEndpoint.cpp:47
ripple::Resource::Gossip::Item::address
beast::IP::Endpoint address
Definition: Gossip.h:39
ripple::Resource::Consumer
An endpoint that consumes resources.
Definition: Consumer.h:33
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:53
beast::IP::Endpoint
A version-independent IP address and port combination.
Definition: IPEndpoint.h:39
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:98
ripple::Resource::Logic::periodicActivity
void periodicActivity()
Definition: resource/impl/Logic.h:340
beast
Definition: base_uint.h:582