#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace xrpl::Resource { class ResourceManagerTest : public ::testing::Test { protected: beast::Journal const j_{TestSink::instance()}; class TestLogic : private boost::base_from_member, public Logic { private: using clock_type = boost::base_from_member; public: explicit TestLogic(beast::Journal journal) : Logic(beast::insight::NullCollector::make(), member, journal) { } void advance() { ++member; } TestStopwatch& clock() { return member; } }; //-------------------------------------------------------------------------- static void populateGossip(Gossip& gossip) { std::uint8_t const v(10 + randInt(9)); std::uint8_t const n(10 + randInt(9)); gossip.items.reserve(n); for (std::uint8_t i = 0; i < n; ++i) { Gossip::Item item; item.balance = 100 + randInt(499); beast::IP::AddressV4::bytes_type const d = {{ 192, 0, 2, static_cast(v + i), }}; item.address = beast::IP::Endpoint{beast::IP::AddressV4{d}}; gossip.items.push_back(item); } } }; TEST_F(ResourceManagerTest, limited_warn_drop) { TestLogic logic{j_}; Charge const fee{kDropThreshold + 1}; beast::IP::Endpoint const addr{beast::IP::Endpoint::fromString("192.0.2.2")}; { Consumer c{logic.newInboundEndpoint(addr)}; // Create load until we get a warning int n = 10000; bool warned = false; while (--n >= 0) { if (c.charge(fee) == Disposition::Warn) { warned = true; break; } ++logic.clock(); } ASSERT_TRUE(warned) << "Loop count exceeded without warning"; // Create load until we get dropped bool dropped = false; while (--n >= 0) { if (c.charge(fee) == Disposition::Drop) { dropped = true; // Disconnect abusive Consumer EXPECT_TRUE(c.disconnect(j_)); break; } ++logic.clock(); } ASSERT_TRUE(dropped) << "Loop count exceeded without dropping"; } // Make sure the consumer is on the blacklist for a while. { Consumer const c{logic.newInboundEndpoint(addr)}; logic.periodicActivity(); EXPECT_EQ(c.disposition(), Disposition::Drop) << "Dropped consumer not put on blacklist"; } // Makes sure the Consumer is eventually removed from blacklist bool readmitted = false; { using namespace std::chrono_literals; // Give Consumer time to become readmitted. Should never // exceed expiration time. auto n = kSecondsUntilExpiration + 1s; while (--n > 0s) { ++logic.clock(); logic.periodicActivity(); Consumer const c{logic.newInboundEndpoint(addr)}; if (c.disposition() != Disposition::Drop) { readmitted = true; break; } } } EXPECT_TRUE(readmitted) << "Dropped Consumer left on blacklist too long"; } TEST_F(ResourceManagerTest, unlimited_warn_drop) { TestLogic logic{j_}; Charge const fee{kDropThreshold + 1}; beast::IP::Endpoint const addr{beast::IP::Endpoint::fromString("192.0.2.2")}; Consumer c{logic.newUnlimitedEndpoint(addr)}; // Create load until we get a warning int n = 10000; bool warned = false; while (--n >= 0) { if (c.charge(fee) == Disposition::Warn) { warned = true; break; } ++logic.clock(); } EXPECT_FALSE(warned) << "Should loop forever with no warning"; } TEST_F(ResourceManagerTest, charges) { TestLogic logic{j_}; { beast::IP::Endpoint const address{beast::IP::Endpoint::fromString("192.0.2.1")}; Consumer c{logic.newInboundEndpoint(address)}; Charge const fee{1000}; JLOG(j_.info()) << "Charging " << c.toString() << " " << fee << " per second"; c.charge(fee); for (int i = 0; i < 128; ++i) { JLOG(j_.info()) << "Time= " << logic.clock().now().time_since_epoch().count() << ", Balance = " << c.balance(); logic.advance(); } } { beast::IP::Endpoint const address{beast::IP::Endpoint::fromString("192.0.2.2")}; Consumer c{logic.newInboundEndpoint(address)}; Charge const fee{1000}; JLOG(j_.info()) << "Charging " << c.toString() << " " << fee << " per second"; for (int i = 0; i < 128; ++i) { c.charge(fee); JLOG(j_.info()) << "Time= " << logic.clock().now().time_since_epoch().count() << ", Balance = " << c.balance(); logic.advance(); } } } TEST_F(ResourceManagerTest, imports) { TestLogic logic{j_}; Gossip g[5]; for (auto& i : g) populateGossip(i); for (int i = 0; i < 5; ++i) logic.importConsumers(std::to_string(i), g[i]); } TEST_F(ResourceManagerTest, import) { TestLogic logic{j_}; Gossip g; Gossip::Item item; item.balance = 100; beast::IP::AddressV4::bytes_type const d = {{ 192, 0, 2, 1, }}; item.address = beast::IP::Endpoint{beast::IP::AddressV4{d}}; g.items.push_back(item); logic.importConsumers("g", g); } } // namespace xrpl::Resource