mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-26 00:20:41 +00:00
added unit-tests
This commit is contained in:
@@ -67,6 +67,67 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
testHashIndexInvariant()
|
||||
{
|
||||
testcase("LedgerHistory hash/index invariant");
|
||||
using namespace jtx;
|
||||
using namespace std::chrono;
|
||||
|
||||
Env env{*this};
|
||||
LedgerHistory lh{beast::insight::NullCollector::New(), env.app()};
|
||||
|
||||
// Create and insert validated ledgers
|
||||
auto const genesis = makeLedger({}, env, lh, 0s);
|
||||
auto const ledger1 = makeLedger(genesis, env, lh, 4s);
|
||||
auto const ledger2 = makeLedger(ledger1, env, lh, 4s);
|
||||
auto const ledger3 = makeLedger(ledger2, env, lh, 4s);
|
||||
|
||||
// Insert as validated (so they go into by_index)
|
||||
lh.insert(genesis, true);
|
||||
lh.insert(ledger1, true);
|
||||
lh.insert(ledger2, true);
|
||||
lh.insert(ledger3, true);
|
||||
|
||||
// Verify the hash/index invariant holds
|
||||
// Can retrieve by sequence and get correct hash
|
||||
BEAST_EXPECT(lh.getLedgerHash(genesis->header().seq) == genesis->header().hash);
|
||||
BEAST_EXPECT(lh.getLedgerHash(ledger1->header().seq) == ledger1->header().hash);
|
||||
BEAST_EXPECT(lh.getLedgerHash(ledger2->header().seq) == ledger2->header().hash);
|
||||
BEAST_EXPECT(lh.getLedgerHash(ledger3->header().seq) == ledger3->header().hash);
|
||||
|
||||
// Can retrieve by sequence and get correct ledger
|
||||
auto fetched1 = lh.getLedgerBySeq(ledger1->header().seq);
|
||||
BEAST_EXPECT(fetched1 != nullptr);
|
||||
BEAST_EXPECT(fetched1->header().hash == ledger1->header().hash);
|
||||
|
||||
auto fetched2 = lh.getLedgerBySeq(ledger2->header().seq);
|
||||
BEAST_EXPECT(fetched2 != nullptr);
|
||||
BEAST_EXPECT(fetched2->header().hash == ledger2->header().hash);
|
||||
|
||||
// Clear ledgers prior to ledger2's sequence
|
||||
lh.clearLedgerCachePrior(ledger2->header().seq);
|
||||
|
||||
// Verify old entries are gone from the in-memory by_index map
|
||||
// Note: getLedgerHash checks by_index directly without DB fallback
|
||||
BEAST_EXPECT(lh.getLedgerHash(genesis->header().seq).isZero());
|
||||
BEAST_EXPECT(lh.getLedgerHash(ledger1->header().seq).isZero());
|
||||
|
||||
// Verify newer entries are still present in by_index
|
||||
BEAST_EXPECT(lh.getLedgerHash(ledger2->header().seq) == ledger2->header().hash);
|
||||
BEAST_EXPECT(lh.getLedgerHash(ledger3->header().seq) == ledger3->header().hash);
|
||||
|
||||
// Verify newer entries remain retrievable and consistent
|
||||
// getLedgerBySeq uses by_index first, then falls back to DB if needed
|
||||
auto fetched2After = lh.getLedgerBySeq(ledger2->header().seq);
|
||||
BEAST_EXPECT(fetched2After != nullptr);
|
||||
BEAST_EXPECT(fetched2After->header().hash == ledger2->header().hash);
|
||||
|
||||
auto fetched3After = lh.getLedgerBySeq(ledger3->header().seq);
|
||||
BEAST_EXPECT(fetched3After != nullptr);
|
||||
BEAST_EXPECT(fetched3After->header().hash == ledger3->header().hash);
|
||||
}
|
||||
|
||||
void
|
||||
testHandleMismatch()
|
||||
{
|
||||
@@ -163,6 +224,7 @@ public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testHashIndexInvariant();
|
||||
testHandleMismatch();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,6 +20,13 @@ original object.
|
||||
class TaggedCache_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
// Mutable value type for testing fetch_and_modify
|
||||
struct MutableValue
|
||||
{
|
||||
int counter = 0;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
@@ -129,6 +136,54 @@ public:
|
||||
BEAST_EXPECT(c.getCacheSize() == 0);
|
||||
BEAST_EXPECT(c.getTrackSize() == 0);
|
||||
}
|
||||
|
||||
// Test fetch_and_modify: insert on miss, modify on hit
|
||||
{
|
||||
using MutCache = TaggedCache<Key, MutableValue>;
|
||||
MutCache mc("mutable_test", 2, 2s, clock, journal);
|
||||
|
||||
// A. Insert on miss: fetch_and_modify creates entry and mutates it
|
||||
mc.fetch_and_modify(5, [](MutableValue& v) {
|
||||
v.counter = 42;
|
||||
v.name = "initial";
|
||||
});
|
||||
|
||||
BEAST_EXPECT(mc.getCacheSize() == 1);
|
||||
BEAST_EXPECT(mc.getTrackSize() == 1);
|
||||
|
||||
// Verify the mutation persisted
|
||||
auto p1 = mc.fetch(5);
|
||||
BEAST_EXPECT(p1 != nullptr);
|
||||
BEAST_EXPECT(p1->counter == 42);
|
||||
BEAST_EXPECT(p1->name == "initial");
|
||||
|
||||
// B. Modify existing object on hit
|
||||
// Keep strong pointer to verify in-place modification
|
||||
auto p2 = mc.fetch(5);
|
||||
BEAST_EXPECT(p2 != nullptr);
|
||||
BEAST_EXPECT(p1.get() == p2.get()); // Same object
|
||||
|
||||
// Modify through fetch_and_modify
|
||||
mc.fetch_and_modify(5, [](MutableValue& v) {
|
||||
v.counter += 10;
|
||||
v.name = "modified";
|
||||
});
|
||||
|
||||
// Verify no new entry was created
|
||||
BEAST_EXPECT(mc.getCacheSize() == 1);
|
||||
BEAST_EXPECT(mc.getTrackSize() == 1);
|
||||
|
||||
// Verify the same object was mutated (strong pointer sees change)
|
||||
BEAST_EXPECT(p1->counter == 52);
|
||||
BEAST_EXPECT(p1->name == "modified");
|
||||
BEAST_EXPECT(p2->counter == 52); // Original pointer sees mutation
|
||||
|
||||
// Verify via fresh fetch
|
||||
auto p3 = mc.fetch(5);
|
||||
BEAST_EXPECT(p3 != nullptr);
|
||||
BEAST_EXPECT(p3.get() == p1.get()); // Same object identity
|
||||
BEAST_EXPECT(p3->counter == 52);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
Reference in New Issue
Block a user