added unit-tests

This commit is contained in:
Valentin Balaschenko
2026-03-20 15:05:36 +00:00
parent 65fc6d905c
commit 04d53f57b3
3 changed files with 117 additions and 8 deletions

View File

@@ -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();
}
};

View File

@@ -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);
}
}
};

View File

@@ -1,8 +0,0 @@
#include <gtest/gtest.h>
int
main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}