From 6eac084f4df6ca7fed3a8d05035834d4b6f5b1ef Mon Sep 17 00:00:00 2001 From: alienx5499 Date: Sun, 8 Mar 2026 11:31:35 +0530 Subject: [PATCH] Replace rand() with fixed-seed RNG to make tests deterministic --- test/libp2p/crypto/marshaller_test.cpp | 5 +-- .../kademlia/peer_routing_table_test.cpp | 18 +++------ .../transport/tcp/tcp_integration_test.cpp | 11 ++--- test/testutil/libp2p/peer.cpp | 6 +-- test/testutil/libp2p/random.hpp | 40 +++++++++++++++++++ 5 files changed, 53 insertions(+), 27 deletions(-) create mode 100644 test/testutil/libp2p/random.hpp diff --git a/test/libp2p/crypto/marshaller_test.cpp b/test/libp2p/crypto/marshaller_test.cpp index b2f3f2ac1..5b916bd9d 100644 --- a/test/libp2p/crypto/marshaller_test.cpp +++ b/test/libp2p/crypto/marshaller_test.cpp @@ -11,6 +11,7 @@ #include #include #include "mock/libp2p/crypto/key_validator_mock.hpp" +#include "testutil/libp2p/random.hpp" using Buffer = std::vector; using libp2p::crypto::Key; @@ -34,9 +35,7 @@ struct KeyCase { }; Buffer randomBuffer(size_t size) { - Buffer buf(size, 0); - std::generate_n(buf.begin(), size, []() { return rand() & 0xff; }); - return buf; + return testutil::randomBytes(size); } class Pubkey : public testing::TestWithParam> { diff --git a/test/libp2p/protocol/kademlia/peer_routing_table_test.cpp b/test/libp2p/protocol/kademlia/peer_routing_table_test.cpp index b0f0675e6..4daf78c60 100644 --- a/test/libp2p/protocol/kademlia/peer_routing_table_test.cpp +++ b/test/libp2p/protocol/kademlia/peer_routing_table_test.cpp @@ -6,11 +6,13 @@ #include #include #include +#include #include #include #include "mock/libp2p/peer/identity_manager_mock.hpp" #include "testutil/libp2p/peer.hpp" +#include "testutil/libp2p/random.hpp" #include "testutil/prepare_loggers.hpp" using namespace libp2p; @@ -50,8 +52,6 @@ bool hasPeer(A &peerset, PeerId &peer) { } TEST_F(PeerRoutingTableTest, BusWorks) { - srand(0); // to make test deterministic - auto &addCh = bus_->getChannel(); auto &remCh = bus_->getChannel(); @@ -85,8 +85,6 @@ TEST_F(PeerRoutingTableTest, BusWorks) { * https://sourcegraph.com/github.com/libp2p/go-libp2p-kbucket@HEAD/-/blob/table_test.go#L168 */ TEST_F(PeerRoutingTableTest, FindMultiple) { - srand(0); // to make test deterministic - std::vector peers; std::generate_n(std::back_inserter(peers), 18, testutil::randomPeerId); @@ -106,7 +104,6 @@ TEST_F(PeerRoutingTableTest, FindMultiple) { */ TEST_F(PeerRoutingTableTest, RecyclingTest) { config_->maxBucketSize = 1; - srand(0); // to make test deterministic auto &addCh = bus_->getChannel(); auto &remCh = bus_->getChannel(); @@ -125,7 +122,7 @@ TEST_F(PeerRoutingTableTest, RecyclingTest) { std::vector peers; // Generate peers for first bucket, in count more than bucket capacity - for (int i = 0; i < 3; ++i) { + while (peers.size() != 3) { auto peer_id = testutil::randomPeerId(); NodeId node_id(peer_id); if (node_id.commonPrefixLen(NodeId(self_id)) == 0) { @@ -163,7 +160,6 @@ TEST_F(PeerRoutingTableTest, RecyclingTest) { TEST_F(PeerRoutingTableTest, PreferLongLivedPeers) { config_->maxBucketSize = 2; - srand(0); // to make test deterministic auto &addCh = bus_->getChannel(); auto &remCh = bus_->getChannel(); @@ -210,7 +206,6 @@ TEST_F(PeerRoutingTableTest, PreferLongLivedPeers) { TEST_F(PeerRoutingTableTest, EldestRecycledIfNotPermanent) { config_->maxBucketSize = 3; - srand(0); // to make test deterministic std::vector peers; @@ -239,7 +234,6 @@ TEST_F(PeerRoutingTableTest, EldestRecycledIfNotPermanent) { TEST_F(PeerRoutingTableTest, EldestPrefferedIfPermanent) { config_->maxBucketSize = 3; - srand(0); // to make test deterministic std::vector peers; @@ -272,14 +266,15 @@ TEST_F(PeerRoutingTableTest, EldestPrefferedIfPermanent) { */ TEST_F(PeerRoutingTableTest, Update) { config_->maxBucketSize = 10; - srand(0); // to make test deterministic std::vector peers; std::generate_n(std::back_inserter(peers), 100, testutil::randomPeerId); + std::uniform_int_distribution dist(0, peers.size() - 1); + auto& rng = testutil::getTestRng(); // 10000 random updates among 100 existing peers for (int i = 0; i < 10000; i++) { - int index = rand() % peers.size(); + size_t index = dist(rng); [[maybe_unused]] auto result = table_->update(peers[index], false); } @@ -300,7 +295,6 @@ TEST_F(PeerRoutingTableTest, Update) { */ TEST_F(PeerRoutingTableTest, Find) { config_->maxBucketSize = 10; - srand(0); // to make test deterministic const auto nPeers = 5; diff --git a/test/libp2p/transport/tcp/tcp_integration_test.cpp b/test/libp2p/transport/tcp/tcp_integration_test.cpp index 87758ae93..bcab12584 100644 --- a/test/libp2p/transport/tcp/tcp_integration_test.cpp +++ b/test/libp2p/transport/tcp/tcp_integration_test.cpp @@ -18,6 +18,7 @@ #include "mock/libp2p/transport/upgrader_mock.hpp" #include "testutil/gmock_actions.hpp" #include "testutil/libp2p/peer.hpp" +#include "testutil/libp2p/random.hpp" #include "testutil/prepare_loggers.hpp" using namespace libp2p::transport; @@ -175,10 +176,7 @@ TEST(TCP, SingleListenerCanAcceptManyClients) { auto conn = expectConnectionValid(rconn); auto readback = std::make_shared(kSize, 0); - auto buf = std::make_shared(kSize, 0); - std::generate(buf->begin(), buf->end(), []() { - return rand(); // NOLINT - }); + auto buf = std::make_shared(testutil::randomBytes(kSize)); EXPECT_TRUE(conn->isInitiator()); @@ -335,10 +333,7 @@ TEST(TCP, OneTransportServerHandlesManyClients) { auto conn = expectConnectionValid(rconn); auto readback = std::make_shared(kSize, 0); - auto buf = std::make_shared(kSize, 0); - std::generate(buf->begin(), buf->end(), []() { - return rand(); // NOLINT - }); + auto buf = std::make_shared(testutil::randomBytes(kSize)); EXPECT_TRUE(conn->isInitiator()); diff --git a/test/testutil/libp2p/peer.cpp b/test/testutil/libp2p/peer.cpp index 56c0db0c8..9d3f1a9ac 100644 --- a/test/testutil/libp2p/peer.cpp +++ b/test/testutil/libp2p/peer.cpp @@ -5,14 +5,12 @@ */ #include +#include namespace testutil { PeerId randomPeerId() { - std::vector rand_key(32, 0); - for (auto i = 0u; i < 32u; i++) { - rand_key[i] = (rand() & 0xffu); // NOLINT - } + auto rand_key = randomBytes(32); return PeerId::fromPublicKey(libp2p::crypto::ProtobufKey{rand_key}).value(); } diff --git a/test/testutil/libp2p/random.hpp b/test/testutil/libp2p/random.hpp new file mode 100644 index 000000000..245ef152b --- /dev/null +++ b/test/testutil/libp2p/random.hpp @@ -0,0 +1,40 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include + +namespace testutil { + + /** + * Returns a deterministic RNG for tests. Same seed every run for reproducible + * tests; avoids flaky behavior from unseeded rand(). + * NOTE: Shared RNG; test execution order affects the sequence (determinism + * is per run, not per test). + */ + inline std::mt19937& getTestRng() { + static std::mt19937 rng(0x42); // arbitrary fixed seed for reproducibility + return rng; + } + + /** + * Fills a buffer with deterministic random bytes. Use in tests instead of + * rand() for reproducibility. + */ + inline std::vector randomBytes(size_t n) { + std::vector buf(n); + auto& rng = getTestRng(); + std::uniform_int_distribution dist(0, 255); + for (size_t i = 0; i < n; ++i) { + buf[i] = static_cast(dist(rng)); + } + return buf; + } + +} // namespace testutil